在下面的代码中,方法roar
未在类Lion
中定义,但仍可使用method_missing
进行调用。
class Lion
def method_missing(name, *args)
puts "Lion will #{name}: #{args[0]}"
end
end
lion = Lion.new
lion.roar("ROAR!!!") # => Lion will roar: ROAR!!!
在哪些情况下我应该如何使用此method_missing
?使用安全吗?
答案 0 :(得分:9)
完全安全使用,只要您以预期的方式使用它并且不会被带走。毕竟,并非你所能做的一切都值得做。
method_missing
的优点是你可以用独特的方式回应各种事物。
缺点是你没有宣传你的能力。期望您respond_to?
某些内容的其他对象无法获得确认,并且可能会以您不想要的方式处理您的自定义对象。
为了构建领域特定语言并在组件之间提供非常松散的粘合剂,这种东西是非常宝贵的。
一个很好的例子是Ruby OpenStruct类。
答案 1 :(得分:8)
摘要:何时使用?什么时候会让你的生活更轻松和不会使他人的生活变得复杂。
这是一个浮现在脑海中的例子。它来自redis_failover gem。
# Dispatches redis operations to master/slaves.
def method_missing(method, *args, &block)
if redis_operation?(method)
dispatch(method, *args, &block)
else
super
end
end
这里我们检查调用的方法是否实际上是redis连接的命令。如果是这样,我们将其委托给底层连接。如果没有,请转发到超级。
method_missing
应用程序的另一个着名示例是ActiveRecord查找程序。
User.find_by_email_and_age('me@example.com', 20)
当然,没有一种方法find_by_email_and_age
。相反,method_missing
会破坏名称,分析部分并使用适当的参数调用find
。
答案 2 :(得分:4)
这是我的最爱
class Hash
def method_missing(sym,*args)
fetch(sym){fetch(sym.to_s){super}}
end
end
这让我可以像访问属性那样访问哈希值。在使用JSON数据时,这非常方便。
因此,例如,我可以写tweets.collect{|each|each['text']}
而不是写tweets.collect(&:text)
,而不是写tweets.first['author']
。或者,而不是tweets.first.author
我可以写{{1}}感觉更自然。实际上,它为您提供了对哈希值的Javascript样式访问。
NB,我期待猴子在我家门口修补警察......
答案 3 :(得分:4)
首先,请坚持Sergio Tulentsev的总结。
除此之外,我认为看一些例子是了解method_missing
的正确与错误情况的最佳方式;所以这是另一个简单的例子:
我最近在Null Object中使用了method_missing
。
Null对象是订单模型的替代品。
订单存储不同货币的不同价格。
没有method_missing
,它看起来像这样:
class NullOrder
def price_euro
0.0
end
def price_usd
0.0
end
# ...
# repeat for all other currencies
end
使用method_missing
,我可以将其缩短为:
class NullOrder
def method_missing(m, *args, &block)
m.to_s =~ /price_/ ? 0.0 : super
end
end
当我向NullOrder
添加新的price_xxx
属性时,不必(记得)更新Order
的附加好处。
答案 4 :(得分:3)
我还发现了(Paolo Perrotta)的一篇博文,其中展示了何时使用method_missing:
class InformationDesk
def emergency
# Call emergency...
"emergency() called"
end
def flights
# Provide flight information...
"flights() called"
end
# ...even more methods
end
检查午餐时间是否有人询问过服务。
class DoNotDisturb
def initialize
@desk = InformationDesk.new
end
def method_missing(name, *args)
unless name.to_s == "emergency"
hour = Time.now.hour
raise "Out for lunch" if hour >= 12 && hour < 14
end
@desk.send(name, *args)
end
end
# At 12:30...
DoNotDisturb.new.emergency # => "emergency() called"
DoNotDisturb.new.flights # ~> -:37:in `method_missing': Out for lunch (RuntimeError)