maeshimaの日記

メモ書きです

メタプログラミングRuby 第3章

  • ブロックは定義された場所の束縛を保持する。
    • 束縛とはローカル変数、インスタンス変数、selfなどの情報のこと
  • スコープゲートは module class def
    • class を Class.new {} にしたり、def を define_method {} にしたりすることでスコープをフラットにすることができる
  • JavaC#といった言語には、「内部スコープ」から「外部スコープ」の変数を参照できる仕組みもあるが、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にブロック引数を渡せるようにしたものらしい