Saturday, December 10, 2005

More Ruby: method_missing

It's been a while since I've shared some cool stuff you can do with Ruby-- here's a trick I've been playing with recently.

Ruby defines several hooks-- methods that it calls behind the scenes when something happens. For example, in a previous post on metaprogramming, I used 'method_added' to refer to a method before it was even defined.

Another useful hook is method_missing: This one is called whenever someone tries to call a method in your object that doesn't exist. Using this hook, we can "pretend" to accept method calls that aren't defined.

This is especially powerful when combined with object composition. Here's an example:

class SimpleCallLogger
def initialize(o)
@obj = o
end
def method_missing(methodname, *args)
puts "called: #{methodname}(#{args})"
a = @obj.send(methodname, *args)
puts "\t-> returned: #{a}"
return a
end
end

This object "intercepts" all method calls made to it, prints out a message and forwards on the method call to an internal object using the 'send' method-- without knowing anything about the object passed to it. I've used this a few times to debug some code without littering it with print statements. Try that in your static language.

Another cool application of this is caching: I'm writing an application with the Openomy APIs that I thought was going a little too slow. I made a class that I could wrap around my openomy-ruby objects and cache the results of some of the calls. Using method_missing, I did this without changing the library or worrying about the cache all over the place.

I posted the caching class, as well as a slightly modified call logger, on my new projects page. An improved version of the Contract library from my previous Ruby metaprogamming post is on there as well (which I submitted to the upcoming Ruby Cookbook). If you have questions about things that are on there, shoot me an email.

1 Comments:

At 5:34 PM, Blogger Maurits said...

Very useful! Thanks a lot!

 

Post a Comment

<< Home