Modules & Mixins

Reviewed & published by Brayan K

Ruby is a dynamic, beginner-friendly programming language, and modules let you both namespace your code and share behaviour across classes through mixins — Ruby's elegant alternative to multiple inheritance.

Part of the free Ruby course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.

By the end of this lesson you'll create modules, use them as namespaces, and mix shared methods into classes with include.

What You'll Learn in This Lesson

1️⃣ Modules as Namespaces and Toolboxes

A module groups related constants and methods. You can call its self. methods directly and reach inside with the :: operator. As a namespace, a module lets two libraries each define a Track without colliding.

# A module groups related methods and constants.
# Used this way, it's a NAMESPACE and a toolbox of helper methods.
module MathTools
  PI = 3.14159

  # module_function methods are called on the module itself.
  def self.circle_area(r)
    PI * r * r
  end

  def self.double(n)
    n * 2
  end
end

puts MathTools::PI               # -> 3.14159   (:: reaches into the module)
puts MathTools.circle_area(2)    # -> 12.56636
puts MathTools.double(21)        # -> 42

# Namespacing also prevents name clashes between libraries:
module Audio
  class Track; end
end
module Video
  class Track; end   # a different Track — no conflict!
end
puts Audio::Track.new.class      # -> Audio::Track

2️⃣ Mixins: Sharing Behaviour with include

The real power is the mixin. Define instance methods in a module, then include it in any class to give every instance those methods. A class can include many modules. Ruby's own Comparable mixin turns a single <=> method into a full set of comparison operators.

# A MIXIN shares instance methods with any class via "include".
module Greetable
  def greet
    "Hi, I'm #{name}"   # relies on the including class having a name method
  end
end

module Farewell
  def bye
    "Goodbye from #{name}"
  end
end

class Person
  include Greetable       # mix in greet
  include Farewell        # mix in bye  (multiple mixins are fine!)
  attr_reader :name
  def initialize(name)
    @name = name
  end
end

p = Person.new("Ada")
puts p.greet            # -> Hi, I'm Ada   (method came from the module)
puts p.bye              # -> Goodbye from Ada
puts Person.ancestors.include?(Greetable)  # -> true

# Ruby's built-in Comparable mixin gives <, >, == from one <=> method:
class Version
  include Comparable
  attr_reader :num
  def initialize(num); @num = num; end
  def <=>(other); num <=> other.num; end
end
puts (Version.new(2) > Version.new(1))   # -> true

Your turn. Give a Duck both walk and swim by mixing in two modules. Complete the TODOs, then run it.

# 🎯 YOUR TURN — replace each TODO, then run with: ruby walkable.rb

# 1) Define a module "Walkable" with a method "walk"
module Walkable
  def walk
    "#{name} is walking"   # 👉 TODO: keep using name
  end
end

# 2) Define a module "Swimmable" with a method "swim"
module Swimmable
  def swim
    "#{name} is swimming"
  end
end

# 3) Mix BOTH into a Duck class
class Duck
  include Walkable          # 👉 TODO: include Walkable
  include Swimmable         # 👉 TODO: include Swimmable
  attr_reader :name
  def initialize(name)
    @name = name
  end
end

donald = Duck.new("Donald")
puts donald.walk
puts donald.swim

# ✅ Expected output:
#    Donald is walking
#    Donald is swimming

Mini-Challenge: A Describable Mixin

Write one Describable module and share it between two unrelated classes — the essence of a mixin. Run with ruby describable.rb.

# 🎯 MINI-CHALLENGE: a Describable mixin.
# Save as describable.rb and run with: ruby describable.rb
#
# 1. Define a module Describable with a method "describe" that returns
#    "<class name>: <name>"  (hint: self.class gives the class).
# 2. Make TWO classes (e.g. Car and Bike) that each include Describable
#    and have an attr_reader :name set in initialize.
# 3. Create one of each and call describe on both.
#
# ✅ Example output:
#    Car: Tesla
#    Bike: BMX

# your code here

Common Errors (and the fix)

Pro Tips

📋 Quick Reference — Modules & Mixins

ConceptRuby Syntax
Define modulemodule Name ... end
Module methoddef self.helper
Reach insideName::PI
Mix in (instance)include Module
Mix in (class)extend Module
Lookup orderKlass.ancestors

🎉 Lesson Complete!

Practice quiz

What is a key difference between a module and a class?

  • modules are faster
  • a class cannot have methods
  • a module cannot be instantiated with .new
  • modules cannot hold constants

Answer: a module cannot be instantiated with .new. You cannot call .new on a module; modules namespace or mix in behaviour.

Which operator reaches a constant inside a module, like PI?

  • double colon, MathTools::PI
  • a dot, MathTools.PI
  • an arrow, MathTools->PI
  • a hash, MathTools#PI

Answer: double colon, MathTools::PI. Use :: to reach module constants, e.g. MathTools::PI.

What does include do?

  • adds class methods
  • creates a subclass
  • deletes methods
  • adds the module's instance methods to the class

Answer: adds the module's instance methods to the class. include mixes a module's instance methods into the class.

How many modules can a single class include?

  • zero
  • as many as you like
  • exactly one
  • exactly two

Answer: as many as you like. A class can compose many mixins via multiple include statements.

What does extend add to a class instead of include?

  • class methods
  • instance methods
  • constants
  • nothing

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

Including Comparable requires you to define which method?

  • each
  • to_s
  • <=>
  • compare

Answer: <=>. Comparable builds <, >, == and more on top of your <=> method.

Including Comparable and defining <=> gives you which methods for free?

  • map and select
  • <, >, ==, between?, clamp
  • push and pop
  • each and count

Answer: <, >, ==, between?, clamp. Comparable derives the full comparison set from <=>.

How does a mixin differ from inheritance?

  • mixins are single, inheritance is multiple
  • they are identical
  • mixins require a parent class
  • inheritance is single (one superclass); mixins can be many

Answer: inheritance is single (one superclass); mixins can be many. A class has one superclass but can include many modules.

A mixin method like greet that uses name requires that:

  • name is a global variable
  • the including class provides a name method
  • name is a constant
  • you call extend instead

Answer: the including class provides a name method. The mixin relies on the host class supplying the name method.

Which call shows the method-lookup order including mixins?

  • Klass.methods
  • Klass.parents
  • Klass.ancestors
  • Klass.lookup

Answer: Klass.ancestors. ancestors lists the lookup chain, including included modules.

Continue this course

Frequently asked questions

What's the difference between a module and a class?

A class is a blueprint you instantiate with .new to create objects. A module is not instantiated — you can't call SomeModule.new. Modules serve two purposes: as a namespace that groups related classes and constants to avoid name clashes, and as a mixin that packages methods to share across multiple classes. Think of a class as 'a kind of thing' and a module as 'a bundle of behaviour or a container of names'.

What is a mixin and how does include work?

A mixin is a module whose methods you 'mix into' a class with include. Once included, every instance of that class gains the module's instance methods as if they were defined right in the class. include Greetable means any Person can call greet. This is Ruby's answer to sharing behaviour without deep inheritance chains: a class can include many modules, composing capabilities from several sources.

How is a mixin different from inheritance?

Inheritance models an 'is-a' relationship and is single — a class has exactly one superclass. Mixins model a 'can-do' capability and are multiple — a class can include any number of modules. So a Duck might inherit from Bird (it is a bird) while mixing in Walkable and Swimmable (it can walk and swim). When you find yourself wanting to share the same behaviour across unrelated classes, a mixin is usually the cleaner tool than forcing them under a common parent.

What are Comparable and Enumerable, and why include them?

They are built-in modules that give you a lot of functionality for a little work. Include Comparable and define a single <=> method, and you instantly get <, >, ==, between?, and clamp. Include Enumerable and define each, and you get map, select, reduce, sort, and dozens more. They're the textbook example of mixins: define the one method that varies, and the module supplies all the methods built on top of it.