Ruby:在instance_eval / class_eval中常量查找是如何工作的?

我正在通过Pickaxe 1.9工作,我对实例/ class_eval块中的常量查找感到困惑。我正在使用1.9.2。 似乎Ruby在* _eval块中处理常量查找的方式与方法查找相同: 在receiver.singleton_class(加上mixins)中寻找定义; 然后在receiver.singleton_class.superclass(加上mixins); 然后继续沿着本征链,直到你到达
#<Class:BasicObject>
; 其超类是Class; 然后上升祖先链的其余部分(包括
Object
,它存储你在顶层定义的所有常量),检查沿途的mixins 它是否正确? Pickaxe的讨论有点简洁。 一些例子:
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'
在class_eval示例中,Foo-the-class不是Foo-the-object的祖先链的停止! 以及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
    
已邀请:
在1.9.2中,常量查找再次改变为等同于1.8.7行为。
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
基本上,常量是准词法范围。这个USED在1.9.x和1.8.x分支之间是不同的,它使库交叉兼容性变得很痛苦,所以他们改回来了。 Yehuda Katz(成功)呼吁恢复1.8行为     
常量是有效的词法范围,因此您无法在定义它们的模块层次结构之外进行简短访问。这里有一个很好的解释,稍微偏离主题,但在这里读得很好。     

要回复问题请先登录注册