attr_accessorの仕組み
おまじない的に使っていたattr_accessor。
てっきり、予約語かなんかの類だと思っていたけど、Rubyの理解が進むにつれて、attr_accessorもメソッドなのだろうかと思ってきた。
ネットで検索しても、誰も触れていないって事はもはや暗黙の了解?と思ったけど、気になるものはしょうがないので、メソッドとして実現できるか調べてみる。
最初に
attr_accessorを使うソース
class Hello attr_accessor :msg end hello = Hello.new hello.msg = "Hello world" p hello.msg #=> "Hello world" p hello.methods #=>メソッドの一覧
メソッドの一覧の中に
["msg=" ,"msg" ,...]
があるので、これがそのままメソッド名だろうと言うことで、attr_accessorを使わないソースを書いてみた。
class Hello @msg def msg @msg end def msg=(msg) @msg = msg end end hello = Hello.new hello.msg = "Hello world" p hello.msg #=> "Hello world" p hello.methods #=>メソッドの一覧
後はこれをうまいことやれば、いいわけだ。
メソッドでメソッドを定義する
http://www.ruby-lang.org/ja/man/を片っ端から読んで、それっぽいのを探したところ、組み込み関数evalに
eval(expr[, binding[, fname[, lineno=1]]])
文字列 expr を Ruby プログラムとして評価してその結果を返します。第2引数に Proc オブジェクトまたは Binding オブジェクトを与えた場合、そのオブジェクトを生成したコンテキストで文字列を評価します。binding も参照してください。
メソッドの定義まではさすがにできないだろうと思ったものの、他にそれっぽいのが見つからなかったのでとりあえず書き換えてみる。
def who (val) eval("def #{val} ;@#{val} end") #getterの定義 eval("def #{val}=(#{val}) ;@#{val} = #{val} end") #setterの定義 end class Hello who :msg end hello = Hello.new hello.msg = "Hello World" p hello.msg #=> "Hello world" p hello.methods #=> メソッドの一覧
意外にも成功。
意外にと思ってる時点で、まだRubyの理解が足りてないってことか?
実際はどうなってるかは、わかんないけどできることがわかったので十分。
まぁ、とりあえず、Rubyが面白くなってきた。