【一人 Ruby Advent Calendar 2017】module_function について【17日目】
一人 Ruby Advent Calendar 2017 17日目の記事になります。
#module_function
とは
#module_function
は任意のメソッドを『モジュール関数』として定義するための Module のインスタンスメソッドです。
#module_function
は以下のように module
内で使用します。
module M def mado "mado" end # 任意のインスタンスメソッドをモジュール関数として定義する module_function :mado # 以降に定義されるインスタンスメソッドを全てモジュール関数として定義する module_function def homu "homu" end def mami "mami" end end
モジュール関数とは
モジュール関数とは『モジュール内で関数を定義している』ように振る舞うメソッドになります。
例えば、以下のように『モジュールのクラスメソッド』として呼び出すことができます。
module M def mado "mado" end module_function :mado end p M.mado # => "mado"
また、include
を行うことでモジュール名を省略して直接メソッド名で呼び出すこともできます。
module M def mado "mado" end module_function :mado end # M を省略する include M p mado # => "mado" class X include M def homu mado + mado end end p X.new.homu # => "madomado"
これは module_function
がモジュールの『クラスメソッド』と『インスタンスメソッド』の両方のメソッドを定義しているためです。
ですので M.mado
とすれば『モジュールのクラスメソッド』が呼ばれ、include M
を行えば『モジュールのインスタンスメソッド』が呼び出されます。
また、この時に定義されるインスタンスメソッドは『private
メソッド』として定義されるのでレシーバを付けてメソッドを呼び出すことはできません。
module M def mado "mado" end module_function :mado end class X include M def homu # Error self.mado end end x = X.new # private なので外部からは呼び出せない p x.mado
このように基本的には include
したクラスのメソッドでのみ呼び出すことができます。
注意
module_function
は『クラスメソッド』と『インスタンスメソッド』の両方のメソッドを『定義する』メソッドになります。
そのため、module_function
化する前のインスタンスメソッドを変更しても module_function
化後のメソッドは影響されません。
module M def mado "mado" end module_function :mado # module_function 化後に処理を書き換える def mado "homu" end # module_function :mado を呼び出した時の M#mado が呼び出される p M.mado # => "mado" end
ですので、必ず最後に module_function
を呼び出してください。
module M def mado "mado" end module_function :mado # module_function 化後に処理を書き換える def mado "homu" end # module_function 化し直す module_function :mado p M.mado # => "homu" end
まとめ
- 関数のようなメソッドを定義したければ
module_function
が利用できる include
を行うことでモジュール名を省略してメソッドと直接呼び出すことが出来る- インスタンスメソッドは
private
なので呼び出しが制限される(include
したクラス外からは呼ばれない module_function
で定義したメソッドはかなり特殊なのでどのような挙動になるのか理解して使う
オブジェクトに依存せず、メソッド単体で完結するような場合は module_function
を利用して定義すると外部から扱いやすくなると思います。