Using #include at the instance level?

I would like to use #include at an instance level, such that it
behaves just as it does at a class level. After a number of
experiments I thought for sure it would work if I ran the include
through the object’s singleton. Alas, submodules remain inaccessible,
eg.

module M
def m1; “m1”; end
module N
def self.n1; “n1”; end
end
end

class X
def initialize(*mods)
(class << self; self; end).class_eval do
include *mods
end
end
def m ; m1 ; end
def n ; N.n1 ; end
end

x = X.new(M)
p x.m
p x.n #=> uninitialized constant X::N (NameError)

Is there any way to achieve this?

On Dec 28, 2009, at 10:29 PM, Intransition wrote:

end
end

x = X.new(M)
p x.m
p x.n #=> uninitialized constant X::N (NameError)

Is there any way to achieve this?

You may write:

class X
def eigenclass
class << self; self; end;
end

def initialize(*mods)
eigenclass.instance_eval do
include *mods
end
end
def m ; m1 ; end
def n; eigenclass::N.n1 ; end
end

I guess constants not like methods are not searched within eigenclass,
and that’s the reason why you are getting an error.

2009/12/29 Intransition [email protected]:

end
end

class X
def initialize(*mods)
(class << self; self; end).class_eval do
include *mods
end
end
def m ; m1 ; end
def n ; N.n1 ; end

Hm, this method above won’t work as scope resolution rules for
constants are different.

end

x = X.new(M)
p x.m
p x.n #=> uninitialized constant X::N (NameError)

Is there any way to achieve this?

Did you consider using #extend?

class X
def initialize(*mods)
extend *mods
end
end

What do you really want to achieve? Do you have a more telling example?

Kind regards

robert

On Dec 29, 1:35 am, fkocherga [email protected] wrote:

I guess constants not like methods are not searched within eigenclass, and that’s the reason why you are getting an error.

You are right. That appears to be the case. I tried setting a constant
directly in the eigenclass and the instance could not see it either.
The behavior surprises me.

On Dec 29, 3:29 am, Robert K. [email protected] wrote:

module M
end
p x.m
end

What do you really want to achieve? Do you have a more telling example?

It’s for encapsulating test cases. Eg.

TestCase.new(SomeClass) do

end

Within the test case block it would help to handle #include, to make
tests less verbose.

Instead of making an instance of TestCase for each case, at this point
it looks like I’ll have to create a new subclass of it.

2009/12/29 Intransition [email protected]:

through the object’s singleton. Alas, submodules remain inaccessible,
def initialize(*mods)
end
def initialize(*mods)
end

Within the test case block it would help to handle #include, to make
tests less verbose.

I see to be a bit slow today: how do you want to use modules there?
Do you want to include them in the test code? What about:

class TestCase
def new(cl, &bl)
@cl = cl
instance_eval(&bl)
end

alias include extend
end

TestCase.new String do
extend Foo
include Bar
end

Instead of making an instance of TestCase for each case, at this point
it looks like I’ll have to create a new subclass of it.

Sorry, you lost me here.

Cheers

robert

On Dec 29, 9:37 am, Robert K. [email protected] wrote:

2009/12/29 Intransition [email protected]:

end

TestCase.new String do
extend Foo
include Bar
end

No no. You got it exactly. Problem is the module’s constants are not
coming through the #extend (which is effectively the same as the
include in the singleton class). Let say I have a library:

module MyApp
module SomeSpace
class FooClass

end
end
end

In the test cases, instead of having to spell out
MyApp::SomeSpace::FooClass everywhere it is needed, it would be nice
to include MyApp::SomeSpace, and then just reference FooClass in the
tests.

Instead of making an instance of TestCase for each case, at this point
it looks like I’ll have to create a new subclass of it.

Sorry, you lost me here.

Instead of the code you presented I’d have to do something like:

class TestCase
alias :_new, :new
def self.new(&block)
Class.new(self, &block)._new
end
end

Haven’t tested it yet, but that should allow #include to work no
problem. Unfortunately it means defining all my dsl methods at the
class level --not even sure the instance level would be of any use in
this case either, in which case the ._new can be dropped – kind of
stupid, just to get #include to work. But what else can I do?

I almost feel like I’m having a mental block and there is actually an
easy way to do this.

2009/12/29 Intransition [email protected]:

On Dec 29, 9:37 am, Robert K. [email protected] wrote:

2009/12/29 Intransition [email protected]:

I see to be a bit slow today: how do you want to use modules there?
Do you want to include them in the test code? What about:

class TestCase
def new(cl, &bl)

Btw, that method’s name should have read “initialize”.

end
end

Sorry, you lost me here.

Instead of the code you presented I’d have to do something like:

class TestCase
alias :_new, :new
def self.new(&block)
Class.new(self, &block)._new
end
end

Then your block needs to contain a class definition. You can use the
block only for one thing - either class / module def or code you
want to execute. Granted, you can have code executed in a class
definition as well but the definition becomes only usable after the
definition has been executed in its entirety. Maybe you haven’t
decided yet what you want the block for and that is causing your
headaches.

Haven’t tested it yet, but that should allow #include to work no
problem. Unfortunately it means defining all my dsl methods at the
class level --not even sure the instance level would be of any use in
this case either, in which case the ._new can be dropped – kind of
stupid, just to get #include to work. But what else can I do?

I almost feel like I’m having a mental block and there is actually an
easy way to do this.

What stops you from doing the include outside?

include Your::Module::Of::Choice

TestCase.new Foo do
x = ChoiceClass.new
x.method_invocation(123)
end

Kind regards

robert

On Dec 29, 11:55 am, Robert K. [email protected] wrote:

Then your block needs to contain a class definition. You can use the
block only for one thing - either class / module def or code you
want to execute. Granted, you can have code executed in a class
definition as well but the definition becomes only usable after the
definition has been executed in its entirety.

That’s true. But the execution of the block is only for the definition
of things which get run later.

Maybe you haven’t
decided yet what you want the block for and that is causing your
headaches.

The block is for defining unit tests. Eg.

testcase SomeClass do
testunit :somemethod => “some concern” do

end
end

include Your::Module::Of::Choice

TestCase.new Foo do
x = ChoiceClass.new
x.method_invocation(123)
end

Yes, I am able to do that. But I want to avoid polluting the top
level.

You know what really gets me is that even though I get an
“uninitialized constant” error, there is no place I seem to be able to
define a #const_missing method to catch it.

This is really becoming annoying. I can’t even do it via a dynamic
class definitions either.

module M
def m1; “m1”; end
module N
def self.n1; “n1”; end
end
end

class X
class << self
alias _new new
def new(&block)
klass = Class.new(self)
klass.class_eval(&block)
klass._new
end
end

def m ; m1 ; end
def n ; N.n1 ; end

end

x = X.new do
include M
end

p x.m
p x.n #=> uninitialized constant X::N (NameError)

Did constant lookup change between 1.8.6 and 1.8.7? Seems to me this
used to be possible, and I find it unacceptable that normal constant
lookup would not apply to dynamic class definitions, let alone the
singleton classes.

2009/12/29 Intransition [email protected]:

class X
def n ; N.n1 ; end
used to be possible, and I find it unacceptable that normal constant
lookup would not apply to dynamic class definitions, let alone the
singleton classes.

AFAIK it hasn’t changed and your code could never work in any version
of Ruby because the const lookup in method #n is done statically.
Apart from that you are defining method X#n and not #n
so the lookup could never work if you would instantiate X.

Also, on a more abstract level: it is at least a bit odd to define
class X which can only ever work if you make sure you include “N”
(whichever way).

I believe you haven’t yet fully analyzed the problem you want to
solve. I suggest to put it to sleep for a while and then get back
later to it. I can’t help you any more because to me it is not clear
what you are trying to achieve. So far we only went through technical
issues but the problem you are trying to solve isn’t cleat to me yet.

Kind regards

robert

On 29.12.2009 17:37, Intransition wrote:

I almost feel like I’m having a mental block and there is actually an
easy way to do this.

Maybe this gets you on track:

“One of those pleasing little Ruby snippets: module Helpers; include
*constants.map(&:const_get); end”
http://twitter.com/pragdave/status/7147303788

AFAIK it hasn’t changed and your code could never work in any version
of Ruby because the const lookup in method #n is done statically.

But it should not, consider:

module M
module N
end
end

#Class.new do <---- This does not work in 1.8.7!
class B < Object
include M
N
end

When ‘class B < Object’ replaced with ‘Class.new do’ the Ruby 1.8.7
interpreter complains about uninitialized constant N. What is the big
reason for dynamically defined class to behave so differently? It would
be very non obvious and unexpected behavior. Actually both cases work as
expected in Ruby 1.9.1 and this is correct behavior according to the
Ruby Draft.

On Dec 29, 3:16 pm, Robert K. [email protected] wrote:

 def self.n1; "n1"; end
 end

p x.m
so the lookup could never work if you would instantiate X.

Also, on a more abstract level: it is at least a bit odd to define
class X which can only ever work if you make sure you include “N”
(whichever way).

I believe you haven’t yet fully analyzed the problem you want to
solve. I suggest to put it to sleep for a while and then get back
later to it. I can’t help you any more because to me it is not clear
what you are trying to achieve. So far we only went through technical
issues but the problem you are trying to solve isn’t cleat to me yet.

All I am trying to do is emulate test/unit but using a DSL.
Essentially:

class MyTest < Test::Unit::TestCase

include M

def test_N_n1
   assert_equal(N.n1, "n1")
 end

end

Becomes:

testcase :MyTest do

include M

testunit :N_n1 do
   assert_equal(N.n1, "n1")
 end

end

That’s it. But I can’t do it exactly b/c I can’t make the include
work.

end

end

Not sure why you need a DSL for, but technically it is doable (in Ruby
1.9.1):
http://gist.github.com/265864

2009/12/30 fkocherga [email protected]:

#Class.new do <---- This does not work in 1.8.7!
class B < Object
 include M
 N
end

When ‘class B < Object’ replaced with ‘Class.new do’ the Ruby 1.8.7 interpreter complains about uninitialized constant N. What is the big reason for dynamically defined class to behave so differently? It would be very non obvious and unexpected behavior. Actually both cases work as expected in Ruby 1.9.1 and this is correct behavior according to the Ruby Draft.

Thanks for the test case! It never occurred to me to do a const
lookup in a class defined with a class body so I never stumbled across
this. I did a bit of research and this is what I found:

Statement from Matz about the change: “In 1.8, constant uses lexical
look-up, even within the block given to instance_eval(). We changed
this behavior in 1.9 to simplify things.”
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/181646

Found via
http://eigenclass.org/hiki/withdrawn-experimental-ruby-features

  • I am not so sure about the “experimental” status of this though -
    maybe this is due to the last update date of the page in 2007…

Adam G. also made an interesting observation about the difference
between const_get and direct constant lookup:
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/333677
(I have changed the test output to easier interpret it. See attachment.)

There’s also this discussion
http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-core/25865?25832-26487

And this
http://blade.nagaokaut.ac.jp/cgi-bin/vframe.rb/ruby/ruby-talk/334016?333995-335445

To sum it up: Ruby 1.9 changed lookup rules from lexical (aka static)
to dynamic. IMHO this explains the observed different behavior.
Thanks again for poking.

Kind regards

robert

2009/12/29 Intransition [email protected]:

On Dec 29, 3:16 pm, Robert K. [email protected] wrote:

testcase :MyTest do
work.
Ah, now I see. I believe your problem comes from the fact that you
are mixing two styles: DSL and “regular” Ruby. If you integrate
defining those modules into your DSL (i.e. not via “module … end”)
then integrating lookups might be easier as well. I don’t have a
clear idea yet how to do that but maybe it’s worth exploring.

Kind regards

robert

On Wed, Dec 30, 2009 at 4:34 AM, Robert K.
[email protected] wrote:

To sum it up: Ruby 1.9 changed lookup rules from lexical (aka static)
to dynamic.

That change may not be permanent.

There was a long thread on ruby-core a month or two ago, prompted by a
question raised by Yehuda K. about the problems the change was
causing for existing DSLs like ActiveRecord and RSpec. After various
proposals to modify the 1.9 behavior to make it more compatible,
Maeda-san posted this:

Matz seems to be in favor of returning to the 1.8 behavior.


Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/person/9021-rick-denatale
LinkedIn: Rick DeNatale - Developer - IBM | LinkedIn

On Dec 29, 9:04 pm, fkocherga [email protected] wrote:

#Class.new do <---- This does not work in 1.8.7!
class B < Object
include M
N
end

When ‘class B < Object’ replaced with ‘Class.new do’ the Ruby 1.8.7 interpreter complains about uninitialized constant N. What is the big reason for dynamically defined class to behave so differently? It would be very non obvious and unexpected behavior. Actually both cases work as expected in Ruby 1.9.1 and this is correct behavior according to the Ruby Draft.

Nice clarification.

Are there two issues here? This issue and the resolution of constants
via instance_eval? Or are these two aspects of the same issue?

In either case, there is no doubt in my mind that ‘class B’ and ‘B =
Class.new do’ should work the same.

On Dec 30, 10:29 am, Rick DeNatale [email protected] wrote:

causing for existing DSLs like ActiveRecord and RSpec. After various
proposals to modify the 1.9 behavior to make it more compatible,
Maeda-san posted this:

http://osdir.com/ml/ruby-core/2009-12/msg00001.html

Matz seems to be in favor of returning to the 1.8 behavior.

What a tangle.

Seems to me there are two desired behaviors: 1) domain behavior, where
by lookup follows from the point of evaluation, and 2) closure
behavior, whereby lookup follows from the point of definition. Both
are perfectly reasonably and depend solely on the need of the
developer’s usecase. There is also the compromise position, first try
domain behavior, failing that try closure behavior.

So if I understand correctly, 1.8 and older used closure behavior, 1.9
switched to domain behavior. There were issues with this change. Some
people suggested the compromise position, but Matz rejected that and
has decided to return to the original closure behavior. Is that a
correct summary?

Short of the compromise position, I would think the only complete
solution would be to allow for both approaches via different methods,
eg. instance_eval vs. instance_domain_eval, or perhaps an option,
instance_eval(&b, :closure=>false).