Proc
はブロックをコンテキスト(ローカル変数のスコープやスタックフ
レーム)とともにオブジェクト化した手続きオブジェクトです。Proc
は
ローカル変数のスコープを導入しないことを除いて名前のない関数のように使
えます(ダイナミックローカル変数は Proc
ローカル
の変数として使えます)。
Proc
がローカル変数のスコープを保持していることは以下の例で
変数 var を参照できていることからわかります。
var = 1 $foo = Proc.new { var } var = 2 def foo $foo.call end p foo # => 2
Proc
を生成したメソッドからリターンしてしまった後は Proc
からの return, retry は例外
LocalJumpError を発生させます。
def foo proc { return } end foo.call # => in `call': return from proc-closure (LocalJumpError) def foo proc { retry } end foo.call # => in `call': retry from proc-closure (LocalJumpError)
ブロック付きメソッドに対して Proc
オブジェクトを `&' を指定して渡すと
呼び出しブロックのように動作しますが、厳密には以下の違いがあります
*1。
# 問題なし (1..5).each { break } # ruby 1.6.7, 1.8 で問題なし。1.6.8 では例外 proc = Proc.new { break } (1..5).each(&proc) # ruby 1.6 では、LocalJumpError # ruby 1.8 では、each 再実行 proc = Proc.new { retry } (1..5).each(&proc) #=> retry from proc-closure (LocalJumpError)
これは、Proc
オブジェクトが呼び出しブロックとして振舞う際の制限です。
Proc.new
Proc.new { ... }
ブロックをコンテキストとともにオブジェクト化して返します。
ブロックを指定しなければ、このメソッドを呼び出したメソッドがブロッ
クを伴うときに、それを Proc
オブジェクトとして生成して返しま
す。
def foo pr = Proc.new pr.call(1,2,3) end foo {|args| p args } # => [1, 2, 3]
これは以下と同じです(厳密には引数の解釈の仕方が異なります。 Proc#yield を参照してください)。
def foo yield(1,2,3) end foo {|args| p args } # => [1, 2, 3]
呼び出し元のメソッドがブロックを伴わなければ、例外 ArgumentError が発生します。
def foo Proc.new end foo # => -:2:in `new': tried to create Proc object without a block (ArgumentError) from -:2:in `foo' from -:4
Proc.new
は、Proc#initialize
が定義されていれば
オブジェクトの初期化のためにこれを呼び出します。このことを
除けば、proc と同じです。
self[arg ...]
call(arg ... )
手続きオブジェクトを実行してその結果を返します。引数はブロックの引 数にそのまま(多重代入のルールに従い)代入されます。
arity
Proc
オブジェクトの引数の数を返します。self
が引数の数
を可変長で受け取れる場合
-(最低限必要な数+1)
を返します。
binding ((<ruby 1.7 feature>))
Proc
オブジェクトが保持するコンテキストを Binding オブ
ジェクトで返します。
to_proc ((<ruby 1.7 feature>))
self
を返します。
to_s ((<ruby 1.7 feature>))
self
の文字列表現を返します。可能なら self
を生成した
ソースファイル名、行番号を含みます。
p Proc.new { true }.to_s => "#<Proc:0x0x401a880c@-:3>"
yield(arg ... )
Proc#call と同じですが、引数の数のチェックを行いません。
pr = Proc.new {|a,b,c| p [a,b,c]} pr.yield(1) #=> [1, nil, nil] pr.yield(1,2,3,4) #=> [1, 2, 3] pr.call(1) #=> wrong # of arguments (4 for 3) (ArgumentError)
これは yield と同じ動作です。
def foo yield(1) end foo {|a,b,c| p [a,b,c]}
*12002-02-20: break に関しては現在 1.6、1.7 共にこの制限はありません
が、まだ流動的なようです [ruby-bugs-ja:PR#98],
2003-03-12: [ruby-dev:19799]