Reason #162 •
June 11th, 2026
Tracking extensions via Module#extended
We've talked about tracking subclasses with Class#subclasses as well as Class#inherited this week. But it's time to step away from inheritance and look at a different approach: module extension.
Module#extended works similarly to Class#inherited, but it triggers when we extend a module:
Ruby
module MyModule
def self.extended(base)
puts "#{base} is extending #{self}"
end
def my_method
puts "Hello from MyModule!"
end
end
class MyClass
extend MyModule
end
# Output: MyClass is extending MyModule
# As a reminder, extending a module adds its methods as class methods:
MyClass.my_method
# Output: Hello from MyModule!
Now let's use it to implement the command registry in our lovely CLI example and take the opportunity to provide DSL-like methods for setting the description and usage of our commands:
Ruby
module Command
@commands = {}
def self.commands = @commands
def self.extended(base)
@commands[base.name.downcase] = base
end
def description(description = nil)
description ? @description = description : @description
end
def usage(usage = nil)
usage ? @usage = usage : @usage
end
def call(*args)
raise NotImplementedError, "Commands must implement the call method"
end
end
module Greet
extend Command
description "Greet someone"
usage "cli.rb greet <name>"
def self.call(name)
puts "Hello, #{name}!"
end
end
module Add
extend Command
description "Add two numbers"
usage "cli.rb add <x> <y>"
def self.call(x, y)
puts x.to_i + y.to_i
end
end
help = ARGV.delete("--help")
if ARGV.empty?
puts "Usage: cli.rb <command> [--help] [args...]"
puts
puts "Available commands:"
Command.commands.keys.sort.each do |name|
puts " #{name}"
end
exit
end
command_name = ARGV.shift
command = Command.commands[command_name]
abort "ERROR: Unknown command - #{command_name}" unless command
if help
puts "Command: #{command_name}"
puts command.description
puts "Usage: #{command.usage}"
exit
end
command.call(*ARGV)
Isn't it neat how description and usage now have that declarative feel to them?
Let's see if it works:
$ ruby cli.rb
Usage: cli.rb <command> [--help] [args...]
Available commands:
add
greet
$ ruby cli.rb greet --help
Command: greet
Greet someone
Usage: cli.rb greet <name>
$ ruby cli.rb greet Alice
Hello, Alice!
Like a charm!
History
Module#extended arrived in Ruby 1.8.1, released on Christmas 2003, one point release after the related hook Module#included.