在下面的代码,方法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
? 而且是可以安全使用?
这是使用所提供完全安全的 ,你预期的方式使用它,不要得意忘形。 并非一切都可以做的是值得做的,毕竟。
的优势method_missing
是,你可以在独特的方式各种各样的事情作出回应。
缺点是你不做广告你的能力。 那希望你对其他对象respond_to?
事情不会得到确认,可能对待你的自定义对象在你不打算的方式。
对于建筑领域特定语言,并提供非常宽松的胶体成分之间,这样的事情是非常宝贵的。
在哪里,这是一个不错的选择一个很好的例子是Ruby OpenStruct类。
总结:何时使用? 当它会让你的生活更轻松和他人的生活不复杂。
下面是弹出想到一个例子。 这是从redis_failover宝石。
# 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
适当的参数。
这里是我的最爱
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
这感觉更自然。 实际上,它给你的Javascript式访问哈希值。
NB, 我期待的猴子在我家门口修补警方任何一分钟...
首先,坚持塞尔吉奥Tulentsev的总结。
除此之外,我觉得看的例子是获得正确和错误的情况下,感觉最好的方式method_missing
; 所以这里是另外一个简单的例子:
我最近使用method_missing
在一个空对象 。
该空对象是一阶模型的替代品。
该命令存储不同价格不同货币。
如果没有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
。
我还发现,从(保罗·佩罗塔)博客文章在那里证明时使用的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)