Proc

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)

イテレータに対して Proc オブジェクトを `&' を指定して 渡すとイテレータブロックのように動作しますが、厳密には以下の 違いがあります*1

# 問題なし
(1..5).each { break }

# LocalJumpError
proc = Proc.new { break }
(1..5).each(&proc)
# => break 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 ... )

ruby 1.7 feature

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]}

*1あらい 2002-02-20: 現在 1.6、1.7 共にこの制限 はありませんが、まだ流動的なようです ruby-bugs-ja:PR#98[外部]