【ruby】モジュールをextendした時の動き
タイトルそのまんまです。 疑問だったのでいろいろ調べてみたのですが、メタプログラミングRubyの特異クラスのところを読んでいたらわかりました。 オブジェクトからモジュールをextendすると、そのメソッドはオブジェクトのクラスではなく特異クラスに入る。
class Object def eigenclass class << self; self; end end end class C; end module M def my_singleton_method 'obj#my_singleton_method()' end end obj = C.new obj.extend M obj.eigenclass.instance_methods.grep(/my_/) #=>[:my_singleton_method] obj.class.instance_methods.grep(/my_/) #=>[]
だから、もしオブジェクトに対してextend
する予定のモジュールに定数とか名前空間を更に定義している場合、外からは非常にアクセスしづらい。
class C C_VAL = :c end module M M_VAL = :m end obj = C.new obj.extend M obj.class::C_VAL #=> :c obj.singleton_class::M_VAL #=> :m obj.class::M_VAL #=> uninitialized constant C::M_VAL
もし2つモジュールをインクルードするとどうなるかというと…
class C; end module M; end module N; end obj = C.new obj.extend M obj.extend N obj.singleton_class.ancestors # => [M, C, Object, Kernel, BasicObject]
特異クラスで継承が行われる。