ssc*_*eck 5 ruby metaprogramming eigenclass
我创建了一个包含常量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
Run Code Online (Sandbox Code Playgroud)
但是常量在本征类的实例方法范围中是不可见的class << self.
有没有办法使模块更健壮,并在上面的错误范围内提供常量?
class << self
def eigen_scope
p [__method__, hello(self::NAME)]
#=> [:eigen_scope, "Hello Otto!"]
end
end
Run Code Online (Sandbox Code Playgroud)
self::NAME有效?A::NAME将是最简单的硬编码版本。B::NAME也会起作用,因为B包括Aeigen_scope,self是B, 所以self::NAME也有效self::NAME也会工作在self.class_scopeself::NAME不起作用instance_scope:B实例不是类/模块。NAME?这里有一个很好的解释。
常量查找搜索在
Module.nesting、Module.nesting.first.ancestors和Object.ancestorsifModule.nesting.firstis nil 或模块中定义的常量
selfclass_scope在和中是相同的eigen_scope。
Module.nesting但不同的是:
[B]为了class_scope[#<Class:B>, B]为了eigen_scope也是如此Module.nesting.first.ancestors:
[B, A, Object, Kernel, BasicObject]为了class_scope[#<Class:B>, A::ClassMethods, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]为了eigen_scopeA没有被搜索到,但是A::ClassMethods!
所以你可以定义:
module A
module ClassMethods
NAME = 'Bob'
end
end
Run Code Online (Sandbox Code Playgroud)