Safely overriding method_missing in a class that already has it

Today I’m making a ridiculous module. Pretty much all it does is override method_missing. There’s a big problem with that, though. What happens when the class you’re including the module in already has method_missing, and you don’t want to mess that up? After a few failed attempts, watching stack levels get too deep, and a little head-scratching, I made this:

module Hero

  def self.included(base)
    base.class_eval do
      unless method_defined? :method_missing
        def method_missing(meth, *args, &block); super; end
      end
      alias_method :old_method_missing, :method_missing
      alias_method :method_missing, :hero_method_missing
    end
  end

  def hero_method_missing(meth, *args, &block)
    if meth.to_s == 'hero'
      "Did I ever tell you you're my #{meth}?"
    else
      old_method_missing(meth, *args, &block)
    end
  end

end

There’s my trivial example. Hero is ready to be included in any class, method_missing defined or not. It’ll handle whenever you try to call a method named hero, and pass everything else on to whatever (the class’ original method_missing, or its parent’s method_missing). Now you can ruin ActiveRecord without totally ruining ActiveRecord!

The secret is defining method_missing in the class if it isn’t already, just super, so that the double alias_method is cool.

Take a look at it in action:

mvb:~ cms$ irb
001:0> load 'hero.rb'
true
002:0> class C;def method_missing(meth);"I'm fancy!";end;end
nil
003:0> C.new.hero
"I'm fancy!"
004:0> class C; include Hero; end
C
005:0> C.new.hero
"Did I ever tell you you're my hero?"
006:0> C.new.garbage!
"I'm fancy!"

I promise the actual use is more interesting, though possibly just as useless.

RSS feed for comments on this post · TrackBack URL

Leave a Comment