我创建了一个包含常量NAME和方法hello的模块.如果类包含模块,则两个定义应在不同范围内可见.
module A NAME = 'otto' def self.included(base) base.extend(ClassMethods) end def hello(name = 'world') self.class.hello(name) end module ClassMethods def hello(name = 'world') "Hello #{name}!" end end end class B include A def instance_scope p [__method__,hello(NAME)] end def self.class_scope p [__method__,hello(NAME)] end class << self def eigen_scope p [__method__,hello(NAME)] end end end B.new.instance_scope B.class_scope B.eigen_scope #=> script.rb:34:in `eigen_scope': uninitialized constant Class::NAME (NameError) from script.rb:41
解决方法
解
class << self def eigen_scope p [__method__,hello(self::NAME)] #=> [:eigen_scope,"Hello otto!"] end end
为什么self :: NAME有效?
> A :: NAME将是最简单的硬编码版本.
> B :: NAME也可以,因为B包括A.
>在eigen_scope里面,self是B,所以self :: NAME也可以
> self :: NAME也可以在self.class_scope中使用
> self :: NAME在instance_scope中不起作用:B实例不是类/模块.
为什么NAME不起作用?
constant lookup searches for constants that are defined in
Module.nesting
,Module.nesting.first.ancestors
,andObject.ancestors
ifModule.nesting.first
is nil or a module
self在class_scope和eigen_scope中是相同的.
尽管如此,Module.nesting是不同的:
> [B]用于class_scope
> [#< Class:B>,B]用于eigen_scope
所以Module.nesting.first.ancestors是:
> class_scope的[B,A,Object,Kernel,BasicObject]
eigen_scope的[#< Class:B>,A :: ClassMethods,#< Class:Object>,#< Class:BasicObject>,Class,Module,BasicObject]
A没有被搜索,但是A :: ClassMethods!
所以你可以定义:
module A module ClassMethods NAME = 'Bob' end end