Today I Learned

A Zero One initiative

Ruby prepend wrappers

Imagine we have some sort of object (which we don’t own) and we’d like to audit it. You could write an explicit wrapper around the object to audit it, but then you’ve got to keep in mind that you have to use this wrapper whenever you use the service.

You can add new functionality, whilst preserving the old interface and function like this:

class Foo # class we do not own
  def bar(arg)
    sleep arg
    "Running bar with #{arg}!"
  end
end

module FooWrapper
  def bar(arg)
    start_time = Time.now
    result = super
    time_taken = Time.now - start_time

    puts "bar() took more than #{time_taken} seconds" if 2 < time_taken
    result
  rescue
    "bar() failed"
  end
end

Foo.class_eval do
  prepend FooWrapper
end

Foo.new.bar 2.5
# bar() took more than 2.501257 seconds
# => "Running bar with 2.5!"

We’ve created a wrapper, opened up the class and prepended the wrapper. The wrapper adds new functionality, whilst preserving the old.

The downside to this approach is that whenever you call Foo#bar, you will get your added functionality each time. This may, or may not, be an issue depending your circumstance.

Looking for help? Each developer at Zero One has years of experience working with Ruby applications of all types and sizes. We're an active presence at Ruby conferences, and have worked on many of the web's Ruby on Rails success stories. Contact us today to talk about your Ruby project.