response_to和response_to_missing有何不同?

Dar*_*dza 5 ruby metaprogramming

我对何时使用每种方法感到困惑。从respond_to?文档:

如果obj响应给定的方法,则返回true 。仅当可选的第二个参数的值为true时,私有方法才包含在搜索中。

如果未实现该方法,例如Windows上的Process.fork,GNU / Linux上的File.lchmod等,则返回false。

如果未定义方法,则response_to_missing?方法被调用并返回结果。

respond_to_missing?

Hook方法,返回obj是否可以响应id方法。

请参阅#respond_to?。

两种方法都带有两个参数。
两种方法似乎都是同一件事(检查某个对象是否响应给定的方法),为什么我们应该同时使用(拥有)这两种方法呢?

定义“ resond_to_missing?”使您能够采用方法:

class A
  def method_missing name, *args, &block
    if name == :meth1
      puts 'YES!'
    else
      raise NoMethodError
    end
  end

  def respond_to_missing? name, flag = true
    if name == :meth1
      true
    else
      false
    end
  end
end

[65] pry(main)> A.new.method :meth1
# => #<Method: A#meth1>
Run Code Online (Sandbox Code Playgroud)

为什么respond_to?不能这样做?

我猜:

respond_to? 检查方法是否在:

  1. 当前对象。
  2. 父对象。
  3. 包含的模块。

respond_to_missing? 检查方法是否为:

  1. 通过定义method_missing

通过数组可能的方法:

def method_missing name, *args, &block
  arr = [:a, :b, :c]
  if arr.include? name
    puts name
  else
    raise NoMethodError
  end
end
Run Code Online (Sandbox Code Playgroud)

将其委托给其他对象:

class A
  def initialize name
    @str = String name
  end

  def method_missing name, *args, &block
    @str.send name, *args, &block
  end
end
Run Code Online (Sandbox Code Playgroud)

2。我不知道的其他方式。

两者都应在哪里定义/使用(我也猜):

从1.9.3开始(我记得还不错)仅定义respond_to_missing?但仅使用respond_to?

最后的问题

我对吗?我错过了什么吗?纠正所有不良情况和/或回答此问题中提出的问题

Sim*_*tti 4

respond_to_missing?当您使用方法缺失技术提供其他方法时,应该更新。这将使 Ruby 解释器更好地理解新方法的存在。

\n\n

事实上,如果不使用respond_to_missing?,您将无法使用 来获取该方法method

\n\n

Marc-Andr\xc3\xa9 发表了一篇关于respond_to_missing?.

\n\n
\n

为了respond_to?要返回 true,可以将其专门化,如下所示:

\n\n
class StereoPlayer\n  # def method_missing ...\n  #   ...\n  # end\n\n  def respond_to?(method, *)\n    method.to_s =~ /play_(\\w+)/ || super\n  end\nend\np.respond_to? :play_some_Beethoven # => true\n
Run Code Online (Sandbox Code Playgroud)\n\n

这更好,但它仍然不能使 play_some_Beethoven 的行为与方法完全相同。的确:

\n\n
p.method :play_some_Beethoven\n# => NameError: undefined method `play_some_Beethoven\'\n#               for class `StereoPlayer\'\n
Run Code Online (Sandbox Code Playgroud)\n\n

Ruby 1.9.2 的引入respond_to_missing?为该问题提供了一个干净的解决方案。与其专一,不如respond_to?专一respond_to_missing?。Here\xe2\x80\x99s 是一个完整的示例:

\n\n
class StereoPlayer\n  # def method_missing ...\n  #   ...\n  # end\n\n  def respond_to_missing?(method, *)\n    method =~ /play_(\\w+)/ || super\n  end\nend\n\np = StereoPlayer.new\np.play_some_Beethoven # => "Here\'s some_Beethoven"\np.respond_to? :play_some_Beethoven # => true\nm = p.method(:play_some_Beethoven) # => #<Method: StereoPlayer#play_some_Beethoven>\n# m acts like any other method:\nm.call # => "Here\'s some_Beethoven"\nm == p.method(:play_some_Beethoven) # => true\nm.name # => :play_some_Beethoven\nStereoPlayer.send :define_method, :ludwig, m\np.ludwig # => "Here\'s some_Beethoven"\n
Run Code Online (Sandbox Code Playgroud)\n
\n\n

另请参见始终定义 respond_to_missing?当重写 method_missing 时

\n