クラスだけでは賄えない部分を担当するモジュール

モジュールはクラスだけでは賄えない部分を担当するものというイメージです。 モジュールはインスタンス化という事ができません。しかし、モジュールは他のモジュールやクラスにインクルードすることができます。

吉田先生

モジュールでは定数やメソッドを定義する事が出来ます。


モジュールとは

モジュールはクラスだけでは賄えない部分を担当するものというイメージです。クラスは〇〇(クラス).newとすることでオブジェクトを作成、つまり〇〇クラスのインスタンスを作ることができます。これをインスタンス化と呼びます。

モジュールはこのインスタンス化という事ができません。しかし、モジュールは他のモジュールやクラスにインクルードすることができます。クラスはインクルードができません。(インクルードとは何かについてはMix-inでご説明します。)また、モジュールでは定数やメソッドを定義する事が出来ます。

モジュールを作る

モジュールを作りたいときは、以下のように書きます。

module モジュール名
 定義
end

モジュール名の1文字目はアルファベット大文字でなければいけません。2文字目以降は小文字の英数が使えます。そして、例えば「FileTest」のように単語を2つ書きたいときは、単語の1文字目を大文字にします。変数などの時と異なり「_」アンダースコアで区切るのではないという事ですね。

定数

モジュールで定義した定数を参照する際は以下のよう形で書きます。

モジュール名::定数名

メソッドの定義

モジュールの中では、メソッドを定義する事が出来ます。定義したメソッドを「モジュール名.メソッド名」という書き方で呼び出したい場合は、「module_function :メソッド名」という形でモジュール内に記述します。

module Aisatsu
 def hello
  puts "こんにちは"
 end
 module_function :hello
end

Aisatsu.hello
#こんにちは

「モジュール名.メソッド名」の形で呼び出しできていることが分かりますね!

名前空間

複数人でプログラムを作っていると、メソッドやクラスの名前が重複するという事が起こってしまう可能性が出てきます。このような事が起こると、先に書いたクラスでの定義などが同じ名前で書いた定義で上書きされてしまい、エラーが出るという事になりかねません。

そういった事を回避するために名前空間というものを使います。つまり、モジュールを名前空間(衝突回避目的で)として使うというイメージです。モジュール内で書いたメソッドを参照する場合は、

モジュール名.メソッド名

という形で参照できます。

Mix-in

「include」というものを使いモジュールをクラスの中に取り込むことをMix-inといいます。(取り込む=include(インクルード)する。という言い方もされます。)クラスの継承と似た部分もあるので使い道などについて迷うこともあるかもしれませんが、以下ポイントを参考に使い分けると良いでしょう。

・複数のクラスが存在していて、それぞれのクラスが内容の近い機能を保持している。しかし、同じスーパークラスのサブクラスとはしたくない時。

・既にスーパークラスを定めている(継承)が、共通機能などをうまくまとめられない時。rubyでは2個以上スーパークラスを持てません。この事を、単純継承(単一継承)といいます。定めたスーパークラスで賄いきれなければMix-minを使うとよいという事ですね。

書き方については以下のようになります。

module モジュール名
 共通項目(メソッドなど)
end

class クラス1(クラス名)
 include モジュール名
  クラス1の為のメソッドなど
end

class クラス2(クラス名)
 include モジュール名
  クラス2の為のメソッドなど
end

このようにインクルードする事により、モジュール内に書いたメソッドはクラス1とクラス2のインスタンスメソッドとして使用できます。では、例を使い実際にコードを書いてみましょう1。

module TestModule
 def name
  "山田"
 end
end

class TestClass
 include TestModule
end

instance = TestClass.new

p instance.name
 #=> "山田" 
instance = TestClass.newで、TestClassのインスタンスを作成しています。そして、p instance.nameでインスタンスに対しTestModuleのメソッドを呼び出していますね。ちなみに、インクルードされたモジュールは仮想的なスーパークラスとなります。

上記module.rbでいうとインクルードされたTestModuleTestClassの仮想的なスーパークラスという事です。仮想的なということなので、スーパークラスではありません。あくまでも、スーパークラスのように扱われるというだけです。

継承関係について

クラスの継承関係は、以下メソッドを使えば調べる事が出来ます。

ancestors
superclass

では、実際に使うとどのような結果が出るかを、上記module.rbTestClassで試してみましょう。

p TestClass.ancestors #=> [TestClass, TestModule, Object, Kernel, BasicObject] p TestClass.superclass #=> Object 
このように、「ancestors」を使えば継承関係のクラスを全て知ることが出来ます。モジュールもスーパークラスではありませんが、仮想的なスーパークラスという事で一覧に含まれていますね。そして、「superclass」の方はモジュールは含まれず、スーパークラスであるObjectとなっています。

rubyであらかじめ用意されているEnumerableというモジュールがあります。このモジュールは、配列やハッシュなどオブジェクトの集まりのクラスで検索などを行うためのものです。自分で定義をしたクラスでこのモジュールを使いたい場合は、クラスの中でeachメソッドが使われていないといけません。

メソッドの検索

Mix-inを使用したときどのような構文かによって、メソッドの実行される順が変わります。

1.インクルード先のクラスで同名のメソッドがある時は、クラスの方のメソッドが優先されます。

module TestModule
 def foo
  "モジュール"
 end
end

class TestClass
 include TestModule
 def foo
  "クラス"
 end
end

instance = TestClass.new

p instance.foo
 #=> "クラス"

 

2.クラスに複数モジュールをインクルードした際は、最後に書いたモジュールが優先されます。

module Module1
 def foo
  "モジュール1"
 end
end

module Module2
 def foo
  "モジュール2"
 end
end

class TestClass
 include Module1
 include Module2
end

instance = TestClass.new

p instance.foo 
 #=> "モジュール2"

3.モジュールの中で他のモジュールがインクルードされている場合でも検索順は、最後に書いたもの~最初に書いたものの順です。

module Module1
 :
end

module Module2
 :
end

module Module3
 include Module1
end

class TestClass
  include Module2
  include Module3
end

p TestClass.ancestors
 #=> [TestClass, Module3, Module2, Module1, Object, Kernel, BasicObject]

*同じモジュールをクラス内で複数回インクルードしたとしても2回目以降は有効となりません。

extend

includeはクラスに追加されるものですが、この「extend」はオブジェクトに機能が追加されます。追加される際は、モジュール内のメソッドが特異メソッドとなります。このメソッドを使えばモジュールで定義した機能をオブジェクトごとに使用できるのです。では、使い方を以下例で学びましょう。

module Test
 def test(name)
   "#{self}、#{name}です"
 end
end

my_name = "私の名前は"                                                                                                                                        
my_name.extend(Test)

p my_name.test("山田")
 #=> "私の名前は、山田です"
my_name.extend(Test)my_nameにモジュールを取り込んでいます。そうすると、my_nametest(name)というメソッドが使えるようになります。この例では、「メソッド名(引数)」としていますが、不要であれば引数は指定しなくてもよいです。

クラスとMix-inについて

クラスというものは、Classクラスに属するオブジェクトです。ですので、extendをクラスに対して使う事も可能となります(クラス内にextendを記述する)

extendを使う事でモジュールに書いたメソッドはクラスメソッドとなります。したがって、以下例のように「クラス名.(モジュールで定義した)メソッド名」という形で呼び出せるようになります。
module TestModule  def test    "モジュール内で定義したメソッド"  end end class TestClass  extend TestModule end TestClass.test #=> "モジュール内で定義したメソッド"

まとめ

モジュールとはメソッドや定数を入れておくことが出来るものです。しかし、インスタンス化することは出来ません。

モジュールは名前空間として使う事が出来るのです。「include」を使用しモジュールをクラスに取り込むことを「Mix-in」といいます。

無料ビデオ講座のお知らせ

Skillhub [スキルハブ]では無料の動画講座を多数公開しています。他校だと数万円するような講座が無料で受講できます。

無料講座一覧を見る

×