Mixing in Class Methods

Credit: Phil Tomson

Problem

You want to mix class methods into a class, instead of mixing in instance methods.

Solution

The simplest way to accomplish this is to call extend on the class object, as seen in the Discussion of Recipe 9.2. Just as you can use extend to add singleton methods to an object, you can use it to add class methods to a class. But that's not always the best option. Your users may not know that your module provides or even requires some class methods, so they might not extend their class when they should. How can you make an include statement mix in class methods as well?

To begin, within your module, define a submodule called ClassMethods,[3]which contains the methods you want to mix into the class:

[3] The name ClassMethods has no special meaning within Ruby: technically, you can call your submodule whatever you want. But the Ruby community has standardized on ClassMethods as the name of this submodule, and it's used in many Ruby libraries, so you should use it too.

module MyLib module ClassMethods def class_method puts "This method was first defined in MyLib::ClassMethods" end end end

To make this code work, we must also define the included callback method within the MyLib module. This method is called every time a module is included in the class, and it's passed the class object in which our module is being included. Within the callback method, we extend that class object with our ClassMethods module, making all of its instance methods into class methods. Continuing the example:

module MyLib def self.included(receiver) puts "MyLib is being included in #{receiver}!" receiver.extend(ClassMethods) end end

Now we can include our MyLib module in a class, and get the contents of ClassMethods mixed in as genuine class methods:

class MyClass include MyLib end # MyLib is being included in MyClass! MyClass.class_method # This method was first defined in MyLib::ClassMethods

 

Discussion

Module#included is a callback method that is automatically called during the inclusion of a module into a class. The default included implementation is an empty method. In the example, MyLib overrides it to extend the class that's including the MyLib module with the contents of the MyLib::ClassMethods submodule.

The Object#extend method takes a Module object as a parameter. It mixes all the methods defined in the module into the receiving object. Since classes are themselves objects, and the singleton methods of a Class object are just its class methods, calling extend on a class object fills it up with new class methods.

See Also

Категории