覆盖method_missing方法的目的是什么?

时间:2016-06-22 07:06:55

标签: ruby-on-rails ruby

通过"良好的基础Rubyist"书。在第4章中,它介绍了如何覆盖method_missing方法的示例。它解释得很清楚的原因是你想要首先做到这一点?覆盖method_missing方法的目的是什么?

3 个答案:

答案 0 :(得分:2)

这是元编程所必需的,如果事先不知道,那个对象“预期”的方法。

Naïve示例(为所有派生类的所有实例变量实现attr_reader

class A
  def method_missing m, *args, &cb
    return instance_variable_get(:"@#{m}") if instance_variables.include? :"@#{m}"
    super
  end
end

class B < A
  def initialize
    @b = 42
  end
end

B.new.b
#⇒ 42

对于更复杂的示例,可以查看Rails代码,其中包含method_missing个。

答案 1 :(得分:2)

我不确定您正在阅读的Well Grounded Rubyist版本(考虑切换到第二版),但后者实际上会让您了解method_missing可以使用的内容对于。第113页的清单4.13 为您提供了一组结合一些类似的方法的想法,例如

class Person
  def all_with_children
    # some select...
  end
  def all_with_parents
    # seems like another select but joined with another table...
  end
  def all_with_cars
    # the same here...
  end
  def all_with_house
    # woah, four methods doing slightly the same!
  end
  # so what if you have 100 database attributes and want to 
  # provide a selector for all of them?
end

使用method_missing代替一些元编程:

def self.method_missing m, *args
  method = m.to_s
  if method.start_with? ("all_with_")
  # now we know that we're going to do SELECT.
  # the only thing to consider is what table should be joined.
  # we defer that from the right part of the method name
  # e.g. "children" for "all_with_children"
  # in case we gonna ask for "all_with_wife" we won't need to add new method!
end

Ruby on Rails 4之前,调用类似Person.find_by_username的内容是一种常见的模式,它隐含了相同的method_missing逻辑。

method_missing视为一种方法,使您有机会在应用程序因未知方法调用而失败之前执行某些操作。

您可能希望在失败时添加一些调试信息(将扩展错误描述记录到日志文件中,或向管理员发送电子邮件,说明出现了问题)。

method_missing可以让您只需几行就可以为所有属性定义自己的getter / setters方法。

简而言之,它为您提供了另一个编写简短且可读代码的机会。请注意,它不应该被滥用,因为您需要为其使用付出一些代价(包括整体代码复杂性和执行时间)。

答案 2 :(得分:1)

想象一下,如果您想要在不事先定义方法的情况下动态响应方法,或者因为一组方法名称使用相似/相同的代码来列出可能性。

例如,您可以使用具有固定价格的不同类,但您希望轻松为大量货币添加转化。所以你可以这样做:obj.price_euro,obj.price_usd等等。所有这些都可以被method_missing捕获。

这并不是一个好主意或坏主意。

请注意,如果您覆盖method_missing,那么您将比定义&#34; def方法慢得多,并且不要忘记更新respond_to?匹配!