Prepend v/s Include v/s Extend — Ruby
In this article, we will learn about the major differences between Prepend, Extend, and Include in Ruby, which allow us to include the module methods in different ways. We will also explore them in detail with examples and will learn about the effect on the class’s ancestral chain(in sort inheritance chain).
Include — Getting some instance methods added
Include, a keyword, which is used to get the module methods as an instance method. So let’s first see it with an example then will be getting in details:
module OrderStatus
def status_packed?
puts "Order Packed"
end
end
class Order
include OrderStatus
def status
puts "You will getting the status"
end
end
order = Order.new
order.status_packed?
=> Order Packed
Order.status_packed?
=> *** NoMethodError Exception: undefined method `status_packed?' for Order:Class
Order.ancestors
=>[Order, OrderStatus, Object, Kernel, BasicObject]
In the above example, the OrderStatus module methods had been used as instance methods for the Order class. Also, we have checked the inheritance chain using the ancestor's method. As we can see OrderStatus had been put between the Order and Object classes in the inheritance chain — Just for sake remember this.
Extend — Getting some class methods
Extend, a keyword, which is used to get the module methods as the class methods. Let’s change the above example to use extend.
module OrderStatus
def status_packed?
puts "Order Packed"
end
end
class Order
extend OrderStatus
def status
puts "You will getting the status"
end
end
order = Order.new
order.status_packed?
=> *** NoMethodError Exception: undefined method `status_packed?' for #<Order:0x000055a848df4ee0>
Order.status_packed?
=> Order Packed
Order.ancestors
=>[Order, Object, Kernel, BasicObject]
In the above example we can see when we replace the include with extend the module methods had been inherited as the class methods. Also, there had been no changes in the ancestral chain as it had not been inherited that had added the method as a singleton method(Method for a single object) to the Class(in reality to its meta-class).
Prepend — instance method again but why? 😫
Prepend, is a keyword, which is again used to get the module methods as instance methods. Let’s first change the above example and understand then we will be getting the difference between include and prepend.
module OrderStatus
def status_packed?
puts "Order Packed"
end
end
class Order
prepend OrderStatus
def status
puts "You will getting the status"
end
end
order = Order.new
order.status_packed?
=> Order Packed
Order.status_packed?
=> *** NoMethodError Exception: undefined method `status_packed?' for Order:Class
Order.ancestors
=>[OrderStatus, Order, Object, Kernel, BasicObject]
So, from the above example, Module methods had been added as instance methods same as include but there had been a major difference between them which is the inheritance chain. As we can see in the ancestor chain the OrderStatus module had been kept earlier or it had been prepend before other methods in the chain. Let’s change the above example a little bit and try to understand this.
module OrderStatus
def status
puts "Order Packed"
end
end
class Order
prepend OrderStatus
def status
puts "You will getting the status"
end
end
order = Order.new
order.status
=> Order Packed
class Order
include OrderStatus
def status
puts "You will getting the status"
end
end
order = Order.new
order.status
=> You will getting the status
From the above example, it is clear that by using the prepend we load the status method of the module earlier than the same name method in the Order class opposite of include.
Conclusion
We can see in the above image the include adding methods to the class as a simple instance method with hierarchy above the class itself but prepend the class is above the module in the Object Hierarchy. Also, extend adds class methods to the metaclass as singleton methods. If there is any further query related to this please comment will be ready to always solve it.