rubyでModuleをincludeしたときに、クラスメソッドも一緒にinclude(?)してくれないものかと、試行錯誤。
クラスメソッドをincludeしたい!でも・・・
module FooModule def self.bar ... end end
というModuleがあるとする。で、
class BazClass include FooModule end
としたときに、
BazClass.bar
といったように"barメソッド"がBazClassのクラスメソッドであるかのような振る舞いをしてくれないものかと。でも、moduleでselfと書くと、それはつまりmodule自身を指すんですよね?だから、
FooModule.bar
はできても、
BazClass.bar
はできない。
self.includedで解決
それで、色々と調べた結果、以下の方法が見つかった。
module FooModule module ClassMethods def bar ... end end def self.included(receiver) receiver.extend(ClassMethods) end end
moduleがincludeされたタイミングで、include元に対してクラスメソッド用のmoduleをextendしている。extendは、
extend(module ... )
引数で指定したモジュールのインスタンスメソッドを self の特異 メソッドとして追加します。self を返します。
include は、クラス(のインスタンス)に機能を追加します が、extend は、ある特定のオブジェクトだけにモジュールの機能を追加 したいときに使用します。
ということになっているので、この場合、上記の「ある特定のオブジェクト」がinclude元のクラス自身になるという理解。結果、以下のように、include元ではさもクラスメソッドが定義されているかのような振る舞いをするようになった。
irb(main):001:0> module FooModule irb(main):002:1> module ClassMethods irb(main):003:2> def bar irb(main):004:3> print "Hello, World" irb(main):005:3> end irb(main):006:2> end irb(main):007:1> irb(main):008:1* def self.included(receiver) irb(main):009:2> receiver.extend(ClassMethods) irb(main):010:2> end irb(main):011:1> end => nil irb(main):012:0> class BazClass irb(main):013:1> include FooModule irb(main):014:1> end => BazClass irb(main):015:0> irb(main):016:0* BazClass.bar Hello,World=> nil