57

What is the point of defining respond_to_missing? as opposed to defining respond_to?? What goes wrong if you redefine respond_to? for some class?

sawa
  • 165,429
  • 45
  • 277
  • 381

2 Answers2

57

Without respond_to_missing? defined, trying to get the method via method will fail:

class Foo
  def method_missing name, *args
    p args
  end

  def respond_to? name, include_private = false
    true
  end
end

f = Foo.new
f.bar  #=> []
f.respond_to? :bar  #=> true
f.method :bar  # NameError: undefined method `bar' for class `Foo'

class Foo
  def respond_to? *args; super; end  # “Reverting” previous redefinition

  def respond_to_missing? *args
    true
  end
end

f.method :bar  #=> #<Method: Foo#bar>

Marc-André (a Ruby core committer) has a good blog post on respond_to_missing?.

Andrew Marshall
  • 95,083
  • 20
  • 220
  • 214
  • 3
    Out of interest, what good is `respond_to?` for then. Is there a legitimate use case for it? – Brendon Muir Jul 15 '15 at 10:33
  • 4
    @BrendonMuir For redefining it? Never, really. But `respond_to?` should always be the method that’s called. You should not be calling `respond_to_missing?` directly. – Andrew Marshall Jul 15 '15 at 12:07
  • 1
    Yes, sorry that's what I meant :) Good to know :) – Brendon Muir Jul 16 '15 at 01:36
  • 1
    In my opinion `respond_to_missing?` should never return true as default. Instead, it should be something like `check_if_method_meet_condition || super` . Another thing is that it is usually defined as `respond_to_missing(method_name, include_private = false)` – Piotr Galas Feb 12 '18 at 10:20
  • 1
    @PiotrGalas If `method_missing` exists (and never raises NameError itself), then `respond_to_missing?` returning `true` always makes perfect sense. But this is just a contrived example. As for the latter point: I was lazy, and the arguments are never used here. – Andrew Marshall Feb 12 '18 at 23:36
5

It's a good practice to create respond_to_missing? if you are overriding method_missing. That way, the class will tell you the method you are calling exists, even though it's not explicitly declared.

respond_to? should probably not be overriden :)

cesartalves
  • 1,507
  • 9
  • 18