🎓 A1Learner
🔍
0 of 28 lessons completed

Ruby Respond to Missing

The intermediate course answered unknown calls with method_missing. This lesson makes existence checks agree with that fallback, so a program can trust the answer it gets.

A fallback that respond_to? misses

Announcer answers cheer through method_missing. The respond_to? line still says false, because nothing told it about the fallback.

class Announcer
  def method_missing(name, *args)
    if name == :cheer
      puts "Cheer called"
    else
      super
    end
  end
end
announcer = Announcer.new
announcer.cheer
puts announcer.respond_to?(:cheer)

respond_to_missing? makes it honest

respond_to_missing? answers true for cheer and passes every other name to super. respond_to? now matches what the fallback can do.

class Announcer
  def method_missing(name, *args)
    if name == :cheer
      puts "Cheer called"
    else
      super
    end
  end
  def respond_to_missing?(name, include_private = false)
    name == :cheer || super
  end
end
announcer = Announcer.new
puts announcer.respond_to?(:cheer)
puts announcer.respond_to?(:sing)

method builds a real Method

method asks for cheer and gets a Method object back. Calling that object runs the fallback, and its class prints as Method.

class Announcer
  def method_missing(name, *args)
    if name == :cheer
      puts "Cheer called"
    else
      super
    end
  end
  def respond_to_missing?(name, include_private = false)
    name == :cheer || super
  end
end
announcer = Announcer.new
action = announcer.method(:cheer)
action.call
puts action.class

Example

class Greeter
  def method_missing(name, *args)
    if name.to_s.start_with?("hello_")
      language = name.to_s.sub("hello_", "")
      puts "Hello in #{language}"
    else
      super
    end
  end
  def respond_to_missing?(name, include_private = false)
    name.to_s.start_with?("hello_") || super
  end
end
greeter = Greeter.new
puts greeter.respond_to?(:hello_french)
puts greeter.respond_to?(:goodbye_french)
greeter.hello_french
action = greeter.method(:hello_spanish)
action.call

Key points

  • method_missing can answer a call that respond_to? still reports as missing.
  • respond_to_missing? tells respond_to? which fallback names are real.
  • A name the fallback handles answers true from respond_to?.
  • A name the fallback rejects still answers false from respond_to?.
  • method builds a real Method object for a name the fallback handles.
  • Calling that Method object runs the fallback with the stored name.

In this example, Greeter answers any name that starts with hello_ through method_missing. respond_to_missing? uses the same check, so respond_to? agrees with the fallback. method builds a Method for hello_spanish, and calling it greets in spanish.

Note

respond_to_missing? receives the name and an include_private flag.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

What does respond_to_missing? do for a class with method_missing?