Wednesday, May 24, 2006

Ruby extend and include

Module.include(module, ..) is commonly used to mix modules into classes and other modules. When a module is included the constants, methods, and module variables of the module are added to the including module or class instances.
module Actions
def left(steps)
Movement.new(self, steps)
end
end
The Actions module can be included to allow a class to generate movements.
class Car
include Actions
end
After Actions is included left can be executed by any instance of Car.
car = Car.new
movement = car.left

Similarly, Object.extend(module, ..) adds the instance methods from each module given as a parameter. However, extend adds the methods to one instance, not to all instances.
car = Car.new
car.extend Actions
movement = car.left
The above code gives car the same behavior as include would, except only the instance that called extend would have this new behavior. Therefore, the above code is valid, but this code would result in an error:
car = Car.new
car.extend Actions
car2 = Car.new
movement = car2.left #calling 'left' here is invalid because car2 does not extend Actions
extend is commonly used to mix instance methods of a module into a class.
module AttributeInitializer
def attr_init(name, klass)
eval "define_method(name) { @#{name} ||= klass.new }"
end
end

class Statement
extend AttributeInitializer

attr_init :charges, Array
end
Many DSL style class methods are added by extending a module instead of including it.

For another example of correct extend usage see Forwardable from the standard library.
Post a Comment