環境
Ruby 2.6
はじめに
モジュールの使い方は、大きく2種類に分けることができます。
- モジュールを単体で呼び出して使う
- クラスにinclude(もしくはextend)してクラスの拡張メソッドとして使う
そして、上記1の方法しか使わない場合、上記2の方法しか使わない場合、上記1,2の両方を併用して使う場合とで、メソッドの定義の仕方が変わってきます。
そんな3種類の定義の仕方をまとめてみました。
動作確認(その1)
動作確認用に、3種類のモジュールを作成しました。
# 1のパターン
module Test_module1
def self.mod_test1
puts "#{__method__}"
end
end
# 2のパターン
module Test_module2
def mod_test2
puts "#{__method__}"
end
end
# 3のパターン
module Test_module3
def mod_test3
puts "#{__method__}"
end
module_function :mod_test3
end
モジュールを単体で呼び出して使う場合、パターン1、パターン3は問題なく動作します。
$Test_module1.mod_test1
=> mod_test1
$Test_module3.mod_test3
=> mod_test3
パターン2の場合はエラーになります。このような書き方はできません。
$Test_module2.mod_test2
=> undefined method `mod_test2' for Test_module2:Module (NoMethodError)
動作確認(その2)
上記のモジュールをクラスに取り込みました。
class Test_class
extend Test_module1
extend Test_module2
extend Test_module3
class << self
def cls_cls_test1
mod_test1
end
def cls_cls_test2
mod_test2
end
def cls_cls_test3
mod_test3
end
end
end
パターン1の場合は、クラスから呼び出して使うことはできません。呼び出そうとするとエラーになります。
$Test_class.cls_cls_test1
=> undefined local variable or method `mod_test1' for Test_class:Class (NameError)
$Test_class.mod_test1
=> undefined method `mod_test1' for Test_class:Class (NoMethodError)
パターン2の場合は問題なく動作します。
$Test_class.cls_cls_test2
=> mod_test2
$Test_class.mod_test2
=> mod_test2
パターン3の場合は、クラスの中のメソッドから、外部のモジュールを呼び出す分には問題ないが、外部のモジュールのメソッドを直接呼び出すことはできないという制限が入ります。
$Test_class.cls_cls_test3
=> mod_test3
$Test_class.mode_test3
=> private method `mod_test3' called for Test_class:Class (NoMethodError)
結論
下記のような使い分けをしましょうということになります。
-
モジュールを単体で呼び出して使うようなときでしか使わない場合は、メソッドにselfをつける。
-
クラスにinclude(もしくはextend)して、クラスの拡張メソッドとしてしか使わない場合は、selfも、module_functionもつけない。
-
モジュールを単体で呼び出して使う場とき、クラスにinclude(もしくはextend)してクラスの拡張メソッドとして使うときと、両方の使い方をする場合は、module_functionを使う。(ただし、クラス内のメソッドからしか読み込まれないという制限付き)