メタプログラミングRuby 第3章
- ブロックは定義された場所の束縛を保持する。
- 束縛とはローカル変数、インスタンス変数、selfなどの情報のこと
- スコープゲートは module class def
- class を Class.new {} にしたり、def を define_method {} にしたりすることでスコープをフラットにすることができる
- JavaやC#といった言語には、「内部スコープ」から「外部スコープ」の変数を参照できる仕組みもあるが、Rubyにはこうした可視性の入れ子構造は存在せず、スコープはきちんと区別されている。
- どこでも使えてしまうグローバル変数の代わりに、トップレベルでのみ使えるmainオブジェクトのインスタンス変数を使うやり方がある。設定を格納しておくときに使えるかな?
- ブロックからProcにするのも、procからブロックにするにも & を使う
- 「define_methodではブロックを引数に持つメソッド定義できない」ってどっかでみたけどrubyのバージョンいくつの話だったんだろう?今は普通に出来るみたいね
ブロックローカル変数
1.9ではブロックパラメータはいつでもブロックローカル。
1.upto(4) do |x;y| end
のようにすることで、ブロックパラメータでない変数 y もブロックローカル変数に出来る
lambdaとProcの違い
return
returnを使った時、lambdaはlambdaから戻る。ProcはProcを使っているスコープ(メソッド等)から戻る。
引数の数の寛容さ
lambdaのほうが厳しい。
lambdaかProcかを調べるには
1.9からlambda?メソッドが使えるようになった
proc
procは1.8だとlambdaで1.9だとProc.new><
Methodオブジェクト
- lambdaは定義されたスコープで評価されるが、Methodは属するオブジェクトのスコープで評価される。
- Method#unbindとUnboundMethod#bindを使って別のオブジェクト(同じクラスじゃないとエラー)のスコープで実行させることが出来る。使いどころわからん><
- MethodオブジェクトはMethod#to_procでProcオブジェクトに出来る。ブロックはdefine_methodでメソッドに変換できる。
クリーンルームの使い方
ブロック内でインスタンス変数を操作している場合、定義したコンテキストのインスタンス変数が操作されてしまう。それを防ぐためにクリーンルーム用のオブジェクト(この例ではObject.new)を作ってそのinstance_eval中でブロックを実行するようにしていた。
instance_exec
Ruby 1.9から追加。instance_evalにブロック引数を渡せるようにしたものらしい