Montag, 13. Mai 2013

method_missing, baby!

Meta programming in Ruby is a pleasure. And there are a lot of reasons for. One is method_missing.
A famous example of its "magic" is ActiveRecord and the dynamic finders in Ruby On Rails (active _record/dynamic_matchers.rb).
The approach is simple. Every time an object method was called, which is not defined, (or better a receiver gets an unknown message), Delegator#method_missing cares about it. You can overwrite method_missing in your class. And that's the hook that can be used for dynamics. And it IS used widely.
I demonstrate how to, in a very simple example.
The story is: I want people to move in different ways:
class Person
private
  def method_missing method_name, *args
    if %w(runs walks goes drives).include?(method_name.to_s)
      move method_name
    else
      super
    end
  end

  def move kind
    puts "#{self.class} #{kind}."
  end
end
There is no public method defined in the class "Person". It looks like no person can move in any way. But:
Person.new.runs
returns:
Person runs.
So what happened?
A new person object was instanciated and an message ("runs") was sent to it. Simply because the message is not defined, method_missing is sent instead. Please read the overwritten Person#method_missing carefully. If the message ("runs") is one of "runs", "walks", "goes" or "drives" the private method Person#move is sent internally. That's all. And that's why:
person = Person.new
person.walks
person.drives
returns:
Person walks.
Person drives.
And that's also why:
Person.new.swims
still calls the super method_missing:
undefined method 'swims' for # (NoMethodError)
Method missing, baby!

Supported by Ruby 1.9.3

Keine Kommentare:

Kommentar veröffentlichen