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

Posted by Alan O'Donnell on Stack Overflow See other posts from Stack Overflow or by Alan O'Donnell
Published on 2010-06-10T15:38:51Z Indexed on 2010/06/10 15:42 UTC
Read the original article Hit count: 251

Filed under:
|
|

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

© Stack Overflow or respective owner

Related posts about ruby

Related posts about constants