🙌

Module/Mix-in/include/prependについて

2023/02/21に公開

自己学習でrubyのModule(モジュール)について調べることがあったので、自分なりに学習したことをまとめました。よかったら参考にしてみてください。

Module(モジュール)

クラスと同じようにメソッドを定義することができ、処理の部分をまとめたもの。

特徴

モジュールでインスタンスを持つことはできない。

モジュールは継承することができない。

(ただし、Mix-inというモジュールで定義したメソッドをクラスに取り込み、モジュールのメソッドを取り込んだクラスのインスタンスに対して使用することができます。)

また、モジュール内のメソッドを実行するときは、メソッドをモジュール関数として外部に公開するため、module_function: メソッド名で指定し、「モジュール名.メソッド名」で実行となります。

https://qiita.com/shiopon01/items/fd6803f792398c5219cd

クラス内でモジュールを呼ぶときは「include」「prepend」メソッドを使用し、モジュールに含まれる定数やメソッドをクラス内で使用することができます。

https://www.sejuku.net/blog/16057

モジュールの使用例

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

  module_function :hello
end

module Goodbye
  def goodbye
    puts "じゃあね〜"
  end

  module_function :goodbye
end

# 実行するときは、「モジュール名.メソッド名」で実行する
Hello.hello  # => こんにちは!
Goodbye.goodbye # => じゃあね〜
module Hello
  def hello
    puts "こんにちは!"
  end
end

module Goodbye
  def goodbye
    puts "じゃあね〜"
  end
end

class Greeting
  include Hello
  include Goodbye
end

# Grretingのインスタンスを作成し、各モジュールを実行
greeting = Greeting.new
greeting.hello # => こんにちは!
greeting.goodbye # => じゃあね〜
module M
  def greeting(name)
    super
    puts "#{name}さん、おはよう!今日も良い天気ですね〜"
  end
end

module MM
  def goodbye(name)
    puts "#{name}さん、さようなら〜"
  end
end

class A
  prepend M
  include MM

  def greeting(name)
    puts "#{name}さん、こんばんは!今日は寒いですね〜"
  end
end

a = A.new
a.greeting("田中")
# =>田中さん、こんばんは!今日は寒いですね〜
# => 田中さん、おはよう!今日も良い天気ですね〜

a.goodbye("花子")
# => 花子さん、さようなら〜 

Mix-in

クラスとモジュールを混ぜ合わせることで、多重継承の代わりに用いられます。

クラス内で「include モジュール名」と記述することで、モジュールで定義したメソッドをそのクラスに対して使用することができます。

(クラスで定義したインスタンスメソッドのように使用することができます。)

module M
  def self_introduction(name, age)
    "私の名前は#{name}です。年齢は#{age}歳。拳で!!!"
  end
end

class A
  include M
end

# クラスAのインスタンスを作成
a = A.new

# モジュールMのself_introductionメソッドを実行(モジュールMを取り込むことで、モジュールMで定義したメソッドをクラスAのインスタンスメソッドのように使用することができる。)
p a.self_introduction("織田信長", 21) # => "私の名前は織田信長です。年齢は21歳。拳で!!!"

# クラスAにモジュールMが含まれているか確認
p A.include?(M) # => true

Mix-inを実現するには、includeの他にもprependメソッドもあります。

prependはすでにあるクラスの動作を変更したいときに使用します

includeとの違いは、モジュールとクラスに同じメソッド名があったときに、includeだとクラスの中にあるメソッドをよび、prependだとモジュールの中にあるメソッドを呼ぶことができます。

prepend 参考

https://docs.ruby-lang.org/ja/latest/method/Module/i/prepend.html

https://magazine.techacademy.jp/magazine/19880

includeでモジュールMをクラスAに取り込んだとき

module M
  def greeting(name)
    puts "#{name}さん、おはよう!今日も良い天気ですね〜"
  end
end

class A
  include M

  def greeting(name)
    puts "#{name}さん、こんばんは!今日は寒いですね〜"
  end
end

a = A.new
a.greeting("田中") # => 田中さん、こんばんは!今日は寒いですね〜

prependでモジュールMをクラスAに取り込んだとき

module M
  def greeting(name)
    puts "#{name}さん、おはよう!今日も良い天気ですね〜"
  end
end

class A
  prepend M

  def greeting(name)
    puts "#{name}さん、こんばんは!今日は寒いですね〜"
  end
end

a = A.new
a.greeting("田中") # => 田中さん、おはよう!今日も良い天気ですね〜

また、モジュールMの中で「super(オーバーライドしているメソッドを呼び出すもの)」を使用すると、クラスAのメソッドを呼び出すことができます。

module M
  def greeting(name)
    super
    puts "#{name}さん、おはよう!今日も良い天気ですね〜"
  end
end

class A
  prepend M

  def greeting(name)
    puts "#{name}さん、こんばんは!今日は寒いですね〜"
  end
end

a = A.new
a.greeting("田中")
# => 田中さん、こんばんは!今日は寒いですね〜
# => 田中さん、おはよう!今日も良い天気ですね〜

Discussion