Ruby中,模組(Module)中可以定義變數與方法。透過適當的設計,你可以將物件之間可能共用的實作抽離至模組中,在必要時讓類別include,使得類別定義時得以精簡。
舉個例子來說,你會定義以下的球類別,並定義了一些比較大小的方法:
class Ball
    attr_reader :radius
    def initialize(radius)
        @radius = radius
    end
    def <=>(that) self.radius - that.radius end
    def <(that)  (self <=> that) < 0 end
    def <=(that) (self < that) || (self <=> that) == 0 end
    def >(that)  !(self <= that) end
    def >=(that) !(this < that) end
    def ==(that) (self <=> that) == 0 end
    
    def eql?(that)
        if self.equal?(that)
            return true
        end
        if that.is_a?(Ball)
            return self == that
        end
        return false
    end
    
    def hash
        41 * @radius
    end
    def to_s
        "Ball(#{@radius})"
    end
end
事實上,比較大小順序這件事,許多物件都會用的到,仔細觀察以上的程式碼,你會發現可抽離的共用比較方法,你可以將之重新設計為模組:
# encoding: Big5
module Comparable
    def <=>(that)
        raise RuntimeError, "必須實作 <=> 方法"
    end
    
    def <(that)  (self <=> that) < 0 end
    def <=(that) (self < that) || (self <=> that) == 0 end
    def >(that)  !(self <= that) end
    def >=(that) !(this < that) end
    def ==(that) (self <=> that) == 0 end
end
模組中除了<=>沒有實作之外,其它的方法都實作了。現在有了Comparable模組,你可以在設計球類別時更為精簡,如果你需要彼此比較的功能,則只要將Comparable模組include進來並<=>方法即可以:
class Ball
    include Comparable
    attr_reader :radius
    def initialize(radius)
        @radius = radius
    end
    def <=>(that) self.radius - that.radius end
    
    def eql?(that)
        if self.equal?(that)
            return true
        end
        if that.is_a?(Ball)
            return self == that
        end
        return false
    end
    
    def hash
        41 * @radius
    end
    def to_s
        "Ball(#{@radius})"
    end
end
將Comparable模組include至Ball類別,如此模組中定義的方法,就會成為Ball的實例方法,在Ruby中稱這樣的機制為Mix-in。
事實上,Ruby確實內建了 Comparable 模組來作比大小這種事,所以實際上你沒有撰寫上面的Comparable範例,你的Ball類別還是可以比大小,因為如此就是include內建的Comparable模組。
類似地,如果你在收集物件之後,必須迭代、取得最大物件、最小物件、排序、尋找物件等動作,不用親自撰寫,只要include內建的 Enumerable 模組就可以了。例如:
class Pond
    include Enumerable
    def initialize(list = [])
        @list = list
    end
    def <<(obj)
        @list << obj
    end
    def each
        @list.each { |obj|
            yield(obj)
        }
    end
end
pond = Pond.new([Ball.new(10), Ball.new(20)])
pond << Ball.new(5)
pond << Ball.new(15)
pond << Ball.new(10)
puts pond.include? Ball.new(5)  # true
print "#{pond.sort}\n"   # [Ball(5), Ball(10), Ball(10), Ball(15), Ball(20)]
puts "Max: #{pond.max}"  # Max: Ball(20)
puts "Min: #{pond.min}"  # Min: Ball(20)
pond.each_with_index do |ball, index|
    puts "#{index} - #{ball}"
end
將Emunerable模組include至類別之後,唯一要實作的就是each方法,實作如何逐一迭代,其餘的方法,Emunerable皆已經使用each方法為基礎實作完成,所以你可以直接呼叫使用。

