method_missing magic - emulating Groovy's "it" in Ruby

2 Oct, 2006

Inspired variously by:

I've cooked up a shortcut for generating simple blocks, meaning that rather than { |x| > 10 }

I can write such things as: > 10)

Disclaimer: I think this is more "cool hack" than useful tool; it's probably too much of an alien artifact to be useful in real life. And it's not generally applicable, like "it" in Groovy. And really, it's not that much more verbose to use a block. Aaaaaanyway ...

The trick is that the above is parsed as>(10)))

The "its" method creates a MessageBuffer object, which records the messages (method invocations) sent it's way:

irb(main):001:0> require 'message_buffer'
=> true
irb(main):002:0> its
=> #<MessageBuffer:0x6b40b44 @messages=[]>
irb(main):003:0> < 10
=> #<MessageBuffer:0x6b3e678 @messages=[[:name], [:length], [:<, 10]]>

Now, the "&" operator coerces it's argument to a Proc, and MessageBuffer#to_proc generates a Proc that replays all the recorded messages. Q.E.D.

The full source-code is fairly short, so I'll include it inline:

class MessageBuffer 

  instance_methods.each do |m|
    undef_method m unless m =~ /^(__|respond_to|inspect)/ 
  def initialize
    @messages = []

  def method_missing(*message)
    @messages << message        # record the message
    self                        # return self so we can keep recording
  def __replay_all_messages__(obj)
    @messages.inject(obj) do |obj, message|
  def to_proc
    proc { |x| __replay_all_messages__(x) }


def its

Update: Florian Gross suggested a better way to replay recorded messages, using inject, and I've updated the code accordingly.