如何在initialize()中使用define_method

时间:2013-10-14 20:09:45

标签: ruby metaprogramming

尝试在define_method内使用initialize,但获取undefined_method define_method。我做错了什么?

class C
  def initialize(n)    
    define_method ("#{n}") { puts "some method #{n}" }    
  end
end

C.new("abc") #=> NoMethodError: undefined method `define_method' for #<C:0x2efae80>

3 个答案:

答案 0 :(得分:39)

我怀疑你正在寻找define_singleton_method

  

define_singleton_method(symbol,method)→new_method
   define_singleton_method(symbol){block}→proc

     

在接收器中定义单例方法。 方法参数可以是ProcMethodUnboundMethod对象。如果指定了块,则将其用作方法体。

如果在self.class上使用define_method,则会将新方法创建为整个类的实例方法,以便它可以作为该类的所有实例的方法。

您可以像这样使用define_singleton_method

class C
  def initialize(s)    
    define_singleton_method(s) { puts "some method #{s}" }    
  end
end

然后:

a = C.new('a')
b = C.new('b')
a.a # puts 'some method a'
a.b # NoMethodError
b.a # NoMethodError
b.b # puts 'some method b'

如果您initialize做了:

self.class.send(:define_method,n) { puts "some method #{n}" }    
然后你会得到:

a.a # puts 'some method a'
a.b # puts 'some method b'
b.a # puts 'some method a'
b.b # puts 'some method b'

这可能不是你想要的。创建一个新实例并让整个类更改是相当奇怪的。

答案 1 :(得分:25)

执行以下操作:

class C
  def initialize(n)    
    self.class.send(:define_method,n) { puts "some method #{n}" }    
  end
end

ob = C.new("abc")
ob.abc
# >> some method abc

Module#define_method是一个私有方法,也是一个方法。您尝试在{的实例上调用它时,一个方法无法正常工作{1}}。您必须在C上使用C进行调用。

答案 2 :(得分:0)

您快到了。只需使用self.class指向该类,甚至不需要使用:send

class C
  def initialize(n)    
    self.class.define_method ("#{n}") { puts "some method #{n}" }    
  end
end
ob = C.new('new_method')
ob2 = C.new('new_method2')
# Here ob and ob2 will have access to new_method and new_method2 methods

您还可以将其与:method_missing一起使用,以向您的班级讲授新的方法,例如:

class Apprentice
  def method_missing(new_method)
    puts "I don't know this method... let me learn it :)"
    self.class.define_method(new_method) do
      return "This is a method I already learned from you: #{new_method}"
    end
  end
end
ap = Apprentice.new
ap.read
=> "I don't know this method... let me learn it :)"
ap.read
=> "This is a method I already learned from you: read"