このマニュアルは既にメンテナンスが終了したバージョンの Ruby を対象としています。 最新版のマニュアルへ

Ruby 3.0 リファレンスマニュアル

class Proc

[edit]

要約

ブロックをコンテキスト(ローカル変数のスコープやスタックフレーム)とともにオブジェクト化した手続きオブジェクトです。

Proc は ローカル変数のスコープを導入しないことを除いて名前のない関数のように使えます。ダイナミックローカル変数は Proc ローカルの変数として使えます。

Proc がローカル変数のスコープを保持していることは以下の例で変数 var を参照できていることからわかります。

var = 1
$foo = Proc.new { var }
var = 2

def foo
  $foo.call
end

p foo       # => 2

Proc オブジェクトの生成

Proc オブジェクトを生成する手段には、主に以下の四つがあります。

* Proc.new * Kernel.#proc * Kernel.#lambda * ->(){ } (-> を使った lambda の短縮記法)

このうち Proc.newKernel.#proc は同じ性質の Proc オブジェクトを生成し、 Kernel.#lambda->(){ } も互いに同じ性質の Proc オブジェクトを生成しますが、前二者と後二者では、生成される Proc オブジェクトの引数の扱いや return・break の挙動などが異なります(詳細は後述)。生成された Proc オブジェクトが後二者 (lambda)に該当するかどうかは Proc#lambda? で調べることができます。

このほか、メソッド呼び出しにブロックを渡した場合、そのブロックをブロック引数 (&block など)で受け取ると Proc オブジェクトが生成されます。

手続きを中断して値を返す

手続きオブジェクトを中断して、呼出し元(呼び出しブロックでは yield、それ以外では Proc#call) へジャンプし値を返すには next を使います。break や return ではありません。

def foo
  f = Proc.new{
    next 1
    2              # この行に到達することはない
  }
end

p foo().call       # => 1

Proc オブジェクトをブロック付きメソッド呼び出しに使う

ブロック付きメソッドに対して Proc オブジェクトを `&` を指定して渡すと呼び出しブロックのように動作します。しかし、厳密には以下の違いがあります。これらは、Proc オブジェクトが呼び出しブロックとして振舞う際の制限です。

問題なし
(1..5).each { break }
LocalJumpError が発生します。
pr = Proc.new { break }
(1..5).each(&pr)

lambda と proc と Proc.new とイテレータの違い

Kernel.#lambdaProc.new はどちらも Proc クラスのインスタンス(手続きオブジェクト)を生成しますが、生成された手続きオブジェクトはいくつかの場面で挙動が異なります。 lambda の生成する手続きオブジェクトのほうがよりメソッドに近い働きをするように設計されています。

Kernel.#proc は Proc.new と同じになります。引数に & を付けることで手続きオブジェクト化したブロックは、Proc.new で生成されたそれと同じように振る舞います。

引数の扱い

lambda のほうがより厳密です。引数の数が違っていると(メソッドのように)エラーになります。 Proc.new は引数を多重代入に近い扱い方をします。

Proc.new は引数の数が違っていてもエラーにならない
b = Proc.new{|a,b,c|
  p a,b,c
}
p b.call(2, 4)
# => 2
    4
    nil
lambda は引数の数が違うとエラーになる
b = lambda{|a,b,c|
  p a,b,c
}
p b.call(2, 4)
# => wrong number of arguments (given 2, expected 3)

メソッド呼び出し/ブロックパラメータの挙動 も参照してください。

ジャンプ構文の挙動の違い

return と break は、lambda と Proc.new では挙動が異なります。例えば return を行った場合、lambda では手続きオブジェクト自身を抜けますが、 Proc.new では手続きオブジェクトを囲むメソッドを抜けます。

def test_proc
  f = Proc.new { return :from_proc }
  f.call
  return :from_method
end

def test_lambda
  f = lambda { return :from_lambda }
  f.call
  return :from_method
end

def test_block
  tap { return :from_block }
  return :from_method
end

p test_proc()   # => :from_proc
p test_lambda() # => :from_method
p test_block()  # => :from_block

以下の表は、手続きオブジェクトの実行を上の例と同じように、手続きオブジェクトが定義されたのと同じメソッド内で行った場合の結果です。

               return                          next                        break
Proc.new   メソッドを抜ける            手続きオブジェクトを抜ける   例外が発生する
proc       メソッドを抜ける            手続きオブジェクトを抜ける   例外が発生する
lambda     手続きオブジェクトを抜ける  手続きオブジェクトを抜ける   手続きオブジェクトを抜ける
イテレータ メソッドを抜ける            手続きオブジェクトを抜ける   手続きオブジェクトを抜ける

orphan な手続きオブジェクトの挙動

Proc(lambda を除く)を生成したメソッド呼び出しが終了した後で、その手続きオブジェクトに対して return を実行すると、戻る先のメソッド呼び出しがすでに存在しないため、例外 LocalJumpError が発生します。

break の場合は条件がやや異なります。その手続きオブジェクトをブロックとして受け取ったメソッド呼び出しがすでに終了している場合に加えて、 Proc.new { break }.call のようにブロックとしてメソッドに渡されていない手続きオブジェクトで break を実行した場合にも、脱出先となるメソッド呼び出しが存在しないため例外 LocalJumpError が発生します。

ここでいう「作成元が終了している」とは、生成元のコード上の位置(レキシカルスコープ)が失われるという意味ではありません。同じメソッドを複数回呼び出した場合、それぞれの呼び出しで生成された手続きオブジェクトは、呼び出しごとに独立してこの状態になります。

ただし、上でも説明した通り lambda で生成した手続きオブジェクトはメソッドと同じように振る舞うことを意図されているため、例外 LocalJumpError は発生しません。

def foo
  Proc.new { return }
end

foo.call
# => in `block in foo': unexpected return (LocalJumpError)

以下の表は、手続きオブジェクトの実行を上の例と同じように、手続きオブジェクトが定義されたメソッドを脱出してから行った場合の結果です。

               return                          next                        break
Proc.new   例外が発生する              手続きオブジェクトを抜ける   例外が発生する
proc       例外が発生する              手続きオブジェクトを抜ける   例外が発生する
lambda     手続きオブジェクトを抜ける  手続きオブジェクトを抜ける   手続きオブジェクトを抜ける

目次

特異メソッド
インスタンスメソッド

特異メソッド

new { ... } -> Proc[permalink][rdoc][edit]

ブロックをコンテキストとともにオブジェクト化して返します。

[EXCEPTION] ArgumentError:
ブロックを省略した呼び出しを行ったときに発生します。
pr = Proc.new {|arg| p arg }
pr.call(1) # => 1
Proc.new # => -e:1:in `new': tried to create Proc object without a block (ArgumentError)

Proc.new は、Proc#initialize が定義されていればオブジェクトの初期化のためにこれを呼び出します。このことを除けば、Kernel.#proc と同じです。

インスタンスメソッド

self << callable -> ProcRuby 2.6.0 から[permalink][rdoc][edit]

self と引数を合成した Proc を返します。

戻り値の Proc は可変長の引数を受け取ります。戻り値の Proc を呼び出すと、まず受け取った引数を callable に渡して呼び出し、その戻り値を self に渡して呼び出した結果を返します。

Proc#>> とは呼び出しの順序が逆になります。

[PARAM] callable:
Proc、Method、もしくは任意の call メソッドを持ったオブジェクト。
f = proc { |x| x * x }
g = proc { |x| x + x }

# (3 + 3) * (3 + 3)
p (f << g).call(3) # => 36
call を定義したオブジェクトを渡す例
class WordScanner
  def self.call(str)
    str.scan(/\w+/)
  end
end

File.write('testfile', <<~TEXT)
  Hello, World!
  Hello, Ruby!
TEXT

pipeline = proc { |data| puts "word count: #{data.size}" } << WordScanner << File.method(:read)
pipeline.call('testfile') # => word count: 4

[SEE_ALSO] Method#<<, Method#>>

self[*arg] -> ()[permalink][rdoc][edit]
call(*arg) -> ()
self === *arg -> ()
yield(*arg) -> ()Ruby 1.9.3 から

手続きオブジェクトを実行してその結果を返します。

引数の渡され方はオブジェクトの生成方法によって異なります。詳しくは Proc#lambda? を参照してください。

「===」は when の所に手続きを渡せるようにするためのものです。

def sign(n)
  case n
  when lambda{|n| n > 0} then 1
  when lambda{|n| n < 0} then -1
  else 0
  end
end

p sign(-4) # => -1
p sign(0)  # => 0
p sign(7)  # => 1

また、以下のような syntactic sugar もあります。

fib = lambda{|n|
  case n
  when 0 then 0
  when 1 then 1
  else
    fib.(n - 2) + fib.(n - 1)
  end
}
p fib.(10) # => 55
[PARAM] arg:
手続きオブジェクトに与える引数を指定します。
[EXCEPTION] LocalJumpError:
Procを生成したメソッドからリターンしてしまった場合に発生します。
self >> callable -> ProcRuby 2.6.0 から[permalink][rdoc][edit]

self と引数を合成した Proc を返します。

戻り値の Proc は可変長の引数を受け取ります。戻り値の Proc を呼び出すと、まず受け取った引数を self に渡して呼び出し、その戻り値を callable に渡して呼び出した結果を返します。

Proc#<< とは呼び出しの順序が逆になります。

[PARAM] callable:
Proc、Method、もしくは任意の call メソッドを持ったオブジェクト。
f = proc { |x| x * x }
g = proc { |x| x + x }

# (3 * 3) + (3 * 3)
p (f >> g).call(3) # => 18
call を定義したオブジェクトを渡す例
class WordScanner
  def self.call(str)
    str.scan(/\w+/)
  end
end

File.write('testfile', <<~TEXT)
  Hello, World!
  Hello, Ruby!
TEXT

pipeline = proc { |fname| File.read(fname) } >> WordScanner >> method(:p)
pipeline.call('testfile') # => ["Hello", "World", "Hello", "Ruby"]

[SEE_ALSO] Method#<<, Method#>>

arity -> Integer[permalink][rdoc][edit]

Proc オブジェクトが受け付ける引数の数を返します。

ただし、可変長引数を受け付ける場合、負の整数

-(必要とされる引数の数 + 1)

を返します。

p lambda{           }.arity # => 0
p lambda{||         }.arity # =>  0
p lambda{|x|        }.arity # =>  1
p lambda{|*x|       }.arity # => -1
p lambda{|x, y|     }.arity # =>  2
p lambda{|x, *y|    }.arity # => -2
p lambda{|(x, y)|   }.arity # =>  1
p lambda{|(x, y), z|}.arity # =>  2

[SEE_ALSO] Ruby用語集

binding -> Binding[permalink][rdoc][edit]

Proc オブジェクトが保持するコンテキストを Binding オブジェクトで返します。

def fred(param)
  proc {}
end

sample_proc = fred(99)
p eval("param", sample_proc.binding) # => 99
curry -> ProcRuby 1.9.3 から[permalink][rdoc][edit]
curry(arity) -> Proc

Procをカリー化します

カリー化したProcはいくつかの引数をとります。十分な数の引数が与えられると、元のProcに引数を渡して実行し、結果を返します。引数の個数が足りないときは、部分適用したカリー化Procを返します。

[PARAM] arity:
引数の個数を指定します
[RETURN]
カリー化したProcオブジェクトを返します
b = proc {|x, y, z| (x||0) + (y||0) + (z||0) }
p b.curry[1][2][3]           # => 6
p b.curry[1, 2][3, 4]        # => 6
p b.curry(5)[1][2][3][4][5]  # => 6
p b.curry(5)[1, 2][3, 4][5]  # => 6
p b.curry(1)[1]              # => 1

b = proc {|x, y, z, *w| (x||0) + (y||0) + (z||0) + w.sum }
p b.curry[1][2][3]           # => 6
p b.curry[1, 2][3, 4]        # => 10
p b.curry(5)[1][2][3][4][5]  # => 15
p b.curry(5)[1, 2][3, 4][5]  # => 15
p b.curry(1)[1]              # => 1

b = lambda {|x, y, z| (x||0) + (y||0) + (z||0) }
p b.curry[1][2][3]           # => 6
p b.curry[1, 2][3, 4]        # => wrong number of arguments (given 4, expected 3)
p b.curry(5)                 # => wrong number of arguments (given 5, expected 3)
p b.curry(1)                 # => wrong number of arguments (given 1, expected 3)

b = lambda {|x, y, z, *w| (x||0) + (y||0) + (z||0) + w.sum }
p b.curry[1][2][3]           # => 6
p b.curry[1, 2][3, 4]        # => 10
p b.curry(5)[1][2][3][4][5]  # => 15
p b.curry(5)[1, 2][3, 4][5]  # => 15
p b.curry(1)                 # => wrong number of arguments (given 1, expected 3+)

b = proc { :foo }
p b.curry[]                  # => :foo
hash -> Integer[permalink][rdoc][edit]

self のハッシュ値を返します。

to_s -> String[permalink][rdoc][edit]
inspect -> String

self の文字列表現を返します。

可能なら self を生成したソースファイル名、行番号を含みます。

p Proc.new {
   true
}.to_s

# => "#<Proc:0x401a880c -:3>"
lambda? -> boolRuby 1.9.3 から[permalink][rdoc][edit]

手続きオブジェクトの引数の取扱が厳密であるならば true を返します。

引数の取扱の厳密さの意味は以下の例を参考にしてください。

# lambda で生成した Proc オブジェクトでは true 
p lambda{}.lambda? # => true
# proc で生成した Proc オブジェクトでは false
proc{}.lambda?   # => false
# Proc.new で生成した Proc オブジェクトでは false
p Proc.new{}.lambda? # => false

# 以下、lambda?が偽である場合
# 余分な引数を無視する
proc{|a,b| [a,b]}.call(1,2,3) # => [1,2]
# 足りない引数には nil が渡される
proc{|a,b| [a,b]}.call(1) # => [1, nil]
# 配列1つだと展開される
proc{|a,b| [a,b]}.call([1,2]) # => [1,2]
# lambdaの場合これらはすべて ArgumentError となる
 
# &が付いた仮引数で生成される Proc は lambda? が偽となる
def n(&b) b.lambda? end
p n {} # => false

# &が付いた実引数によるものは、lambda?が元の Procオブジェクトから
# 引き継がれる
p lambda(&lambda {}).lambda? # => true
proc(&lambda {}).lambda?     # => true
p Proc.new(&lambda {}).lambda? # => true

p lambda(&proc {}).lambda?   # => false
proc(&proc {}).lambda?       # => false
p Proc.new(&proc {}).lambda? # => false

p n(&lambda {})              # => true
p n(&proc {})                # => false
p n(&Proc.new {})            # => false

# Method#to_proc によるものは lambda?が真となる
def m() end
p method(:m).to_proc.lambda? # => true

# Module#define_method は特別扱いで、
# これで定義されたメソッドの引数は常に厳密に取り扱われる
class C
  define_method(:d) {}
end
C.new.d(1,2)       # ~> ArgumentError
p C.new.method(:d).to_proc.lambda? # => true

class C
  define_method(:e, &proc {})
end
C.new.e(1,2)       # ~> ArgumentError
p C.new.method(:e).to_proc.lambda? # => true
parameters -> [object]Ruby 1.9.3 から[permalink][rdoc][edit]

Proc オブジェクトの引数の情報を返します。

Proc オブジェクトが引数を取らなければ空の配列を返します。引数を取る場合は、配列の配列を返し、各配列の要素は引数の種類に対応した以下のような Symbol と、引数名を表す Symbol の 2 要素です。

:req

必須の引数

:opt

デフォルト値が指定されたオプショナルな引数

:rest

* で指定された残りすべての引数

:keyreq

必須のキーワード引数

:key

デフォルト値が指定されたオプショナルなキーワード引数

:keyrest

** で指定された残りのキーワード引数

:block

& で指定されたブロック引数

分割代入を使った |(a, b)| のように引数名を持たない引数の場合は、引数の種類を表す Symbol だけの 1 要素の配列になります。ただし、オプショナルな引数の場合は引数名が nil の 2 要素の配列になります。

引数名を持たない引数の例
p lambda { |(a, b)| }.parameters  # => [[:req]]
p proc { |(a, b)| }.parameters    # => [[:opt, nil]]
p proc { |x, (a, b)| }.parameters # => [[:opt, :x], [:opt, nil]]
prc = lambda{|x, y=42, *other, k_x:, k_y: 42, **k_other, &b|}
prc.parameters # => [[:req, :x], [:opt, :y], [:rest, :other], [:keyreq, :k_x], [:key, :k_y], [:keyrest, :k_other], [:block, :b]]

[SEE_ALSO] Method#parameters, UnboundMethod#parameters

ruby2_keywords -> procRuby 2.7.0 から[permalink][rdoc][edit]

self に、通常の引数スプラット(*args)を通してキーワード引数を透過させるためのフラグを設定し、self を返します。引数スプラットは受け取るものの、明示的なキーワード引数やキーワードスプラット(**kwargs)は受け取らない Proc に対してだけ使ってください。

フラグを設定した Proc がキーワード引数付きで呼び出されると、末尾の Hash 引数に特別なフラグが設定されます。その Hash が別のメソッド呼び出しの引数スプラットの末尾要素として渡され、かつその呼び出しが明示的なキーワード引数やキーワードスプラットを含まない場合、末尾要素はキーワード引数として解釈されます。つまり、キーワード引数がこの Proc を経由してほかのメソッドへ渡されるようになります。

キーワード引数をほかのメソッドに委譲する Proc に対して、Ruby 2.7 より前のバージョンとの後方互換性のためだけに使ってください。

このメソッドは後方互換性のためだけに存在するので、いずれ削除される可能性があります。Ruby 2.7 より前のバージョンには存在しないため、例のように呼び出す前に Object#respond_to? で確認してください。また、このメソッドが削除されたときには、フラグを設定していた Proc はキーワード引数を透過しない挙動に変わることに注意してください。

module Mod
  foo = ->(meth, *args, &block) do
    send(:"do_#{meth}", *args, &block)
  end
  foo.ruby2_keywords if foo.respond_to?(:ruby2_keywords)
end

[SEE_ALSO] Module#ruby2_keywords, Hash.ruby2_keywords_hash

source_location -> [String, Integer] | nilRuby 1.9.3 から[permalink][rdoc][edit]

ソースコードのファイル名と行番号を配列で返します。

その手続オブジェクトが ruby で定義されていない(つまりネイティブである)場合は nil を返します。

# /path/to/target.rb を実行
proc {}.source_location            # => ["/path/to/target.rb", 1]
proc {}.source_location            # => ["/path/to/target.rb", 2]
p (eval "proc {}").source_location # => ["(eval)", 1]
p method(:p).to_proc.source_location # => nil

[SEE_ALSO] Method#source_location

to_proc -> self[permalink][rdoc][edit]

self を返します。

pr = proc {}
p pr == pr.to_proc # => true