【Ruby】define_methodについて調べました

はじめに

せっかく調べたのに忘れてしまうため、メモを残しておく。

今回は、ライブラリの挙動を確認していたところ
define_methodが書かれており、復習も兼ねて調べました。

環境

前提条件

  • irbかPryが動作すること

やり方

define_methodに関すること

実行

[1] pry(main)> class Animal
[1] pry(main)*   { cat: 'にゃー', dog: 'わん' }.each do |name, message|
[1] pry(main)*     # 動的にクラスやモジュールを定義でき、defによるメソッド定義をしなくてもよい
[1] pry(main)*     # メソッド本体はブロックで記述する
[1] pry(main)*     define_method(name) do
[1] pry(main)*       message
[1] pry(main)*     end
[1] pry(main)*   end
[1] pry(main)* end
=> {:cat=>"にゃー", :dog=>"わん"}
[2] pry(main)>
[3] pry(main)> puts Animal.new.cat
にゃー
=> nil
[4] pry(main)>
[5] pry(main)> class Animal2
[5] pry(main)*   { cat: 'にゃー', dog: 'わん' }.each do |name, message|
[5] pry(main)*     # ブロックにブロック引数を加えるとブロック引数がメソッドの引数になる
[5] pry(main)*     # ブロック引数:name
[5] pry(main)*     define_method(name) do |num|
[5] pry(main)*       message * num
[5] pry(main)*     end
[5] pry(main)*   end
[5] pry(main)* end
=> {:cat=>"にゃー", :dog=>"わん"}
[6] pry(main)>
[7] pry(main)> # メソッドの引数:2
[8] pry(main)> puts Animal2.new.dog(2)
わんわん
=> nil
[9] pry(main)> class Animal3
[9] pry(main)* end
=> nil
[10] pry(main)>
[11] pry(main)> { cat: 'にゃー', dog: 'わん' }.each do |name, message|
[11] pry(main)*   # ブロックをオブジェクトとして定義する
[11] pry(main)*   proc = Proc.new { |num| message * num }
[11] pry(main)*   # class_evalは、ブロックをクラス定義やモジュール定義の中のコードであるように実行する
[11] pry(main)*   # ブロックの戻り値がメソッドの戻り値になる
[11] pry(main)*   Animal3.class_eval { define_method(name, proc) }
[11] pry(main)* end
=> {:cat=>"にゃー", :dog=>"わん"}
[12] pry(main)>
[13] pry(main)> puts Animal3.new.cat(3)
にゃーにゃーにゃー
=> nil

まとめ

defでメソッド定義しなくてもメソッドを定義するという
初見殺しな面もありますが、メタプログラミングをする上で
扱うものの1つだと思うのでしっかり覚えておきます。

参考資料

define_method (Module) - Rubyリファレンス