はじめに

異なる関数に同じ名前をつけてしまったことはありませんか?
Rubyには「名前空間(スコープ)」の概念があり、同じスコープに同じ名前の関数があると上書きされてしまいます。
名前を変更すれば解決しますが、同じ名前をつけてしまったことに気づかないこともあります。
そうならないよう、Rubyでは「モジュール」を作ることができるようになっています。
この記事では、Ruby初心者の方向けに、モジュールとミックスインについてお伝えしていきます。

名前の衝突

トップレベル(最上位)のスコープをグローバルスコープといい、なにもしなければクラスや変数、関数などはグローバル空間に定義されます。
そのため、次のように同じ名前の関数を定義すると、名前が衝突して最後に定義した関数で上書きされてしまいます。
例:

def hello
    puts "Hello!"
end
def hello
    puts "こんにちは!"
end
hello()

この例では、同じ名前の関数を2回定義しています。
最終的に呼び出されるのは、最後に定義した関数です。
この例は短いため、すぐに名前の衝突に気づけますが、もしもっと長いプログラムだったらどうでしょうか?
このような事態を避けるため、Rubyでは「モジュール」という機能が提供されています。

モジュールに分けて定義する

モジュールは、新しい名前空間(スコープ)を作ることができます。
このため、同じファイルに同名のメソッドを定義できるのです。メソッドをグループ分けするようなイメージです。
それでは、先ほどの例をモジュールに分割してみましょう。
例:

module English
    def self.hello
        puts "Hello!"
    end
end
module Japanese
    def self.hello
        puts "こんにちは!"
    end
end

モジュールを定義するには、”moduleキーワード”を使います。モジュール名は大文字から始めましょう。
ここでは、”Englishモジュール”と”Japaneseモジュール”を定義して、それぞれに先ほどのメソッドを定義しています。
モジュール内のメソッドを使うには、次のようにします。
例:

English.hello
Japanese.hello

例のように、モジュール名を使うことで、それぞれのメソッドを呼び出すことができます。
以前学習した、クラスメソッドのようですね。
次は、モジュールに関連するミックスインについてみていきましょう。

モジュールをミックスインする

モジュールは名前空間を分けるだけではなく、「ミックスイン」という機能も提供します。
ミックスインとは、クラスにモジュールで定義されているメソッドを取り込んで拡張することです。
似たようなことはクラスの継承(サブクラス)を使ってもできますが、継承がひとつのクラスからしかできないのに対し、ミックスインは複数のモジュールを取り込めます。
両者は目的がやや異なるため、適切に使い分けることが重要です。
それでは、ミックスインの例をみてみましょう。
例:

module Util
    def class_name
        self.class.to_s
    end
end
class Animal
    include Util
end
a = Animal.new
puts a.class_name

この例では、クラス名を返すメソッドをミックスインしています。
まるでインスタンスメソッドとして定義されているかのように、自身のオブジェクトにアクセスできます。
”includeキーワード”を使うと、モジュール中のメソッドはインスタンスメソッドとして追加されます。
一方、次のように”extendキーワード”を使うと、クラスメソッドになります。
例:

module Hello
    def say
        puts "Hello, Mixin"
    end
end
class Any
    extend Hello
end
Any.say

先ほどの例とは違い、クラスメソッドになっているのが確認できますね。
用途に合わせて使い分けましょう。

便利な組み込みモジュール

Rubyには、あらかじめ便利な組み込みのモジュールがライブラリとして提供されています。
たとえば、コレクションを扱うためのメソッド群を提供する「Enumerableモジュール」や比較のための演算子を提供する「Comparableモジュール」です。
これらのモジュールを取り込むときには、クラス側で既定のメソッドを実装する必要がありますが、自前ですべてを実装するよりも遥かに簡単です。
積極的に利用してみましょう。

まとめ

モジュールの分け方とミックスインの方法がお分かりになりましたか?
適切なモジュールわけを行えば、名前の衝突を防ぐことができます。
関連する複数のメソッドをまとめることもでき、プログラムがわかりやすくなります。
また、ミックスインによるクラスの機能拡張も行うこともでき、組み込みのモジュールを使えばさらに手軽です。
ぜひ活用してみましょう。