Reputation: 1286
I'm working my way through Pickaxe 1.9, and I'm a bit confused by constant-lookup in instance/class_eval blocks. I'm using 1.9.2.
It seems that Ruby handles constant-lookup in *_eval blocks the same way it does method-lookup:
#<Class:BasicObject>
; Object
, which stores all the constants you define at the top-level), checking for mixins along the wayIs this correct? The Pickaxe discussion is a bit terse.
Some examples:
class Foo
CONST = 'Foo::CONST'
class << self
CONST = 'EigenFoo::CONST'
end
end
Foo.instance_eval { CONST } # => 'EigenFoo::CONST'
Foo.class_eval { CONST } # => 'EigenFoo::CONST', not 'Foo::CONST'!
Foo.new.instance_eval { CONST } # => 'Foo::CONST'
In the class_eval example, Foo-the-class isn't a stop along Foo-the-object's ancestor chain!
And an example with mixins:
module M
CONST = "M::CONST"
end
module N
CONST = "N::CONST"
end
class A
include M
extend N
end
A.instance_eval { CONST } # => "N::CONST", because N is mixed into A's eigenclass
A.class_eval { CONST } # => "N::CONST", ditto
A.new.instance_eval { CONST } # => "M::CONST", because A.new.class, A, mixes in M
Upvotes: 3
Views: 1153
Reputation: 1580
Constants are effectively lexically scoped so you cannot access them short hand outside of the module hierarchy within which they are defined. There is a good explanation here and slightly off topic but a good read here.
Upvotes: 0
Reputation: 2530
In 1.9.2 the constant lookup has changed again to be equivalent to the 1.8.7 behavior.
class A
class B
class C
end
end
end
A.class_eval { B } # => NameError
A.instance_eval { B } # => NameError
A.new.instance_eval { B } # => A::B
Basically, the constants are quasi-lexically scoped. This USED to be different between 1.9.x and 1.8.x branches, and it made library cross compatibility a pain, so they changed it back.
Yehuda Katz's (successful) appeal to restore 1.8 behavior
Upvotes: 1