Back to Blog

Get in Touch

Imbue: A Module Configuration Pattern for Ruby

By Michael Bleigh February 21, 2012 in ruby, modules, configuration, imbue

Missing

It's a very common practice in Ruby to use Module mixins to enhance the functionality of a class. In fact, one of the most powerful and useful features of the Ruby language is that it is so easy to do so. Great stuff all around.

Another common pattern, however, is to want to provide some include-time configuration when the module is mixed in. Let's imagine I'm writing an extension for ActiveRecord that creates a slug based on some field. What I want in the end might be something that looks like this:

class MyModel < ActiveRecord::Base
  slug :name
end

OK, that seems easy enough. How can I implement that? Well, there are a number of different ways. I could just re-open ActiveRecord::Base:

module ActiveRecord
  class Base
    def self.slug(field)
      # do some things here...
    end
  end
end

Ruby gives us a lot of rope to implement things in different ways. In this case, it's given us enough to hang ourselves. Opening existing classes like this is a bit dangerous, escpecially in an environment like Rails that has so much lazy loading of classes. How can we improve on this? Well, we could make our slug extension into a module:

module Sluggable
  def slug(field)
    include Sluggable::ActivatedInstanceMethods
    # do something with field
  end

  module ActivatedInstanceMethods
    # some code here...
  end
end

ActiveRecord::Base.extend Sluggable

This is a little bit better: we are encapsulating the behavior of Sluggable into its own entity rather than polluting an existing class. This still doesn't seem quite right, though: why does every ActiveRecord class need to know about this slug method? Ideally I would only modify the behavior of classes that I actually want to implement the slug behavior, not all ActiveRecord classes.

So what's next? Well, we can do something like this instead:

class MyModel < ActiveRecord::Base
  extend Sluggable

  slug :field_name
end

This works fine, but it's a little distasteful looking. Why do I need to have two lines of code in my model? Doesn't that defeat some of the purpose of trying to abstract functionality out into its own little world?

Introducing Imbue

The more I thought about this problem, the more I felt like there needed to be a more primitive implementation of this pattern within Ruby. I want to be able to include a module into a class with the knowledge that the module is going to, in some ways, reconfigure my class with optional arguments that I pass. Of course, some would argue that if we allowed the include keyword to do this we would be stripping modules of their dignity. So can we come up with perhaps a different keyword that represents the pattern of "transformative mixin"? I propose imbue. Imbue means "Inspire or permeate with a feeling or quality" which sounds pretty similar to what we're trying to accomplish here.

So how can we go about implementing this concept of "imbue"? Here's a dead-simple version of it:

class Module
  def imbue(mod, *args)
    result = include(mod)
    mod.imbued(self, *args) if mod.respond_to?(:imbued)
    result
  end
end

Well, that's pretty concise, huh? Surely 7 lines of code can't have that much effect on our problem area, can they? Here's what these 7 lines of code let us do:

module Sluggable
  def self.imbued(base, source, options = {})
    base.extend ClassMethods
    base.send :include, InstanceMethods
    # additional transformation here
  end

  module ClassMethods
    # relevant class methods
  end

  module InstanceMethods
    # activated instance methods
  end
end

class MyModel < ActiveRecord::Base
  imbue Sluggable, :field_name
end

In the end, I really like the way this looks. It's less cryptic than the hide-the-ball class method because it gives us the fully qualified module. It's more concise than the include-and-class-method strategy because it lets us pass options along with the module we want to include. It's more Rubyish than the factory pattern, giving us a simple standard method call instead of using metaprogramming to generate an anonymous module. To sum up, I really like it!

This pattern is so commonly used in Ruby that I would almost argue that something akin to imbue should be a part of the language itself. It gives you a great way to encapsulate transformative behaviors that can then be applied generically. What do you think about imbue? Would you like to see it as a gem or even part of Ruby itself? Let me know in the comments.

Medium

Michael Bleigh

Michael has been with Intridea since 2007 and works to build Intridea's portfolio of products. With many years of experience working as both a designer and a developer, Michael specializes in helping to bridge the gap between the back-end development and the front-end design of a project. Michael is a prolific member of the Ruby on Rails community, having released popular open source libraries such as OmniAuth and spoken at conferences including RailsConf and RubyConf.

More posts by Michael Bleigh

Michael Bleigh

To the troubling idea isn't about what signal you're sending to your employee...

Michael Bleigh

Node.js has a pattern that I personally enjoy: if you require a directory, it...

Michael Bleigh

Last weekend I had the opportunity to speak at RubyConf 2012 about a topic th...