- モジュールを使うと、メソッドを共同利用できるようになる
- 複数のクラスでも、モジュールによってメソッドを共同利用できる
- クラスからモジュールをインクルードすることで
- モジュールに定義したメソッドを、あたかもそのクラス自身に定義されたメソッドとして使えるようになる
例
- ホイップクリームをトッピングするメソッドを作る
- メソッドをドリンク・ケーキのクラスで共同利用する
複数のクラスでメソッドを共同利用する手順
- モジュールを作る
- モジュールにメソッドを定義する
- モジュールのメソッドをクラスで使う
モジュールを作る
module モジュール名
end
module WhippedCream
end
モジュール名の命名 ModuleName : キャメルケース
- クラス同様に、先頭は大文字・キャメルケースでモジュール名を定義する
クラスとの違い
- 定義方法は似ているが、クラスとの違いは
- インスタンス(オブジェクト)を作ることができない
- 主にメソッドを共同利用するための部品
モジュールにメソッドを定義する
- クラス同様に
- インスタンスメソッド・クラスメソッド(正確にはモジュールメソッド)を定義できる
- インスタンス変数や引数、戻り値なども同様に使える
module AddCream
def add_cream
@name += " with cream"
end
end
モジュールのメソッドをクラスで使う
- 定義したモジュールをクラスで利用するには、
include
メソッドでモジュールを指定してインクルードする
class クラス名
include モジュール名
end
module AddCream
def add_cream
@name += " with cream"
end
end
class Drink
include AddCream # モジュールをインクルード
def initialize(name)
@name = name
end
def name
@name
end
end
drink = Drink.new("mocha")
drink.add_cream # モジュール定義のメソッドを呼び出し
p drink.name
# "mocha with cream"
モジュールを複数のクラスで共同利用する
module AddCream
def add_cream
@name += " with cream"
end
end
class Item
include AddCream
def initialize(name)
@name = name
end
def name
@name
end
end
class Drink < Item
end
class Food < Item
end
drink = Drink.new("mocha")
drink.add_cream
p drink.name
# "mocha with cream"
food = Food.new("cake")
food.add_cream
p food.name
# "cake with cream"
モジュールの使いどころ
- クラスの継承は、「親クラスから派生する子クラス」といった関係性が曖昧になると、コード全体に違和感が生じる
- モジュールの場合は上記のような関係性は気にする必要はないため、「クラスを継承することが適切でない」といった場面でも気にせず利用できる
Enumerable
モジュール
- 例)配列に対して「全要素が該当しない」ことを調べる
none?
メソッド
p [1, 2].none? {|i| i == 0} # true
p [1, 2].none? {|i| i == 1} # false
- 配列に対して使える
none?
メソッドだが、リファレンスの Array
クラスのページには記載がないEnumarable
モジュールのページに記載がある
Array
クラスは、Enumarable
モジュールをインクルードしているため、このメソッドを利用できるEnumarable
モジュールにはたくさんのメソッド群が定義されているので、他の多数のメソッドも利用できる
Hash
クラスも、Enumarable
モジュールをインクルードしているため、このメソッドを利用できる
h = {a: 1, b: 2}
p h.none? {|k, v| v == 0} # true
p h.none? {|k, v| v == 1} # false
extend
モジュールのメソッドをクラスメソッドにする
- モジュールのメソッドをクラスで
include
すると、インスタンスメソッドとして利用できる - モジュールのメソッドをクラスで
extend
すると、クラスメソッドとして利用できる
module Greeting
def hello
"Hello!"
end
end
class Shop
extend Greeting
end
p Shop.hello
# "Hello!"
extend
したモジュールのメソッドを、インスタンスメソッドで呼び出そうとするとエラーになる
shop = Shop.new
p shop.hello
# undefined method `hello' for #<Shop:0x000000010cd8c1a8> (NoMethodError)
モジュールのメソッドや定数をそのまま使う
- モジュールにクラスメソッドや定数を定義しておき、そのまま呼び出すこともできる
クラスメソッド呼び出し
module Greeting
def self.hello
"Hello!"
end
end
p Greeting.hello # "Hello!"
定数呼び出し
モジュール名::定数名
module Greeting
Default = "Hello, world."
end
p Greeting::Default # "Hello, world."
Ruby が用意しているモジュール
- 自分で定義する以外に、予め Ruby で用意されたモジュールを使うこともできる
- 例)
Math
モジュール
p Math::PI
# 3.141592653589793
名前空間
- 同じクラス名を複数の場所で使いたい
- ただ、それぞれ別のクラスのため別々に定義して呼び分けたい
class Beer
def self.info
"KIRIN beer"
end
end
class Beer
def self.info
"ASAHI beer"
end
end
p Beer.info
# "ASAHI beer"
- モジュールを使って名前を付け分けるという方法がある
module Kirin
class Beer
def self.info
"KIRIN beer"
end
end
end
module Asahi
class Beer
def self.info
"ASAHI beer"
end
end
end
p Kirin::Beer.info
# "KIRIN beer"
p Asahi::Beer.info
# "ASAHI beer"
クラス名(またはモジュール名)::クラス名(またはモジュール名)
クラスとモジュールの使い分け
- クラスとモジュールは、どちらでも同等のことができる
- インスタンスを
- 作るとき → クラスを使う
- 作らないとき → モジュールを使う
- と使い分けることで、その意図が伝わりやすい
- 上記の例のように、単に名前空間を分けることが目的ならインスタンスを作る必要がないため、モジュールを使うとよい