その他

【Ruby】モジュール動作メモ

今回はメタプログラミングを読んでいて、試しに自分のローカルで動かしてみたので、それをメモしていこうと思います。

includeとprepend

module M1
  def my_method
    'M1#my_method()'
  end
end

module M2
  def my_method
    'M2#my_method()'
  end
end

class C
  prepend M1
  include M1 # 無視される
  include M2

  def my_method
    'C#my_method'
  end
end

class D < C; end

p '-------------------'
p D.ancestors => [D, M1, C, M2, Object, Kernel, BasicObject]
p C.ancestors => [M1, C, M2, Object, Kernel, BasicObject]
p C.new.my_method => "M1#my_method()"

モジュールM1とM2をそれぞれprepend、includeしたクラスCのインスタンスからmy_methodを実行するとprependしたモジュールM1のmy_methodが呼ばれた。継承チェーンの中でprependされたメソッドはCクラスのメソッドより下にくるため、([M1, C, M2, Object, Kernel, BasicObject]) Cクラスのメソッドより先に見つかるため、M1のメソッドが呼ばれたのだ。

当然prepend M1をコメントアウトすると、Cクラスのmy_methodが呼ばれる。

# 略
class C
  prepend M1
  include M1 # 無視される
  include M2
end
# 略

p C.new.my_method => "C#my_method()"

また、同じモジュールを2回 prependまたは includeしても2回目の記述は無視される。

refine

Refinementはオープンクラスの問題点であったグローバルに適用されて、気づかぬうちにメソッドを上書きしてしまうなどの問題が発生しない。

module StringExtensions
  refine String do
    def reverse
      "esrever"
    end
  end
end

module StringStuff
  p 'my_string'.reverse
  using StringExtensions
  p 'my_string'.reverse
end

=> "gnirts_ym"
=> "esrever"

Refinementsが有効になるのはrefineブロックとusingを呼び出したところからモジュールの終わりまでである。トップレベルでusingがいる場合はファイルの終わりまで有効である。

Refinementsが有効になっている限定されたスコープの中では、オープンクラスと同じでメソッドの再定義や追加ができる。

オーバーライドしているモジュール内ではrefineは無効である。

# 先程の続き
mudule StringStuff
  p 'my_string'.reverse
end

=> "gnirts_ym"

また、少々謎ではあるが、

class MyClass
  def my_method
    p 'original my_method'
  end

  def another_method
    my_method
  end
end

module MyClassRefinements
  refine MyClass do
    def my_method
      p 'refined my_method'
    end
  end
end 

using MyClassRefinements
MyClass.new.my_method => "refined my_method"
MyClass.new.another_method => "original my_method"

using MyClassRefinementsの後にanother_methodを呼び出しているのに結果はoriginal my_methodが呼ばれている。個々の部分はメタプログラミングの説明を呼んでもよく分からなかった。

さいごに

Rubyというかプログラミングっておもしろい。コツコツやっていきます。

ABOUT ME
酒井 駿
名古屋工業大学大学院卒業後、豊田合成(株)で品質管理を経験し、その後スタートアップ・マネーフォワードを経て、2024年11月に株式会社EGGHEAD創業。 製造業とエンジニアリング、両方の現場の知見を活かし、製造業における生成AIを活用した業務改善やシステム開発を支援します。