respond_to和respond_to_missing有何不同?

时间:2013-12-22 15:52:48

标签: ruby metaprogramming

我很困惑何时使用这些方法。 来自respond_to?文档:

  

如果 obj 响应给定方法,则返回true。私人方法   仅在可选的第二个参数中包含在搜索中   评估为真。

     

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

     

如果没有定义方法,则response_to_missing?方法被称为和   结果返回。

respond_to_missing?

  

Hook方法返回 obj 是否可以响应 id 方法或   不

     

请参阅#respond_to?。

两种方法都有两个参数 两种方法似乎都是一样的(检查某个对象是否响应给定的方法)所以为什么我们应该使用(have)两者?

定义'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>

为什么respond_to?无法做到这一点?

我猜:

respond_to?检查方法是否在:

  1. 当前对象。
  2. 父对象。
  3. 包含的模块。
  4. respond_to_missing?检查方法是否为:

    1. 通过method_missing
    2. 定义

      通过一系列可能的方法:

      def method_missing name, *args, &block
        arr = [:a, :b, :c]
        if arr.include? name
          puts name
        else
          raise NoMethodError
        end
      end
      

      将其委托给不同的对象:

      class A
        def initialize name
          @str = String name
        end
      
        def method_missing name, *args, &block
          @str.send name, *args, &block
        end
      end
      

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

      两者都应该被定义/使用(我猜也是):

      从1.9.3开始(我记得公平)仅定义respond_to_missing?但仅使用respond_to?

      上次提问

      我是对的吗?我错过了什么吗?纠正所有错误和/或回答问题中提出的问题。

1 个答案:

答案 0 :(得分:4)

当您使用缺少方法的方法提供其他方法时,应该更新

respond_to_missing?。这将使Ruby解释器更好地理解新方法的存在。

事实上,如果不使用respond_to_missing?,则无法使用method获取该方法。

Marc-André posted a great article关于respond_to_missing?

  

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

class StereoPlayer
  # def method_missing ...
  #   ...
  # end

  def respond_to?(method, *)
    method.to_s =~ /play_(\w+)/ || super
  end
end
p.respond_to? :play_some_Beethoven # => true
     

这样更好,但它仍然没有使play_some_Beethoven的行为与方法完全相同。事实上:

p.method :play_some_Beethoven
# => NameError: undefined method `play_some_Beethoven'
#               for class `StereoPlayer'
     

Ruby 1.9.2引入了respond_to_missing?,它为问题提供了一个干净的解决方案。而不是专门化respond_to?一个专门化respond_to_missing?。这是一个完整的例子:

class StereoPlayer
  # def method_missing ...
  #   ...
  # end

  def respond_to_missing?(method, *)
    method =~ /play_(\w+)/ || super
  end
end

p = StereoPlayer.new
p.play_some_Beethoven # => "Here's some_Beethoven"
p.respond_to? :play_some_Beethoven # => true
m = p.method(:play_some_Beethoven) # => #<Method: StereoPlayer#play_some_Beethoven>
# m acts like any other method:
m.call # => "Here's some_Beethoven"
m == p.method(:play_some_Beethoven) # => true
m.name # => :play_some_Beethoven
StereoPlayer.send :define_method, :ludwig, m
p.ludwig # => "Here's some_Beethoven"

另见Always Define respond_to_missing? When Overriding method_missing