The Core Rule
In Ruby modules:
includeadds module methods as instance methods.extendadds module methods as singleton methods to a specific object.
For classes, that usually means:
includeaffects instances of the class.extendaffects class-level methods.
Example 1: include
module Greeter
def greet
"hello"
end
end
class User
include Greeter
end
u = User.new
puts u.greet # => "hello"
greet becomes an instance method of User objects.
Example 2: extend
module Slugger
def slug(value)
value.downcase.gsub(" ", "-")
end
end
class Article
extend Slugger
end
puts Article.slug("Hello Ruby") # => "hello-ruby"
slug is available on the class itself.
Method Lookup and Ancestors
When you include a module in a class, Ruby inserts that module into the ancestor chain.
class User
include Greeter
end
puts User.ancestors.inspect
# [User, Greeter, Object, Kernel, BasicObject]
This explains why module methods are found during instance method lookup.
self Methods in Modules
Methods defined as def self.foo are singleton methods on the module object itself.
They are not mixed in by include.
module Naming
def self.nickname
"mod-nick"
end
def instance_name
"instance"
end
end
After include Naming, only instance_name is injected.
Common Pattern: Class Methods + Instance Methods
Use included hook to extend class methods automatically.
module Trackable
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
def track(name)
@tracked ||= []
@tracked << name
end
end
def tracked?
true
end
end
This pattern is used heavily in Rails-style DSLs.
prepend in Modern Ruby
prepend inserts module before class in lookup chain.
Use it to wrap/override behavior safely:
module Logging
def save
puts "before"
super
end
end
class Model
prepend Logging
def save
puts "save"
end
end
Output:
beforesave
Typical Mistakes
- Expecting
includeto create class methods. - Defining everything with
self.in module and then including it. - Calling
extendinsideinitializewithout clear reason. - Overusing metaprogramming for simple composition problems.
Practical Decision Guide
Use:
includefor shared instance behavior.extendfor shared class-level behavior.prependfor method decoration/interception.
Keep module responsibilities small and explicit.
Conclusion
include and extend are simple once you map them to method lookup:
- include = instance side.
- extend = object singleton side.
Understanding this model helps you read Rails internals, build cleaner DSLs, and avoid subtle metaprogramming bugs.
Comments