在运行时继承一个新的类方法

发布于 2025-01-01 10:11:24 字数 1202 浏览 2 评论 0原文

在 Ruby 中,.constants 对于检查类很有用:

> Numeric.constants(false)
=> [:KILOBYTE, :MEGABYTE, :GIGABYTE, :TERABYTE, :PETABYTE, :EXABYTE]
> Object.constants(false)
=> [:Object, :Module, ...]

这是在 Module

> Object.method(:constants)
=> #<Method: Class(Module)#constants>

我想添加另一种方法来打印包含所有常量及其值的哈希值。这是到目前为止的结果:

def Module.constants_hash(inherit=true)
    self.constants(inherit).inject({}) do |hash, constant|
        hash[constant] = self::const_get(constant)
        hash
    end
end

这适用于Module(尽管它没有常量,因此结果只是一个空哈希),但是它不是继承的

> Object.constants_hash(false)
NoMethodError: undefined method `constants_hash' for Object:Class
from (pry):117:in `<main>'

我当然可以将代码中的类名更改为例如Object以使调用起作用,但是是否可以使所有依赖模块也继承新方法?换句话说,是否可以在运行时添加一个方法,然后由需要修改后的类的类继承?

我宁愿不要重载原始的 Module.constants,以避免更改 API。

In Ruby, <ClassName>.constants is useful to inspect classes:

> Numeric.constants(false)
=> [:KILOBYTE, :MEGABYTE, :GIGABYTE, :TERABYTE, :PETABYTE, :EXABYTE]
> Object.constants(false)
=> [:Object, :Module, ...]

This is defined in Module:

> Object.method(:constants)
=> #<Method: Class(Module)#constants>

I'd like to add another method to print a hash with all the constants and their values. Here's the result so far:

def Module.constants_hash(inherit=true)
    self.constants(inherit).inject({}) do |hash, constant|
        hash[constant] = self::const_get(constant)
        hash
    end
end

This works for Module (although it has no constants, so the result is just an empty hash), but it's not inherited:

> Object.constants_hash(false)
NoMethodError: undefined method `constants_hash' for Object:Class
from (pry):117:in `<main>'

I can of course change the class name in the code to e.g. Object to make the call work, but is it possible to make all the dependent modules inherit the new method as well? In other words, is it possible to add a method at runtime which is then inherited by classes which require the modified class?

I'd rather not overload the original Module.constants, to avoid changing the API.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

荒芜了季节 2025-01-08 10:11:24

ObjectClass 类型的实例。 Class 类继承自Module。为了让 Object.constants_hash 工作,您需要定义 ClassModule 类的 instance 方法

class Module
  def constants_hash(inherit=true)
      self.constants(inherit).inject({}) do |hash, constant|
          hash[constant] = self::const_get(constant)
          hash
      end
  end
end

:您编写代码时只需将 constants_hash 添加到 Module 实例(类型为 Class)的单个类,这就是原因你没有得到预期的结果。

Object is an instance of type Class. Class class is inherited from Module. In order for Object.constants_hash to work, you need to define instance method of Class or Module classes:

class Module
  def constants_hash(inherit=true)
      self.constants(inherit).inject({}) do |hash, constant|
          hash[constant] = self::const_get(constant)
          hash
      end
  end
end

In you code you just add constants_hash to a singleton class of Module instance (of type Class), this is why you don't get expected result.

灯角 2025-01-08 10:11:24

通过在模块中声明此方法,然后根据需要将其混合到每个上下文中,您可能会有更好的运气:

module ConstantsHash
  def constants_hash(inherit = true)
    Hash[
      self.constants(inherit).collect do |constant|
        [ constant, const_get(constant) ]
      end
    ]
  end
end

Module.extend(ConstantsHash)
Object.extend(ConstantsHash)

puts Object.constants_hash.inspect

请注意,使用 Hash[] 而不是 inject({ }) 在这种情况下似乎确实效果更好。

You might have better luck by declaring this method in a module, then mixing it in to each context as required:

module ConstantsHash
  def constants_hash(inherit = true)
    Hash[
      self.constants(inherit).collect do |constant|
        [ constant, const_get(constant) ]
      end
    ]
  end
end

Module.extend(ConstantsHash)
Object.extend(ConstantsHash)

puts Object.constants_hash.inspect

As a note, using Hash[] instead of inject({ }) does seem to work better in cases like this.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文