I'm a Ruby on Rails / jQuery web developer. Follow me at @sikachu

`method_missing` call stack in Ruby

November 23rd, 2010 Posted in Programming, Ruby

Just found out something cool from reading “Don’t Know Metaprogramming In Ruby?” from RubyLearning blog. Consider this code snippet:

class Person
class Student < Person
class HighSchoolStudent < Student

If you’re calling some method that’s undefined, let’s say we’re calling HighSchoolStudent#name Ruby will try to call the method in this order:

  1. HighSchoolStudent#name
  2. Student#name
  3. Person#name
  4. Object#name
  5. Kernel#name
  6. BasicObject#name
  7. HighSchoolStudent#method_missing
  8. Student#method_missing
  9. Person#method_missing
  10. Object#method_missing
  11. Kernel#method_missing
  12. BasicObject#method_missing

From this example, you can see that not explicitly define method and capture it in method_missing might not be good in terms of the performance. So, what should you do?

I think the best way to do it, if you know that this method will get called again, would be define the ‘real’ method after it gets called. That will reduce the call stack starting from the second run, resulting in faster code.

# Let say we're defining method for #*_with_id here
def method_missing(name, *args)
  super if name !~ /_with_id$/
  define_method "#{name}_with_id" do
    instance_variable_get(:id) + "-" + instance_variable_get(:name)

Hope this will make your code run faster, while still DRY.

  • Rails uses this a lot in Active Record. The attribute methods like Post.title are created in this manner.Also shouldn’t that be Object, Kernel and BasicObject instead of SimpleObject? You can get the order of classes/modules Ruby will look for by using klass.ancestors. For the above on 1.9.2 I get:ruby-1.9.2-p0 > HighSchoolStudent.ancestors => [HighSchoolStudent, Student, Person, Object, Kernel, BasicObject]

  • You’re definitely right!

    This is what happen when you write something up and forgot to consult IRB. Oops ..