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

I work through Pickaxe 1.9, and I am a little confused by the constant search in instance / class_eval blocks. I am using 1.9.2.

Ruby seems to handle persistent searches in * _eval blocks in the same way as the lookup method:

  • find the definition in receiver.singleton_class (plus mixins);
  • then to receiver.singleton_class.superclass (plus mixins);
  • then continue your own chain until you reach #<Class:BasicObject> ;
  • whose superclass is the class;
  • and then up the rest of the chain of ancestors (including Object , which stores all the constants that you define at the top level), checking for mixes along the way

It is right? The discussion of Pickaxe is a little bit.

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 does not stop along the chain of ancestors Foo-the-object!

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 eigenclass A.class_eval { CONST } # => "N::CONST", ditto A.new.instance_eval { CONST } # => "M::CONST", because A.new.class, A, mixes in M 
+3
source share
2 answers

In 1.9.2, constant search changed again to be equivalent to 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 quasilexically bounded. It was USED to be different between branches 1.9.x and 1.8.x, and it made library cross-compatibility a pain, so they changed it.

Yehuda Katz (successful) calls for restoring behavior 1.8

+1
source

Constants are effectively lexically limited, so you cannot get a short hand to them outside the hierarchy of modules in which they are defined. There is a good explanation here and a little off topic, but good to read here .

0
source

Source: https://habr.com/ru/post/912784/


All Articles