導入
Ruby は「メソッドを実行時に作る」「呼ばれたメソッドが無くても対応する」といった、プログラムでプログラムを書くことができます。これをメタプログラミングと呼び、Rails の魔法のような書き心地を支えています。入口の2つ、define_method と method_missing を触ってみましょう。
説明
define_method は、メソッドを実行時に動的に定義します。似たメソッドをまとめて作れます。
class Calculator
define_method(:double) { |x| x * 2 }
define_method(:triple) { |x| x * 3 }
end
c = Calculator.new
puts c.double(5) # 10
puts c.triple(5) # 15
method_missing は、存在しないメソッドが呼ばれたときに代わりに実行されます。設定値の取得などを柔軟にさばけます。
class Config
def initialize
@data = { host: "localhost", port: 8080 }
end
def method_missing(name, *args)
@data[name] || "未設定"
end
end
c = Config.new
puts c.host # localhost(host メソッドは定義していないのに動く)
puts c.port # 8080
puts c.unknown # 未設定
メタプログラミングは強力ですが、使いすぎると「どこで定義されたか分からない」読みにくいコードにもなります。まずは仕組みを知ることが、Rails のようなライブラリの中身を理解する助けになります。
やってみよう
define_method で別の計算メソッド(例:half)を足したり、method_missing の @data を書き換えて、定義していない名前でも値が返る様子を確かめましょう。
演習
Calc クラスに define_method(:twice) で「引数を2倍して返す」メソッドを定義してください。Calc.new.twice(5) の結果を puts で表示します(10 になります)。
ヒント1を見る
define_method(:twice) { |x| x * 2 } をクラスの中に書きます。