开发者

Ruby: how does constant-lookup work in instance_eval/class_eval?

开发者 https://www.devze.com 2023-01-03 13:22 出处:网络
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.

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:

  1. look for a definition in receiver.singleton_class (plus mixins);
  2. then in receiver.singleton_class.superclass (plus mixins);
  3. then continue up the eigenchain until you get to #<Class:BasicObject>;
  4. whose superclass is Class;
  5. and then up the rest of the ancestor chain (including Object, which stores all the constants you define at the top-level), checking for mixins along the way

Is this correct? The Pickaxe discussion is a bit terse.

Some examples:

class Foo
  CONST = 'Foo::CONST'
  class << self
    C开发者_Python百科ONST = '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


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


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号