Ruby Tutorials

Tutorials on Ruby specific concepts.

22

FEB
2006

Class Level Mix-ins

A question that comes up pretty often in Ruby circles was posed again today, by Xavier Noria:

#
# Is there standard idiom to add module methods to classes that mix them in?
#
# That is, I would like class C to croak:
#

module M
  def self.croak
    puts "Croak!"
  end
end

class C
  include M
  croak  # doesn't work
end

This brings up a couple of interesting points about mix-ins. Obviously, class methods are not easily added to things, but we generally want class methods so we can call them directly from the module. Here's how I deal with this issue.

First, instance methods are the way to go for anything you will be mixing in, period. With instance methods, you can inject them into a class or object. With anything else you have to start hacking. That gives us our first change:

module M
  def croak
    puts "Croak!"
  end
end

Now, we really wanted a module method, so I've made things worse. However, as I've said, we have all the choices with this setup. Let's just mix the module into it's own class!

module M
  extend self  # creates self.croak
  def croak
    puts "Croak!"
  end
end

This trick of duplicating all instance methods as module methods is quite handy. I use it in Rails to make testing helper methods trivial, for example. You basically get two interfaces for the price of one. You can call module methods or mix it into objects.

We've already seen how to fix Xavier's class using the new module, but here it is in writing:

class C
  extend M
  croak  # works fine now
end

Remember, module methods are more powerful if they are instance methods, because you then have all the easy choices. Just mix them into whatever you like, even if it is the module itself.

Comments (1)
  1. Gregory Brown
    Gregory Brown March 3rd, 2006 Reply Link

    Hmm... this now makes extend really clear to me, I've never hit a case where I absolutely needed it but plenty of places where this would have been handy if I knew how to use it.

    Thanks James!

    1. Reply (using GitHub Flavored Markdown)

      Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

      Ajax loader
Leave a Comment (using GitHub Flavored Markdown)

Comments on this blog are moderated. Spam is removed, formatting is fixed, and there's a zero tolerance policy on intolerance.

Ajax loader