こんにちは、鈴木です。
モジュールの include と extend は慣れるまではややこしいですね。
ライブラリを使用する時に、提供されているモジュールを include すれば良いのか、extend すれば良いのか迷うこともあると思います。
えぇーい、面倒くさい! ということで生まれたかどうかは知りませんが、モジュールに関する頻出パターンをご紹介します。
「モジュールが include された時に、クラスメソッドとインスタンスメソッドの両方を追加する」という手法です。
この手法を使うと、何も考えずに include すれば便利なクラスメソッドやインスタンスメソッドが使えるようになるモジュールを作ることができます。
includeされた時にクラスメソッドとインスタンスメソッドを同時に追加する頻出パターン
このような時の頻出パターンとして、以下のようなコードが書かれることが多いです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
module YourModule def self.included(base) base.extend(ClassMethods) end module ClassMethods def hello puts 'Hello!' end end def bye puts 'Bye!' end end |
YourModule を include すると、bye メソッドはインスタンスメソッドとして使えるようになります。そして、ネストしている ClassMethods モジュールで定義されている hello はクラスメソッドとして使えるようになります。
モジュールの include と extend
この動作を理解するために、モジュールの include と extend についておさらいしましょう。
例として、ログ出力機能を提供する Logging というモジュールがあるとします。
1 2 3 4 5 |
module Logging def log(message) puts message end end |
Logging モジュールを include すると、インスタンスメソッドとして log メソッドを使えるようになります。
1 2 3 4 5 6 |
class Momotaro include Logging end momotaro = Momotaro.new momotaro.log('桃から生まれた') |
Logging モジュールを extend すると、クラスメソッドとして log メソッドを使えるようになります。
1 2 3 4 5 |
class Kintaro extend Logging end Kintaro.log('マサカリを担いだ') |
include されたときに included が呼ばれる
モジュールに included メソッドを定義しておくと、モジュールが include された時に呼び出されます。
1 2 3 4 5 6 7 8 9 10 |
module Logging def self.included(base) # (2) base には Momotaro クラスが渡される end end class Momotaro # (1) Momotaro クラスが Logging を include すると include Logging end |
included の引数は include したクラスやモジュールです。
それに対して extend すれば、include されたときにクラスメソッドも同時に追加することができる、という仕組みです。
まとめ
モジュールの include と extend の動作、そして include したときに included メソッドが呼ばれることが分かれば、冒頭の頻出パターンのコードを理解することができますね。