简体   繁体   English

如何通过反射获取Ruby的Module类定义的常量?

[英]How do I get constants defined by Ruby's Module class via reflection?

I was trying to get Matz and Flanagan's "Ruby Programming Language" metaprogramming chapter into my head, However I couldn't understand the output from the following code snippet that I dreamed up: 我试图让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"]

The book states that the class method constants returns the list of constants for the class (as you can see in the output for A.constants ). 本书指出类方法constants返回类的constants列表(如A.constants的输出中A.constants )。 I was trying to get the list of constants defined for the Module class when I came across the above strange behavior. 当我遇到上述奇怪的行为时,我试图获取为Module类定义的常量列表。

A 's constants show up in Module.constants. A常量出现在Module.constants中。 How do I get the list of constants defined by the Module class? 如何获取Module类定义的常量列表?

The docs state 文档陈述

Module.constants returns all constants defined in the system. Module.constants返回系统中定义的所有常量。 including names of all classes and methods 包括所有类和方法的名称

Since A inherits its implementation from Module.constants , how does it behave differently in the base and derived types? 由于AModule.constants继承了它的实现,它在基类和派生类型中的表现如何?

p A.class               # => Class
p A.class.ancestors       # => [Class, Module, Object, Kernel]

Note: If you're using Ruby 1.9, constants would return an array of symbols instead of strings. 注意:如果您使用的是Ruby 1.9, constants将返回符号数组而不是字符串。

Good question! 好问题!

Your confusion is due to the fact that the class method Module.constants hides the instance method Module#constants for Module . 你的困惑是由于类方法的事实Module.constants隐藏实例方法Module#constantsModule

In Ruby 1.9, this has been addressed by adding an optional parameter: 在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).

In your example above, A.constants calls Module#constants (the instance method), while Module.constants calls, well, Module.constants . 在上面的示例中, A.constants调用Module#constants (实例方法),而Module.constants调用Module.constants

In Ruby 1.9, you thus want to call Module.constants(true) . 在Ruby 1.9中,您希望调用Module.constants(true)

In Ruby 1.8, it is possible to call the instance method #constants on Module . 在Ruby 1.8中,可以在Module上调用实例方法#constants You need to get the instance method and bind it as a class method (using a different name): 您需要获取实例方法并将其绑定为类方法(使用不同的名称):

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

I wish I was able to backport the 1.9 functionality completely to 1.8 for my backports gem, but I can't think of a way to get only the constants of a Module, excluding the inherited ones, in Ruby 1.8. 我希望我能够将1.9功能完全反向移植到1.8 for backports gem,但我想不出在Ruby 1.8中只获取模块常量的方法,不包括继承的模块。

Edit : Just changed the official documentation to correctly reflect this... 编辑 :刚刚更改了官方文档以正确反映这一点......

I had to go back into my thinking cave for a while after Marc's response. 在Marc的回应之后,我不得不回到我的思考洞穴一段时间。 Tinkered with more code snippets and then some more. 使用更多代码片段进行修补,然后再进行更多操作。 Finally when Ruby's method resolution seemed to make sense wrote it down as a blog post so that I don't forget. 最后,当Ruby的方法分辨率似乎有意义时,将其写成博客文章,这样我就不会忘记。

Notation: If A" is the eigenclass of A 符号:如果A“A的本征

When A.constants is called, method resolution (refer to the image in my blog post to have a visual aid) looks up the following locations in order A.constants ,方法解析(请参阅我博客文章中的图像以获得视觉辅助)按顺序查找以下位置

  • MyClass" , Object" , BasicObject" (singleton methods) MyClass"Object"BasicObject" (单例方法)
  • Class (instance methods) Class (实例方法)
  • Module (instance methods) Module (实例方法)
  • Object (instance methods) and Kernel Object (实例方法)和内核
  • BasicObject (instance methods) BasicObject (实例方法)

Ruby finds the instance method Module#constants Ruby找到实例方法Module#constants

When Module.constants is called, Ruby looks at Module.constants ,Ruby会查看

  • Module" , Object" , BasicObject" (singleton methods) Module"Object"BasicObject" (单例方法)
  • Class (instance methods) Class (实例方法)
  • Module (instance methods) Module (实例方法)
  • Object (instance methods) and Kernel Object (实例方法)和内核
  • BasicObject (instance methods) BasicObject (实例方法)

this time, Ruby finds the singleton/class method at Module".constants as Marc said. 这次,Ruby在Module".constants找到了singleton / class方法,正如Marc所说。

Module defines a singleton method which shadows the instance method. 模块定义了一个影响实例方法的单例方法。 The singleton method returns all known constants whereas the instance method returns the constants defined in current class and its ancestors. 单例方法返回所有已知常量,而实例方法返回当前类及其祖先中定义的常量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM