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

标签 ruby constants instance-eval

我正在研究 Pickaxe 1.9,我对 instance/class_eval block 中的常量查找感到有点困惑。我正在使用 1.9.2。

似乎 Ruby 在 *_eval block 中处理常量查找的方式与处理方法查找的方式相同:

  1. 在 receiver.singleton_class 中查找定义(加上 mixins);
  2. 然后在 receiver.singleton_class.superclass 中(加上 mixins);
  3. 然后继续沿着特征链向上,直到到达 #<Class:BasicObject> ;
  4. 它的父类(super class)是Class;
  5. 然后沿着祖先链的其余部分(包括 Object ,它存储您在顶层定义的所有常量),沿途检查混入

这是正确的吗? 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 的祖先链中的一站!

还有一个混合的例子:

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

基本上,常量是准词法范围的。这过去在 1.9.x 和 1.8.x 分支之间是不同的,这使得库的交叉兼容性很痛苦,所以他们改回来了。

Yehuda Katz's (successful) appeal to restore 1.8 behavior

关于Ruby:常量查找在 instance_eval/class_eval 中如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3015947/

相关文章:

ruby-on-rails - 对象实例的未定义​​方法 `includes'

haskell - mapM 如何与 Haskell 中的 const 函数一起工作?

javascript - JavaScript 中的 const 关键字 :

c++ - 如何根据模板参数创建一个方法const?

java - 解码 MIME(HTML+附件)

ruby-on-rails - 测试环境中的Searchkick映射不适用于 `fields`选项

ruby - 没有 Rails 的国际化?

ruby - class_eval 与 instance_eval

ruby - Ruby 1.9.2 中 instance_eval 在哪里定义?

ruby - module_eval/class_eval/instance_eval 如何统计行号