Ruby:define_method 与 def
Posted
技术标签:
【中文标题】Ruby:define_method 与 def【英文标题】:Ruby: define_method vs. def 【发布时间】:2010-09-16 04:52:18 【问题描述】:作为一个编程练习,我编写了一个 Ruby sn-p,它创建一个类,从该类实例化两个对象,对一个对象进行猴子补丁,并依靠 method_missing 对另一个对象进行猴子补丁。
这是交易。这按预期工作:
class Monkey
def chatter
puts "I am a chattering monkey!"
end
def method_missing(m)
puts "No #m, so I'll make one..."
def screech
puts "This is the new screech."
end
end
end
m1 = Monkey.new
m2 = Monkey.new
m1.chatter
m2.chatter
def m1.screech
puts "Aaaaaargh!"
end
m1.screech
m2.screech
m2.screech
m1.screech
m2.screech
您会注意到我有一个method_missing 参数。我这样做是因为我希望使用 define_method 来动态创建具有适当名称的缺失方法。但是,它不起作用。事实上,即使使用带有静态名称的 define_method,如下所示:
def method_missing(m)
puts "No #m, so I'll make one..."
define_method(:screech) do
puts "This is the new screech."
end
end
以以下结果结束:
ArgumentError: wrong number of arguments (2 for 1)
method method_missing in untitled document at line 9
method method_missing in untitled document at line 9
at top level in untitled document at line 26
Program exited.
使错误消息更令人困惑的是我只有一个参数method_missing
...
【问题讨论】:
【参考方案1】:def method_missing(m)
self.class.class_exec do
define_method(:screech) puts "This is the new screech."
end
end
screech 方法将适用于所有 Monkey 对象。
【讨论】:
【参考方案2】:define_method
是对象 Class 的(私有)方法。您是从一个实例调用它。没有名为define_method
的实例方法,因此它递归到您的method_missing
,这次使用:define_method
(缺少的方法的名称)和:screech
(您传递给define_method
的唯一参数)。
试试这个(在所有 Monkey 对象上定义新方法):
def method_missing(m)
puts "No #m, so I'll make one..."
self.class.send(:define_method, :screech) do
puts "This is the new screech."
end
end
或者这个(只在被调用的对象上定义它,使用对象的“特征类”):
def method_missing(m)
puts "No #m, so I'll make one..."
class << self
define_method(:screech) do
puts "This is the new screech."
end
end
end
【讨论】:
这是一个很好的答案,Avdi,它解决了我的其他一些问题。谢谢。 作为一般规则,这说明了为什么您应该始终 a) 在method_missing
中使用白名单,以便您仅处理您实际使用的那些方法 感兴趣并且 b) 使用super
转发您不想想要处理“食物链上游”的所有事情。
@JörgWMittag 我可以多说几句 b) 使用 super 转发所有你不想处理“食物链上游”的东西。 ?【参考方案3】:
self.class.define_method(:screech) 不起作用,因为 define_method 是私有方法 你可以这样做
class << self
public :define_method
end
def method_missing(m)
puts "No #m, so I'll make one..."
Monkey.define_method(:screech) do
puts "This is the new screech."
end
【讨论】:
以上是关于Ruby:define_method 与 def的主要内容,如果未能解决你的问题,请参考以下文章