【问题标题】:How do I get constants defined by Ruby's Module class via reflection?如何通过反射获取 Ruby 的 Module 类定义的常量?
【发布时间】:2011-01-19 12:53:28
【问题描述】:

我试图让 Matz 和 Flanagan 的“Ruby 编程语言”元编程章节进入我的脑海,但是我无法理解我梦想的以下代码 sn-p 的输出:

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"]

本书指出类方法constants返回类的常量列表(正如您在A.constants的输出中看到的那样)。 当我遇到上述奇怪行为时,我试图获取为 Module 类定义的常量列表。

A 的常量显示在 Module.constants 中。如何获取 Module 类定义的常量列表?

docs 状态

Module.constants 返回系统中定义的所有常量。包括所有类和方法的名称

由于A 继承自Module.constants 的实现,它在基类型和派生类型中的行为有何不同?

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

注意:如果您使用的是 Ruby 1.9,constants 将返回一个符号数组而不是字符串。

【问题讨论】:

  • 我回答你的问题了吗?我之所以问,是因为我的回答未被“接受”,但没有要求提供任何其他信息...
  • @Marc - 你的回答让我想到了更多的问题、更多的涂鸦和擦除。这周花了我的时间试图解决方法解决方案......我仍然不清楚可能性是什么 - 但我认为我 90% 确定它是如何工作的。请参阅下面的帖子。

标签: ruby reflection metaprogramming


【解决方案1】:

好问题!

您的困惑是由于类方法Module.constants 隐藏了Module 的实例方法Module#constants

在 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).

在上面的示例中,A.constants 调用 Module#constants(实例方法),而 Module.constants 调用,嗯,Module.constants

在 Ruby 1.9 中,您因此想调用 Module.constants(true)

在 Ruby 1.8 中,可以在 Module 上调用实例方法 #constants。您需要获取实例方法并将其绑定为类方法(使用不同的名称):

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

我希望我能够将我的backports gem 的 1.9 功能完全向后移植到 1.8,但是我想不出在 Ruby 1.8 中只获取模块常量的方法,不包括继承的常量。

编辑:刚刚更改了官方文档以正确反映这一点...

【讨论】:

  • @Marc - 如果您能回顾一下我对方法解析的理解并确认它,将不胜感激。博客文章链接在我下面的文章中。谢谢并接受:)
【解决方案2】:

在马克回应后,我不得不回到我的思考洞穴中。修改了更多的代码 sn-ps,然后再修改了一些。最后,当 Ruby 的方法解析似乎有意义时,将其写为博客文章,以免我忘记。

符号:如果A"A的特征类

当调用A.constants 时,方法解析(参考my blog post 中的图像以获得视觉帮助)按顺序查找以下位置

  • MyClass"Object"BasicObject"(单例方法)
  • Class(实例方法)
  • Module(实例方法)
  • Object(实例方法)和内核
  • BasicObject(实例方法)

Ruby 找到实例方法Module#constants

Module.constants 被调用时,Ruby 会查看

  • Module"Object"BasicObject"(单例方法)
  • Class(实例方法)
  • Module(实例方法)
  • Object(实例方法)和内核
  • BasicObject(实例方法)

这一次,Ruby 在 Module".constants 找到了单例/类方法,正如 Marc 所说。

Module 定义了一个隐藏实例方法的单例方法。单例方法返回所有已知的常量,而实例方法返回当前类及其祖先中定义的常量。

【讨论】:

    猜你喜欢
    • 2012-05-02
    • 1970-01-01
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多