You probably read about how easy it was to implement the Proxy design pattern in Ruby.
Thanks to the Ruby method_missing method, you can pass messages to underlying objects. See the previous article Local resource available in the wild, thanks to DRb for a fully described example.
But there’s one caveat, you have to be very careful when implementing your method_missing method.
Take this code for example:
def method_missing(name, *args, &block) # Get the first arg, which contain information about which underlying # object to call. id = arg[0] # Call the corresponding underlying object with the first argument removed my_underlying_objects[id].__send__(name, *args[1..-1], &block) end
If you execute this code, you’ll be stuck in an infinite loop. Why ? There’s a typo, one typo which will cause a segmentation fault. I wrote arg[0] instead of args[0].
To detect this problem before it happens, we can take advantage of the Kernel#caller method. It generates the current execution stask. Here is how we can use it to detect that the current object is calling himself:
def method_missing(name, *args, &block) # Check that we're not calling 'method_missing' recursively if caller.first.include?(__FILE__) raise "#{self.class} is calling itself -method #{name}-. Verify that you do not call a non existing method !!" end # Get the first arg, which contain information about which underlying # object to call. id = args[0] # Call the corresponding underlying object with the first argument removed my_underlying_objects[id].__send__(name, *args[1..-1], &block) end
That’s all, we just check that the caller method is not in the current file. If your method_missing code become more and more complex, especially if it includes some meta-programming tricks, you’ll feel A LOT safer!
One last thing: Kernel#caller is not what we could call a non-expensive method, you should only use it in development.
One comment
wrote on 26 September 2008
Hello Noob,
How are you?
When is the next update of your blog? I’m really interested in reading a news about Ruby and Spring.
Venkata