如何确定持续可访问性?

时间:2016-01-26 02:11:04

标签: ruby constants

Ruby在持续可访问性方面似乎已经多次发生过变化。对于Ruby 1.9.2,在问题和答案here中有关于持续可访问性的描述,但是那里写的不再是真实的。

在Ruby 2.3中,如果我在类中定义了一个常量:

class A
  Foo = :a
end

我无法通过instance_evalclass_eval

访问它
A.new.instance_eval{Foo} # => error
A.class_eval{Foo} # => error
A.instance_eval{Foo} # => error

虽然我可以从课堂上访问它:

class A; Foo end # => :a

Ruby 2.3中的常量可访问性如何工作?如果可能的话,请解释Ruby中常量可访问性的历史变化以及导致它们的参数。

2 个答案:

答案 0 :(得分:2)

注意:以下答案基于Ruby 2.2,尚未在2.3上验证

根据Module#class_eval

的文档
  

在mod的上下文中计算字符串或块,除外   给出一个块,常量/类变量查找不受影响。

虽然下面的代码出错了,

A.class_eval{Foo} # uninitialized constant Foo (NameError)

以下作品正在eval编辑。

A.class_eval("Foo") #=> :a

似乎Constant需要模块名称或类名才能正确评估它。以下是:

A.class_eval{self::Foo} #=> :a

那么,这些:

A.new.instance_eval {self.class::Foo} #=> :a
A.instance_eval {self::Foo} #=> :a

答案 1 :(得分:2)

Ruby中的常量查找使用lexical scope遍历当前作用域并包含模块。可以通过Module.nesting

查看查找路径
> module Out
>   module In
>     puts Module.nesting
>   end
> end
Out::In # gets searched for a given constant first
Out 

查询在块内保持相同以启用关闭行为,即使对于class_eval也是如此。

然而,在Ruby 1.9中,instance_evalinstance_exec的接收者, class_evalclass_exec被添加到查找路径之前,这意味着所有常量引用都将首先在接收器的范围中查找。

Yehuda Katz提出issue引用严重破坏:

  

考虑RSpec的情况:

describe "Date" do   
  it "equals itself" do
    Date.today.should == Date.today   
  end 
end
     

如果我们首先使用动态范围,那么如果RSpec添加Spec :: Date,它将会   突然打破这个规格。词汇范围更直观,而且是   今天许多正常用途的预期。

随后行为reverted又恢复到1.8。