Ruby ha ereditarietà singola: una classe ha un solo genitore. I moduli aggirano il limite condividendo comportamenti tra classi diverse tramite include.

module Tracciabile
  def log(evento)
    puts "[#{Time.now}] #{self.class}: #{evento}"
  end
end

class Launch
  include Tracciabile
end

class Payload
  include Tracciabile
end

Launch.new.log("creato")   # entrambe hanno .log

Con include i metodi del modulo diventano metodi di istanza; con extend diventano metodi di classe. È il pattern dei mixin: componi comportamenti come mattoncini invece di ereditare da una super-classe gigante.

Rails ne è pieno (Comparable, Enumerable, i Concern). Un modulo per responsabilità, incluso dove serve: codice condiviso senza gerarchie fragili.