The following is a guest post by Kevin McNamee and originally appeared on his blog. Kevin is currently a student a The Flatiron School. You can learn more about him here, or follow him on twitter here.
Modules are similar to classes except they don’t have instances and don’t have subclasses. In ruby, modules can provide value in a wide range of uses. Modules collect related methods and constants in one singular location to share behavior across classes. Mixins allow for exactly this.
Without even writing a module, you are using mixins everyday throughout your ruby programs. You are most likely utilizing enumerables everyday. Enumerables are just modules built into ruby’s standard library. Enumerables are a set of methods that are accessable across all classes in ruby. To visualize this, let’s take a look at what we see if we check for the ancestors of the
Array class in irb:
You can see that
Enumerable is mixed in to the object hierarchy of the
Array class. The array is not a subclass of Enumerable, but rather inherits the behaviors and full set of methods from the enumerables.
To show an example, we want to create two classes: a
Movie class and a
Song class. We want each class to have similar behavior in that instances of each class can be thumbed up or thumbed down. We wouldn’t want to create a superclass in order share theses methods because we don’t want any shared properties other than the ability to be thumbed up or thumbed down. In this case, we will create a module called
Now, we can create our two classes for Movies and Songs. By including the Rankable module in both the
Movie class as well as the
Song class, we are able to augment the behavior to vote our movies and songs up and down.
Let’s now create a new movie instance and pass the
thumbs_up method. You can see by mixing in the
Rankable module, we have access to the thumbs_up method.
A similar method is accessible when we instantiate a new instance of the
Just as we looked at the ancestor hierarchy of the Array class earlier, when we check the ancestors of
Song we will see a similar output. The difference here is, instead of
Enumerable which remember is a module built into the ruby library, we will see our custom module,
Rankable between the
Movie class and
When a method is passed to an instance of the
Movie class, it will first look in the
Movie class for the behavior of that method. If the the instance does not find that method in it’s direct class, it will start going up the chain of superclasses to find the method behavior. Before checking the next direct superclass, the instance will check for a method in the direct module. If no module exists, the class instance will only then look in direct superclass. The image visualizes this action.
Mixins are great for abstracting behaviors from your classes and ensuring you do are not creating duplicate code in your programs. This is a basic overview of using modules as mixins. Modules can flex the power of your ruby code in much deeper ways including a replacement of monkey patching your code as well as namespacing. Look for more in depth posts on each of these topics in the future.