実装したいこと
- メタプログラミングRubyのP145〜146あたりの問題を実装してみました
- ざっくりとした用件は以下になります
- attr_accessor のようなアトリビュートのセッター/ゲッターを提供するメソッドに、妥当性を検査する処理を記述した任意のブロックを渡せるようにする。
- 影響範囲を限定するため、モジュールに実装してincludeしたクラスのみに適用するようにする
モジュールの実装
module CheckedAttributes
# モジュールをincludeしたクラスに、attr_checkedをクラスメソッドとして定義する
def self.included(klass)
klass.extend(SingletonMethods)
end
module SingletonMethods
def attr_checked(name, &blk)
define_method "#{name}" do
instance_variable_get("@#{name}")
end
define_method "#{name}=" do |val|
# この辺りはもう少しシュッと出来そう
if block_given? && !blk.call(val)
raise "validation error"
end
instance_variable_set("@#{name}", val)
end
end
end
end
includeして利用する側
class Sample
include CheckedAttributes
attr_checked :age do |val|
val > 30
end
end
# 確認するコード
obj = Sample.new
puts obj.age=(31)
=> 31
puts obj.inspect
=> #<Sample:0x0000000001c50480 @age=31>
puts obj.age=(30)
# paiza.io のMain.rbで実行しています
=> Main.rb:15:in `block in attr_checked': validation error (RuntimeError)
from Main.rb:44:in `<main>'
まとめ的なもの
- クラスマクロの中で、
define_method
を使った方法で実装してみました- 前章までに登場していた、
instance_variable_XXX
やdefine_method
などの理解度を確認できるいい感じの問題だなぁと感じました
- 前章までに登場していた、
- 業務でクラスマクロを作るシーンが今のところあまり思いついていないですが、Railsのコードを理解するのに役に立ちそうな予感がしています
- 本では
class_eval
を使って実装している方法など別の方法もいくつか掲載されていたようで、キャッチアップしていこうと
思います