Ruby Logo

Ruby Modules & Mixins Mastery

Master Ruby modules for namespacing, mixins with include, extend, and prepend for code reuse.

Home Ruby Ruby Modules & Mixins Mastery

Ruby Modules & Mixins Mastery

Master Ruby modules for namespacing, mixins with include, extend, and prepend for code reuse and clean architecture. Learn how to avoid repetition and organize your code elegantly.

Understanding Modules

Module: A collection of methods, constants, and classes that provides two main benefits:
1. Namespacing: Group related functionality together
2. Mixins: Share code between multiple classes without inheritance

Key Differences: Modules vs Classes

  • Cannot be instantiated: No Module.new
  • Cannot inherit: No superclass/subclass relationship
  • Can be mixed in: include, extend, prepend
  • Perfect for shared behavior: DRY principle

Creating Modules

Modules are defined similar to classes but serve different purposes.

# Basic module definition
module Greetings
def say_hello
puts "Hello from the Greetings module!"
end
def say_goodbye
puts "Goodbye from the Greetings module!"
end
end
# Module with constants
module MathConstants
PI = 3.14159
E = 2.71828
GOLDEN_RATIO = 1.618
def self.circle_area(radius)
PI * radius ** 2
end
end

Include: Adding Instance Methods

include adds the module's methods as instance methods to the class.

# Module with useful methods
module Printable
def print_info
puts "Class: #{self.class}"
puts "Object ID: #{self.object_id}"
puts "Methods: #{self.methods.grep(/print/).join(', ')}"
end
def print_border(text)
border = "=" * text.length
puts border
puts text
puts border
end
end
# Including the module in classes
class Document
include Printable # Module methods become instance methods
def initialize(title, content)
@title = title
@content = content
end
def display
print_border(@title) # Method from Printable module
puts @content
end
end
class Report
include Printable # Same module, different class
def initialize(data)
@data = data
end
end
# Using included methods
doc = Document.new("My Document", "This is the content")
report = Report.new([1, 2, 3])
doc.display # Uses print_border from module
doc.print_info # Direct access to module method
report.print_info # Same module method, different object
report.print_border("REPORT DATA")

Extend: Adding Class Methods

extend adds the module's methods as class methods (singleton methods) to the class.

# Module with utility methods
module StringUtils
def titleize(text)
text.split.map(&:capitalize).join(" ")
end
def slugify(text)
text.downcase.gsub(/[^a-z0-9]/, "-").gsub(/-+/, "-").gsub(/^-|-$/, "")
end
def word_count(text)
text.split.length
end
end
# Extending a class with module methods
class Article
extend StringUtils # Module methods become class methods
def initialize(title, content)
@title = title
@content = content
end
def formatted_title
self.class.titleize(@title) # Call class method
end
def url_slug
self.class.slugify(@title)
end
end
# Using extended methods
# Call methods directly on the class
puts Article.titleize("hello world") # "Hello World"
puts Article.slugify("My Great Article!") # "my-great-article"
puts Article.word_count("This is a test") # 4
# Instance can use class methods
article = Article.new("my great article", "Content here")
puts article.formatted_title # "My Great Article"
puts article.url_slug # "my-great-article"

Prepend: Method Chain Control

prepend inserts the module earlier in the method lookup chain, allowing modules to override class methods.

# Module with enhanced behavior
module Loggable
def save
puts "[LOG] Starting save operation..."
result = super # Call the original method
puts "[LOG] Save operation completed"
result
end
end
# Class with original method
class User
prepend Loggable # Module method runs BEFORE class method
def initialize(name)
@name = name
end
def save
puts "Saving user: #{@name}"
true # Simulate successful save
end
end
# Compare with include
class Product
include Loggable # Class method runs BEFORE module method
def save
puts "Saving product"
super # This would call module method, but it won't work
end
end
# Testing prepend vs include
user = User.new("Alice")
user.save
# Output:
# [LOG] Starting save operation...
# Saving user: Alice
# [LOG] Save operation completed
# Check method lookup order
puts User.ancestors
# [User, Loggable, Object, Kernel, BasicObject] - Loggable comes first!

Method Lookup Order

  • prepend: Module → Class → Parent Classes
  • include: Class → Module → Parent Classes
  • extend: Adds methods as class methods only

Namespacing with Modules

Modules provide namespacing to organize code and avoid naming conflicts.

# Namespace modules
module Banking
class Account
def initialize(balance)
@balance = balance
end
def withdraw(amount)
@balance -= amount if amount <= @balance
end
end
class Transaction
def initialize(amount, type)
@amount = amount
@type = type
end
end
end
module Gaming
class Account # Different Account class!
def initialize(username)
@username = username
@score = 0
end
def level_up
@score += 100
end
end
end
# Using namespaced classes
bank_account = Banking::Account.new(1000)
game_account = Gaming::Account.new("player1")
bank_account.withdraw(100)
game_account.level_up
# Access constants in namespaces
module API
VERSION = "2.1.0"
BASE_URL = "https://api.example.com"
end
puts API::VERSION # "2.1.0"
puts API::BASE_URL

🚀 Interactive Practice

Interactive Code Runner

Ruby Code Editor
Output will appear here when you run the code...

🎯 Key Takeaways

  • include: Adds module methods as instance methods
  • extend: Adds module methods as class methods
  • prepend: Like include but puts module first in method lookup chain
  • Namespacing: Use :: to access nested classes and constants
  • DRY principle: Modules help avoid code duplication
  • Method lookup: Understanding ancestors chain is crucial
  • Multiple inclusion: Classes can include multiple modules

Quick Navigation

Related Topics

Video Tutorial

Watch and learn ruby modules & mixins mastery

Pro Tip: After reading through the content above, watch this video to reinforce your understanding and see the concepts in action!