【Ruby】動的プログラミング3
前回の復習
method_missingとは?
→呼び出したメソッドが存在しない時に実行されるメソッド。例外が呼び出される。通常はBasicObjectクラスで実装されているがオーバーライドすることで振る舞いを変えられる。クラスの継承の中で親クラスがオーバーライドしている可能性もあるため、ある程度メソッド名を絞って実装するのがよい。
7-3 eval
なんだそれ?
→evaluate(式評価)の略。式評価で何を評価しているかというと「その式がある環境で実行された時に、どんな意味を持っているか」ということ。evalのためのメソッドには以下の様なものがある。
eval 'p self' object = Object.new # レシーバのオブジェクトをselfとして式を評価 object.instance_eval {p self} # レシーバのクラスをselfとして式を評価 object.class.class_eval {p self}
どうやって使うの?
→実行する環境によってselfが変わるため、メソッドを作るメソッドを作ることができる。あんまりピンとこないためサンプルコードを見る。
class LoggingInstanceVariable logging_instance_val_names = %w(first_val second_val third_val) logging_instance_val_names.each do |val_name| eval <<-END_OF_DEF attr_reader :#{val_name}, :before_#{val_name} def #{val_name}=(val) @before_#{val_name} = @#{val_name} @#{val_name} = val end END_OF_DEF end end obj = LoggingInstanceVariable.new obj.first_val = 1 p obj.first_val p obj.before_first_val obj.first_val = 2 p obj.first_val p obj.before_first_val
値がインスタンス変数に代入されたら、一個前の値だけ保存しておくという手続きをevalを使ってまとめたもの。
Javaだったらクラスを作ってデータをまとめて…とするのだろうけど、それじゃ過剰設計だというときに使えそう。
また、動的にメソッドの追加もできる。
class AttrClass def initialize @attr = "attr" end def add_reader(instance_val_name) eval <<-END_OF_DEF def #{instance_val_name} @#{instance_val_name} end END_OF_DEF end def add_writer(instance_val_name) eval <<-END_OF_DEF def #{instance_val_name}=(val) @#{instance_val_name} = val end END_OF_DEF end end attr_obj = AttrClass.new p attr_obj #=> attr_obj.respond_to? "attr" #=> false attr_obj.add_reader "attr" attr_obj.respond_to? "attr" #=> true p attr_obj.attr #=> attr
特異メソッドだけでなく普通のメソッドを普通のクラスに後から追加するなんてこともできてしまう。
まだなれていないためとても気持ち悪い!
class_eval、instance_eval等evalメソッドには他にも種類があるが、とりあえずとばす。