Ruby is well known for its flexibility and expressive syntax. One of its powerful features is the ability to share functionality using modules. While many languages offer mixins, Ruby stands out with three key methods: include, extend, and prepend. Understanding these methods can significantly improve code reuse and clarity. Let’s explore each with examples!
include → Adds Module Methods as Instance Methods
When you use include in a class, it injects the module’s methods as instance methods of the class.
Example: Using include for instance methods
module Greet
def hello
"Hello from Greet module!"
end
end
class User
include Greet
end
user = User.new
puts user.hello # => "Hello from Greet module!"
✅ Scope: The methods from Greet become instance methods in User.
extend → Adds Module Methods as Class Methods
When you use extend in a class, it injects the module’s methods as class methods.
Example: Using extend for class methods
module Greet
def hello
"Hello from Greet module!"
end
end
class User
extend Greet
end
puts User.hello # => "Hello from Greet module!"
✅ Scope: The methods from Greet become class methods in User, instead of instance methods.
prepend → Adds Module Methods Before Instance Methods
prepend works like include, but the methods from the module take precedence over the class’s own methods.
Example: Using prepend to override instance methods
module Greet
def hello
"Hello from Greet module!"
end
end
class User
prepend Greet
def hello
"Hello from User class!"
end
end
user = User.new
puts user.hello # => "Hello from Greet module!"
✅ Scope: The methods from Greet override User‘s methods because prepend places Greet before the class in the method lookup chain.
Method Lookup Order
Understanding how Ruby resolves method calls is essential when using these techniques.
The method lookup order is as follows:
- Prepend modules (highest priority)
- Instance methods in the class itself
- Include modules
- Superclass methods
- Object, Kernel, BasicObject
To visualize this, use the ancestors method:
class User
prepend Greet
end
puts User.ancestors
# => [Greet, User, Object, Kernel, BasicObject]
How Ruby Differs from Other Languages
- Ruby is unique in dynamically modifying method resolution order (MRO) using
prepend,include, andextend. - In Python, multiple inheritance is used with
super(), butprepend-like behavior does not exist. - JavaScript relies on prototypes instead of module mixins, making Ruby’s approach cleaner and more structured.
Quick Summary
| Keyword | Injects Methods As | Works On | Takes Precedence? |
|---|---|---|---|
include | Instance methods | Instances | No |
extend | Class methods | Classes | N/A |
prepend | Instance methods | Instances | Yes (overrides class methods) |
By understanding and using include, extend, and prepend, you can make your Ruby code more modular, reusable, and expressive. Master these techniques to level up your Ruby skills!
Enjoy Ruby 🚀