一部ソースコードは省略しています。
def delegate(*methods) module_eval(<<-EOS, file, line - 1) def #{method_prefix}#{method}(*args, &block) # def customer_name(*args, &block) #{to}.__send__(:#{method}, *args, &block) # client.__send__(:name, *args, &block) rescue NoMethodError # rescue NoMethodError if #{to}.nil? # if client.nil? #{exception} # # add helpful message to the exception else # else raise # raise end # end end # end EOS endこれ、メソッドの中でmodule_evalを使っているんですよね。
え、そんなことできたっけ?って感じでした。 例えば、これとか。
class Zombie def hi module_eval <<-EOS def hello_zombie puts "Hello Zombie" end EOS end end Zombie.new.himoduke_eval2.rb:7:in `hi': undefined method `module_eval' for #
class Zombie module_eval <<-EOS def hello_zombie puts "Hello Zombie" end EOS end Zombie.new.hello_zombieじゃあ、Railsではどうやってメソッドの中にmodule_evalを入れているのか?
もう一度、delegation.rbを見てみる。
class Module endなんとModuleを再オープンしていた。class Delegationではないらしい。
それをquerying.rbでrequireして使っていた。
へ〜、こうやるとメソッドの中で使えるようになるんだ〜、ってことで試してみる。
class Module def delegate(value) module_eval <<-EOS def #{value} p "hello Zombie" end EOS end end module Human delegate("hello") end class Zombie include Human end Zombie.new.helloRuby では、モジュールもオブジェクトの一つで Module クラスのインスタンスです。
なのでclass Moduleを再オープンしてdelegateを定義。 もうちょっと、確認する。
Module.methods.grep(/eval/) Module.instance_methods.grep(/eval/)実行結果
[:module_eval, :class_eval, :instance_eval]
[:module_eval, :class_eval, :instance_eval]
class Zombie end Zombie.methods.grep(/eval/) Zombie.instance_methods.grep(/eval/)実行結果
[:module_eval, :class_eval, :instance_eval]
[:instance_eval]
なるほど。つまり、インスタンスメソッドとしてmodule_evalを持っていれば、
メソッド定義の中でmodule_evalを使えるってことか。
そんなわけで納得できました。
Railsのソースコードは勉強になりますね。
0 件のコメント:
コメントを投稿