简体   繁体   中英

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

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
    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

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM