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.newProc.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 ... )手続きオブジェクトを実行してその結果を返します。引数はブロックの引 数にそのまま(多重代入のルールに従い)代入されます。
arityProcオブジェクトの引数の数を返します。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]