这是一个关于你的面条的问题。
在使用class_eval
并将类作为接收器进行评估的块中,方法声明和常量声明之间似乎存在差异。这里有一些代码可以证明这种差异:
module X
def save_block(&block)
@block = block
end
end
module Y
extend X
save_block do
SOME_CONSTANT = 1
def meth
"a method"
end
end
def self.included(m)
m.class_eval &@block
end
end
class Z
include Y
end
class W
include Y
end
至少在Ruby 1.9.3中执行此代码会导致以下错误:
warning: already initialized constant SOME_CONSTANT
我没想到。首先考虑meth
所在的位置:
Z.instance_methods(false)
=> [:meth]
W.instance_methods(false)
=> [:meth]
并且Y
没有任何实例方法:
Y.instance_methods(false)
=> []
这是有道理的,因为该块是以Z
和W
作为class_eval
的接收者执行的。但是,常量是不同的,因此出现错误消息,如下所示:
Y.constants(false)
=> [:SOME_CONSTANT]
Z.constants(false)
=> []
W.constants(false)
=> []
这里,常量最终在Y
中定义(出于某些奇怪的原因),因此当块第二次执行时,常量SOME_CONSTANT
已经定义。
我非常期待一些启示。
更新(2012/11/19):
正如@phoet在下面指出的那样(对我的回答的评论的回应),常量在块的lexical scope中定义,也就是说,在最初定义块的范围内。在我的例子中,这将是Y。