Ruby Pattern: Extend through Include

Ruby modules can be mixed into a class two ways. The first way is to include the module in the class, making all methods in the module available in the class.

module BasicMath
  def add(number)
    self + number
  end
end

Fixnum.class_eval do
  include BasicMath
end

3.add 4 #=> 7

Also, a class can extend itself by using a module. (Actually, any object can use a module for extension).

module ExtendMe
  def verbal_object_id
    "my object id is #{self.object_id}"
  end
end

class Person
  extend ExtendMe
end

Person.verbal_object_id #=>  "my object id is 24339630"

However, the majority of the time modules are used with classes, they are included, not extended. Even if I am writing a module which only adds class methods (and could therefore be used with extend rather than include), I write the module like this:
module ExtendThroughInclude
  def self.included(klass)
    klass.extend ClassMethods
  end

  def instance_method
    "this is an instance of #{self.class}"
  end

  module ClassMethods
    def class_method
      "this is a method on the #{self} class"
    end
  end
end

class Person
  include ExtendThroughInclude
end

Person.new.instance_method #=> "this is an instance of Person"
Person.class_method #=> "this is a method on the Person class"

If you're unfamiliar with modules, the included method is called whenever the module is included in a class. The class the module was included in is passed as the argument.

Writing modules like this is good for consistency. This is the pattern used throughout Rails and most Ruby projects. Next time you need to have a module add a method directly on a class, make it a module that can be included.
Hi, I'm Dan Manges, a software developer best known for being the founding CTO of Braintree. Send me an email.
blog comments powered by Disqus