What happens when a method doesn't exist

Free preview 3 min to read

A familiar error, looked at closely

NoMethodError has shown up many times in this series: a typo, a method called on the wrong type, a name that doesn't exist on that object.

"hello".fly
# raises: NoMethodError: undefined method 'fly' for an instance of String

The instinct is to read this as "Ruby checked, fly isn't there, error." That's close, but it skips a step, and this course, the last of the nine in this series, is built on that step.

Ruby doesn't give up at once

Before raising NoMethodError, Ruby walks up the object's ancestor chain looking for a method named fly: its class, that class's superclass, any included modules, all the way up. Only when that search comes up empty does Ruby take one more step. It calls a method named method_missing on the object, passing the attempted name, :fly, along with the arguments and block of the original call. String doesn't override method_missing, so the default version, defined on BasicObject, runs, and its job is to raise NoMethodError. That's the error every earlier course has shown. It was never a special case; it was method_missing's default behavior.

Why this matters: you can override the hook

method_missing is an ordinary method, defined on BasicObject and inherited by every object in Ruby, so any class can override it like any other method. Overriding it means stepping in at that moment, right before Ruby would raise NoMethodError, and deciding that something else should happen.

class Ghost
  def method_missing(name, *args)
    "you called #{name} with #{args.inspect}, and nothing by that name exists, but I intercepted it"
  end
end

Ghost.new.anything_at_all(1, 2)
# => "you called anything_at_all with [1, 2], and nothing by that name exists, but I intercepted it"

anything_at_all was never defined. Calling it doesn't raise, because Ghost's own method_missing caught the call before Ruby's default one ran.

What this course covers

  • Overriding method_missing to handle calls to methods that were never defined.
  • respond_to_missing?, the method you must override alongside it, and why skipping it is a common mistake.
  • Calling super inside method_missing for anything you don't handle, so a typo still raises NoMethodError instead of being absorbed.
  • How this closes the nine-course Ruby OOP series, from classes to this mechanism, and what comes next.

Key takeaways

  • Before raising NoMethodError, Ruby calls method_missing on the object, passing the attempted method name, arguments and block.
  • The NoMethodError seen throughout this series was BasicObject's default method_missing running, not a separate error path.
  • Because method_missing is an ordinary inherited method, any class can override it to catch calls to methods that don't exist.
  • This course is about doing that override correctly and safely, and it closes the nine-course Ruby OOP series.
Lesson 1 of 7 · free

Keep going with lesson 2

Overriding method_missing

The method_missing signature, and one override answering a family of calls like DynamicPoint's x, y and z.

A free account also gives you the quizzes, your progress and notes, and the discussion.

Type to start searching...