Ruby の落とし穴:モジュールの特異メソッドは include 先クラスからはコールできない?


[ruby-talk:247201] Re: class << Foo; include Foo; end を読みつつ、へぇ… Ruby には module_function なんて機能(インスタンスメソッドの特異メソッド化?)があるんだ…とか軽く驚きつつ、でもこれって include Foo した Bar からは呼べないのか…と不思議に思ったのでメモ。当初、module_function が壊れているのか?と思っていたのですが、どうやらこれ、モジュールの特異メソッドの仕様なんですね。

class B; def self.hoge; "B.hoge" end end
B.hoge
=> "B.hoge"

class D < B; end
D.hoge
=> "B.hoge"
module M; def self.fuga; "M.fuga" end end
M.fuga
=> "M.fuga"

class C; include M end
C.fuga
=> NoMethodError: undefined method `fuga' for C:Class

ところで、Squeak Smalltalk のモジュールライクな多重継承機構である Traits ではどうかと調べてみると、こちらは大丈夫(私のメンタルモデルどおり)なようです。

Object subclass: #B

B class >> hoge
   ^ 'B class >> #hoge'
B hoge   "=> 'B class >> #hoge' "
B subclass: #D
D hoge   "=> 'B class >> #hoge' "
Trait named: #T

T classTrait >> fuga
   ^ 'T classTrait >> #fuga'
T fuga   "=> 'T classTrait >> #fuga' "
Object subclass: #C
   uses: T
C fuga   "=> 'T classTrait >> #fuga' "