Recently I started working through EdgeCase’s Ruby Koans project as a way to become familiar with the Ruby language. The Koans are a set of unit tests that you need to make pass in order to move on to the next step. In making them pass, you learn about the syntax of the Ruby language as well as some of the commonly used libraries.

To get started, follow the instructions on the Koan’s project page on github. When working through them, keep in mind that it’s not a race. Take your time to really understand what each exercise is meant to teach you.

If you’d like a little help getting started with the Koans, one of the author’s, Jim Weirich, will be helping folks at the next Cleveland Ruby user group meeting. Jim is a leader in the Ruby community (active contributor to both Rake and RubyGems) as well as a phenomenal teacher. If you have the evening free, I’d really recommend coming to hear him talk! And in addition to the awesome upcoming CleRb session with Jim Weirich, one of the local .Net SIGs will be featuring Michael Letterle later in the month who will be speaking on IronRuby. Looking forward to both of these events!

In one of the more challenging exercises, you’re asked to build an object proxy that you can wrap around another object to intercept and track method calls made to the underlying object. Below is the solution I came up with (you may want to quit reading if you plan on doing the exercises yourself!). I’m not sure it’s the most elegant solution but it did get the tests passing!

class Proxy
  def initialize(target_object)
    @object = target_object
    @message_log = {}
  end

  def method_missing(method_name, *args, &block)
    if @object.respond_to?(method_name)
      @message_log[method_name] = number_of_times_called(method_name) + 1
      @object.send(method_name, *args, &block)
    else
      super(method_name, *args, &block)
    end
  end

  def messages
    @message_log.keys.reverse
  end

  def called?(method_name)
    @message_log.key?(method_name)
  end

  def number_of_times_called(method_name)
    @message_log[method_name] || 0
  end
end
DotNetKicks Image