Gis*_*shu 42 ruby reflection metaprogramming
我试图让Matz和Flanagan的"Ruby Programming Language"元编程章节进入我的脑海,但是我无法理解我梦想的以下代码片段的输出:
p Module.constants.length # => 88
$snapshot1 = Module.constants
class A
NAME=:abc
$snapshot2 = Module.constants
p $snapshot2.length # => 90
p $snapshot2 - $snapshot1 # => ["A", "NAME"]
end
p Module.constants.length # => 89
p Module.constants - $snapshot1 # => ["A"]
p A.constants # => ["NAME"]
Run Code Online (Sandbox Code Playgroud)
本书指出class方法constants返回类的常量列表(正如您在输出中看到的那样A.constants).当我遇到上述奇怪的行为时,我试图获取为Module类定义的常量列表.
A的常量出现在Module.constants中.如何获取Module类定义的常量列表?
该文档的状态
Module.constants返回系统中定义的所有常量.包括所有类和方法的名称
由于A继承了它的实现Module.constants,它在基类和派生类型中的表现如何?
p A.class # => Class
p A.class.ancestors # => [Class, Module, Object, Kernel]
Run Code Online (Sandbox Code Playgroud)
注意:如果您使用的是Ruby 1.9,constants则会返回符号数组而不是字符串.
Mar*_*une 55
好问题!
你的困惑是由于该类方法Module.constants隐藏了实例方法Module#constants的Module.
在Ruby 1.9中,通过添加可选参数解决了这个问题:
# No argument: same class method as in 1.8:
Module.constants # ==> All constants
# One argument: uses the instance method:
Module.constants(true) # ==> Constants of Module (and included modules)
Module.constants(false) # ==> Constants of Module (only).
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,A.constants调用Module#constants(实例方法),而Module.constants调用,以及Module.constants.
在Ruby 1.9中,您需要调用Module.constants(true).
在Ruby 1.8,可以调用实例方法#constants上Module.您需要获取实例方法并将其绑定为类方法(使用不同的名称):
class << Module
define_method :constants_of_module, Module.instance_method(:constants)
end
# Now use this new class method:
class Module
COOL = 42
end
Module.constants.include?("COOL") # ==> false, as you mention
Module.constants_of_module # ==> ["COOL"], the result you want
Run Code Online (Sandbox Code Playgroud)
我希望我能够将1.9的功能完全反向移植到1.8我的backportsgem,但我想不出在Ruby 1.8中只获取模块常量的方法,不包括继承的模块.
编辑:刚刚更改了官方文档以正确反映这一点......