GGistDev

Modules and Mixins in Ruby

Modules provide namespaces and reusable behavior; mix them into classes.

Modules as namespaces

Group related constants and methods to avoid name collisions.

module MathUtil
  PI = 3.14159

  def self.circle_area(r)
    PI * r * r
  end
end

MathUtil::PI
MathUtil.circle_area(2)

Notes:

  • Use modules to organize libraries and prevent constant collisions
  • Access module methods via Module.method or Module::CONST

include, extend, prepend

  • include: adds module methods as instance methods (after the class in lookup)
  • extend: adds module methods as class (singleton) methods
  • prepend: like include but places the module before the class in the lookup chain
module Identified
  def id
    @id ||= SecureRandom.uuid
  end
end

class User
  include Identified   # id becomes an instance method
end

u = User.new
u.id

class Registry
  extend Identified    # id becomes a class method here
end

Registry.id

Method lookup order

Use ancestors to see where Ruby searches methods.

User.ancestors
# => [User, Identified, Object, Kernel, BasicObject] (with include)

prepend puts the module before the class, allowing interception and super chaining.

module Logging
  def save
    puts "saving..."
    super
  end
end

class Repo
  def save; :ok end
end

class Repo
  prepend Logging
end
Repo.new.save  # logs then calls original

module_function

Expose a method both as a module function and as a private instance method for mixin.

module Slug
  def slugify(s)
    s.downcase.gsub(/\W+/, '-')
  end
  module_function :slugify
end

Slug.slugify("Hello World")  # callable on the module

Mix in standard behavior (Comparable)

Include Comparable and define <=> to get rich comparisons for free.

class Version
  include Comparable
  attr_reader :parts
  def initialize(s) @parts = s.split('.').map!(&:to_i) end
  def <=>(other) parts <=> other.parts end
end

Version.new("1.2") < Version.new("1.10")  # => true

Hooks

React to mixins with callbacks.

module M
  def self.included(base)
    base.extend(ClassMethods)
  end
  module ClassMethods
    def enabled?; true end
  end
end
class C; include M end
C.enabled?

Summary

  • Use modules to namespace code and share behavior
  • Choose include/extend/prepend based on where methods should appear and intercept
  • module_function dual‑exposes utilities; Comparable unlocks comparisons with <=>