【Rails】モジュールとは一体なにか

rails

今回はRubyに出てくるモジュールを取り上げたいと思います。

Rubyリファレンスマニュアル」によるとモジュールとは

”Rubyのオブジェクトで”ちょっと特殊でクラスではない。しかし機能は同じ。”

とのこと。この説明だけだとよくわからないのでモジュールの特徴、使用方法、役割などを調べまとめてみました。

モジュールとは

クラスがデータと処理を一つにまとめたものであるのに対しモジュールは処理のみをまとめたものになります。この機能によって柔軟にコードを書くことができます。

モジュールとクラスの違い

モジュールとクラスでは以下2点の違いがあるようです。

  • モジュールはインスタンスを持てない
  • モジュールは継承ができない

モジュールはインスタンスを持てない

モジュールはクラスと違ってインスタンスを持つことができません。モジュールにメソッドは定義できてもインスタンスを持ち、それを呼び出すことはできません。

しかしmodule_functionメソッドを使って、メソッドをモジュール関数にすることで呼び出すことができるようになります。

module Greeting
 def hello 
  puts 'Hello' 
 end 
 module_function :hello
end 
Greeting.hello #=> "Hello"

モジュールは継承ができない

モジュールはクラスとは違い他からの継承ができません。

しかしモジュールをクラスに組み込むことでクラスは多重継承が実現できます。これについては後で詳しく説明したいと思います。

モジュールができること3つ

そしてモジュールができることを以下の3つにまとめてみました。

  • 定数やメソッドをまとめる
  • クラスに組み込んで多重継承を実現する
  • 名前空間を提供する

定数やメソッドをまとめる

モジュールはクラスと同様にメソッドや定数をまとめることができます。

定数

モジュール内で定義した定数は、モジュール名を経由して呼び出すことができます。

module Greeting 
 Version="2.3.0"
end

Greeting::Version #=> "2.3.0"

インスタンスメソッド

先ほども出てきましたが、モジュールはインスタンスメソッドを定義できても呼び出すことはできません。しかしながらmodule_functionメソッドを使って、メソッドをモジュール関数にすることで呼び出すことができるようになります。

module Greeting
 def hello
  puts 'Hello'
 end
 module_function :hello
end
Greeting.hello #=> "Hello"
module Greeting
 def hello
  puts 'Hello'
 end
end
Greeting.hello 

#=>undefined method `hello' for Greeting:Module

クラスメソッド

モジュール内で定義されたクラスメソッドはクラス同様にモジュールから直接呼び出すことができます。ただしincludeやextendメソッドで拡張したクラスからは呼び出しができません。

module Greeting
 def self.hello
  puts 'Hello'
 end
end

Greeting.hello #=> "Hello"

クラスに組み込んで多重継承を実現する

クラスは単一継承ですが、クラスにモジュールを組み込むことによって多重継承にすることができます。組み込む方法はクラスにinclude、extendメソッドを加えることにより実現できます。これをMix-inといいます。

Mix-inは似たようなクラスを持っているが違う種類のクラスに対して共有のメソッドを提供したい場合などに使用します。これによりクラスの肥大化を防ぐことにも一役を買ってくれます。

ただしモジュール関数、クラスメソッドは組み込むことができません。

includeメソッド

includeメソッドは対象のクラスでincludeしたモジュールのメソッドがインスタンスメソッドとして組み込まれるようにするものになります。

module Greeting
 def hello
  puts 'Hello'
 end
end

class Ins
 include Greeting
end

ins = Ins.new
ins.hello #=> "Hello"

extendメソッド

extendメソッドは対象のクラスでextendしたモジュールのメソッドがクラスメソッドとして組み込まれるようにするものになります。

module Greeting
 def hello
  puts 'Hello'
 end
end

class Ins
 extend Greeting
end

Ins.hello #=> "Hello"

名前空間を提供する

名前空間とは

簡単にいうと名前空間とはメソッドや変数を管理する範囲のことです。

私たちの実生活でも同姓同名の人がいたら混乱してしまいますが、それぞれの出身や所属などの個々の情報が分かれば混乱することはありません。

それと同様にメソッドや変数の名前が同じであった場合に衝突しないように、「どこに属するメソッドもしくは変数なのか」というのを明記する仕組みが名前空間となります。

そして名前空間は「 :: 」←こちらの記号を使うことができます。

A::B、これはAに属するBを呼び出すという意味になります。

名前空間とMix-in

モジュールを重ねることでMix-inに使うモジュールを名前空間内に提供することができます。

module Name #名前空間としてのモジュール
 module Greeting #Mix-inとしてのモジュール
 def hello
  puts 'Hello'
 end
 end
end

class Ins #Mix-in
 extend Name::Greeting  #Nameモジュールに属するGreetingモジュールを呼び出すという意味
end

Ins.hello #=> "Hello"

最後に

モジュールはコードを読みやすくして再利用を可能にしてくれます。

これでRubyリファレンスに書かれている”ちょっと特殊でクラスではない。しかし機能は同じ。”

の意味が少しばかり分かった気がします。

 

参考:RubyのModuleの使い方とはいったい

Rubyのmodule(モジュール)の使い方を現役エンジニアが解説【初心者向け】

【Ruby/namespace】Rubyでよく見る「:: ←これ」を深ぼる

 

コメント