ruby - 在 Ruby 中动态定义类方法

标签 ruby metaprogramming

在 Ruby 1.9.3 中,我需要创建几个类实例,每个类实例都具有相似的实例方法和类方法,但仅在几个固定参数方面有所不同。它们的类类型的区别也很重要,所以我不能简单地使用同一类的不同实例。

一个简化的示例如下所示。

module Animal
private
  def self.make_animal(name, legs, noise)
    klass = Class.new
    klass.const_set(:NUM_LEGS, legs)
    klass.class.send(:define_method, :scream) { noise.upcase + '!' }
    Animal.const_set(name, klass)
  end
  make_animal :Tiger, 4, 'roar'
  make_animal :Human, 2, 'derp'
end

除了动态定义“scream”方法的 block 中使用的变量在“scream”方法的运行时而不是“make_animal”方法的运行时绑定(bind)之外,这似乎工作正常。

Animal::Human::NUM_LEGS # => 2 -- ok
Animal::Tiger::NUM_LEGS # => 4 -- ok
Animal::Human.scream # => "DERP!" -- ok
Animal::Tiger.scream # => "DERP!" -- fail!

如何修改上面的代码,让老虎尖叫“ROAR!”

[注意] 我确实需要在示例中维护愚蠢的 OO 结构,原因过于复杂,无法在此描述。我只对学习如何使用参数化方法实现以编程方式在动态定义的类上定义类方法感兴趣。

最佳答案

klass.class 在两种情况下 (Class) 相同:所有类都是 Class 的实例。结果,你定义了 scream,然后又重新定义了它。

在 ruby​​ 中通常被认为是类方法的实际上是单例方法(如果您有兴趣,可以阅读很多关于 eigenclasses 等的东西)。

def some_object.foo
end

Construct 创建单例方法。通常这将在类定义中,使用 self 但你可以在任何事情上这样做,例如如果你这样做

x = 'dog'
def x.bark
  "Woof"
end

然后 x.bark 将返回 woof,但不会在任何其他字符串上定义 bark。

这里你的方法需要引用你的noise变量,所以你需要使用define_singleton_method来定义你的方法。

如果您仍在使用 ruby​​ 1.8,则不能使用 define_singleton_method - 您需要利用这样一个事实,即单例方法是 eigenclass 上的方法。

klass = Class.new
eigenclass = class << klass; self; end
eigenclass.send(:define_method, :scream){noise}

相当于使用define_singleton_method

关于ruby - 在 Ruby 中动态定义类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13847543/

相关文章:

ruby - rbenv:在 Linux Mint 上找不到 gem 命令

javascript - "Rails way"应用 javascript 链接

c++ - 带模板的 N 维嵌套元循环

Ruby Hash 其键是对象的函数?

ruby-on-rails - PG::UndefinedTable:错误:缺少 FROM 子句

ruby - Ruby 中的并行数组

c++ - 在 C++ 中如何使用模板调用提供类型的特定成员

ruby-on-rails-3.2 - 如何从其 "string name"访问实例变量?

r - 元编程和 R 中的替代函数

macros - 如何 “splat” 动态创建函数的函数参数