Class: Proc
Overview
A Proc object is an encapsulation of a block of code, which can be stored in a local variable, passed to a method or another Proc, and can be called. Proc is an essential concept in Ruby and a core of its functional programming features.
square = Proc.new {|x| x**2 }
square.call(3) #=> 9
# shorthands:
square.(3) #=> 9
square[3] #=> 9
Proc objects are closures, meaning they remember and can use the entire context in which they were created.
def gen_times(factor)
Proc.new {|n| n*factor } # remembers the value of factor at the moment of creation
end
times3 = gen_times(3)
times5 = gen_times(5)
times3.call(12) #=> 36
times5.call(5) #=> 25
times3.call(times5.call(4)) #=> 60
Creation
There are several methods to create a Proc
-
Use the Proc class constructor:
proc1 = Proc.new {|x| x**2 } -
Use the Kernel#proc method as a shorthand of Proc.new:
proc2 = proc {|x| x**2 } -
Receiving a block of code into proc argument (note the
&):def make_proc(&block) block end proc3 = make_proc {|x| x**2 } -
Construct a proc with lambda semantics using the Kernel#lambda method
(see below for explanations about lambdas):
lambda1 = lambda {|x| x**2 }
-
Use the Lambda proc literal syntax
(also constructs a proc with lambda semantics):
lambda2 = ->(x) { x**2 }
Lambda and non-lambda semantics
Procs are coming in two flavors: lambda and non-lambda (regular procs). Differences are:
-
In lambdas,
returnandbreakmeans exit from this lambda; -
In non-lambda procs,
returnmeans exit from embracing method
(and will throw +LocalJumpError+ if invoked outside the method);
-
In non-lambda procs,
breakmeans exit from the method which the block given for.
(and will throw +LocalJumpError+ if invoked after the method returns);
-
In lambdas, arguments are treated in the same way as in methods: strict,
with +ArgumentError+ for mismatching argument number,
and no additional argument processing;
-
Regular procs accept arguments more generously: missing arguments
are filled with +nil+, single Array arguments are deconstructed if the
proc has multiple arguments, and there is no error raised on extra
arguments.
Examples:
# +return+ in non-lambda proc, +b+, exits +m2+.
# (The block +{ return }+ is given for +m1+ and embraced by +m2+.)
$a = []; def m1(&b) b.call; $a << :m1 end; def m2() m1 { return }; $a << :m2 end; m2; p $a
#=> []
# +break+ in non-lambda proc, +b+, exits +m1+.
# (The block +{ break }+ is given for +m1+ and embraced by +m2+.)
$a = []; def m1(&b) b.call; $a << :m1 end; def m2() m1 { break }; $a << :m2 end; m2; p $a
#=> [:m2]
# +next+ in non-lambda proc, +b+, exits the block.
# (The block +{ next }+ is given for +m1+ and embraced by +m2+.)
$a = []; def m1(&b) b.call; $a << :m1 end; def m2() m1 { next }; $a << :m2 end; m2; p $a
#=> [:m1, :m2]
# Using +proc+ method changes the behavior as follows because
# The block is given for +proc+ method and embraced by +m2+.
$a = []; def m1(&b) b.call; $a << :m1 end; def m2() m1(&proc { return }); $a << :m2 end; m2; p $a
#=> []
$a = []; def m1(&b) b.call; $a << :m1 end; def m2() m1(&proc { break }); $a << :m2 end; m2; p $a
# break from proc-closure (LocalJumpError)
$a = []; def m1(&b) b.call; $a << :m1 end; def m2() m1(&proc { next }); $a << :m2 end; m2; p $a
#=> [:m1, :m2]
# +return+, +break+ and +next+ in the stubby lambda exits the block.
# (+lambda+ method behaves same.)
# (The block is given for stubby lambda syntax and embraced by +m2+.)
$a = []; def m1(&b) b.call; $a << :m1 end; def m2() m1(&-> { return }); $a << :m2 end; m2; p $a
#=> [:m1, :m2]
$a = []; def m1(&b) b.call; $a << :m1 end; def m2() m1(&-> { break }); $a << :m2 end; m2; p $a
#=> [:m1, :m2]
$a = []; def m1(&b) b.call; $a << :m1 end; def m2() m1(&-> { next }); $a << :m2 end; m2; p $a
#=> [:m1, :m2]
p = proc {|x, y| "x=#{x}, y=#{y}" }
p.call(1, 2) #=> "x=1, y=2"
p.call([1, 2]) #=> "x=1, y=2", array deconstructed
p.call(1, 2, 8) #=> "x=1, y=2", extra argument discarded
p.call(1) #=> "x=1, y=", nil substituted instead of error
l = lambda {|x, y| "x=#{x}, y=#{y}" }
l.call(1, 2) #=> "x=1, y=2"
l.call([1, 2]) # ArgumentError: wrong number of arguments (given 1, expected 2)
l.call(1, 2, 8) # ArgumentError: wrong number of arguments (given 3, expected 2)
l.call(1) # ArgumentError: wrong number of arguments (given 1, expected 2)
def test_return
-> { return 3 }.call # just returns from lambda into method body
proc { return 4 }.call # returns from method
return 5
end
test_return # => 4, return from proc
Lambdas are useful as self-sufficient functions, in particular useful as arguments to higher-order functions, behaving exactly like Ruby methods.
Procs are useful for implementing iterators:
def test
[[1, 2], [3, 4], [5, 6]].map {|a, b| return a if a + b > 10 }
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
end
Inside map, the block of code is treated as a regular (non-lambda) proc, which means that the internal arrays will be deconstructed to pairs of arguments, and return will exit from the method test. That would not be possible with a stricter lambda.
You can tell a lambda from a regular proc by using the #lambda? instance method.
Lambda semantics is typically preserved during the proc lifetime, including &-deconstruction to a block of code:
p = proc {|x, y| x }
l = lambda {|x, y| x }
[[1, 2], [3, 4]].map(&p) #=> [1, 3]
[[1, 2], [3, 4]].map(&l) # ArgumentError: wrong number of arguments (given 1, expected 2)
The only exception is dynamic method definition: even if defined by passing a non-lambda proc, methods still have normal semantics of argument checking.
class C
define_method(:e, &proc {})
end
C.new.e(1,2) #=> ArgumentError
C.new.method(:e).to_proc.lambda? #=> true
This exception ensures that methods never have unusual argument passing conventions, and makes it easy to have wrappers defining methods that behave as usual.
class C
def self.def2(name, &body)
define_method(name, &body)
end
def2(:f) {}
end
C.new.f(1,2) #=> ArgumentError
The wrapper def2 receives body as a non-lambda proc, yet defines a method which has normal semantics.
Conversion of other objects to procs
Any object that implements the to_proc method can be converted into a proc by the & operator, and therefore can be consumed by iterators.
class Greeter
def initialize(greeting)
@greeting = greeting
end
def to_proc
proc {|name| "#{@greeting}, #{name}!" }
end
end
hi = Greeter.new("Hi")
hey = Greeter.new("Hey")
["Bob", "Jane"].map(&hi) #=> ["Hi, Bob!", "Hi, Jane!"]
["Bob", "Jane"].map(&hey) #=> ["Hey, Bob!", "Hey, Jane!"]
Of the Ruby core classes, this method is implemented by Symbol, Method, and Hash.
:to_s.to_proc.call(1) #=> "1"
[1, 2].map(&:to_s) #=> ["1", "2"]
method(:puts).to_proc.call(1) # prints 1
[1, 2].each(&method(:puts)) # prints 1, 2
{test: 1}.to_proc.call(:test) #=> 1
i[test many keys].map(&{test: 1}) #=> [1, nil, nil]
Orphaned Proc
return and break in a block exit a method. If a Proc object is generated from the block and the Proc object survives until the method is returned, return and break cannot work. In such case, return and break raises LocalJumpError. A Proc object in such situation is called as orphaned Proc object.
Note that the method to exit is different for return and break. There is a situation that orphaned for break but not orphaned for return.
def m1(&b) b.call end; def m2(); m1 { return } end; m2 # ok
def m1(&b) b.call end; def m2(); m1 { break } end; m2 # ok
def m1(&b) b end; def m2(); m1 { return }.call end; m2 # ok
def m1(&b) b end; def m2(); m1 { break }.call end; m2 # LocalJumpError
def m1(&b) b end; def m2(); m1 { return } end; m2.call # LocalJumpError
def m1(&b) b end; def m2(); m1 { break } end; m2.call # LocalJumpError
Since return and break exits the block itself in lambdas, lambdas cannot be orphaned.
Numbered parameters
Numbered parameters are implicitly defined block parameters intended to simplify writing short blocks:
# Explicit parameter:
%w[test me please].each { |str| puts str.upcase } # prints TEST, ME, PLEASE
(1..5).map { |i| i**2 } # => [1, 4, 9, 16, 25]
# Implicit parameter:
%w[test me please].each { puts _1.upcase } # prints TEST, ME, PLEASE
(1..5).map { _1**2 } # => [1, 4, 9, 16, 25]
Parameter names from _1 to _9 are supported:
[10, 20, 30].zip([40, 50, 60], [70, 80, 90]).map { _1 + _2 + _3 }
# => [120, 150, 180]
Though, it is advised to resort to them wisely, probably limiting yourself to _1 and _2, and to one-line blocks.
Numbered parameters can’t be used together with explicitly named ones:
[10, 20, 30].map { |x| _1**2 }
# SyntaxError (ordinary parameter is defined)
To avoid conflicts, naming local variables or method arguments _1, _2 and so on, causes a warning.
_1 = 'test'
# warning: `_1' is reserved as numbered parameter
Using implicit numbered parameters affects block’s arity:
p = proc { _1 + _2 }
l = lambda { _1 + _2 }
p.parameters # => [[:opt, :_1], [:opt, :_2]]
p.arity # => 2
l.parameters # => [[:req, :_1], [:req, :_2]]
l.arity # => 2
Blocks with numbered parameters can’t be nested:
%w[test me].each { _1.each_char { p _1 } }
# SyntaxError (numbered parameter is already used in outer block here)
# %w[test me].each { _1.each_char { p _1 } }
# ^~
Numbered parameters were introduced in Ruby 2.7.
Class Method Summary collapse
-
.new {|...| ... } ⇒ Proc
Creates a new Proc object, bound to the current context.
Instance Method Summary collapse
-
#<<(g) ⇒ Proc
Returns a proc that is the composition of this proc and the given g.
-
#==(other) ⇒ Object
Two procs are the same if, and only if, they were created from the same code block.
-
#===(*args) ⇒ Object
call-seq: proc === obj -> result_of_proc.
-
#>>(g) ⇒ Proc
Returns a proc that is the composition of this proc and the given g.
-
#[](*args) ⇒ Object
call-seq: prc.call(params,…) -> obj prc -> obj prc.(params,…) -> obj prc.yield(params,…) -> obj.
-
#arity ⇒ Integer
Returns the number of mandatory arguments.
-
#binding ⇒ Binding
Returns the binding associated with prc.
-
#call(*args) ⇒ Object
call-seq: prc.call(params,…) -> obj prc -> obj prc.(params,…) -> obj prc.yield(params,…) -> obj.
-
#clone ⇒ Object
:nodoc:.
-
#curry(*args) ⇒ Object
Returns a curried proc.
-
#dup ⇒ Object
:nodoc:.
-
#eql?(other) ⇒ Object
Two procs are the same if, and only if, they were created from the same code block.
-
#hash ⇒ Integer
Returns a hash value corresponding to proc body.
-
#lambda? ⇒ Boolean
Returns
trueif a Proc object is lambda. -
#parameters(lambda: nil) ⇒ Array
Returns the parameter information of this proc.
-
#ruby2_keywords ⇒ Proc
Marks the proc as passing keywords through a normal argument splat.
-
#source_location ⇒ Array, Integer
Returns the Ruby source filename and line number containing this proc or
nilif this proc was not defined in Ruby (i.e. native). -
#to_proc ⇒ Proc
Part of the protocol for converting objects to Proc objects.
-
#to_s ⇒ String
(also: #inspect)
Returns the unique identifier for this proc, along with an indication of where the proc was defined.
-
#yield(*args) ⇒ Object
call-seq: prc.call(params,…) -> obj prc -> obj prc.(params,…) -> obj prc.yield(params,…) -> obj.
Class Method Details
.new {|...| ... } ⇒ Proc
Creates a new Proc object, bound to the current context.
proc = Proc.new { "hello" }
proc.call #=> "hello"
Raises ArgumentError if called without a block.
Proc.new #=> ArgumentError
821 822 823 824 825 826 827 828 |
# File 'proc.c', line 821 static VALUE rb_proc_s_new(int argc, VALUE *argv, VALUE klass) { VALUE block = proc_new(klass, FALSE); rb_obj_call_init_kw(block, argc, argv, RB_PASS_CALLED_KEYWORDS); return block; } |
Instance Method Details
#<<(g) ⇒ Proc
Returns a proc that is the composition of this proc and the given g. The returned proc takes a variable number of arguments, calls g with them then calls this proc with the result.
f = proc {|x| x * x }
g = proc {|x| x + x }
p (f << g).call(2) #=> 16
See Proc#>> for detailed explanations.
3743 3744 3745 3746 3747 |
# File 'proc.c', line 3743 static VALUE proc_compose_to_left(VALUE self, VALUE g) { return rb_proc_compose_to_left(self, to_callable(g)); } |
#==(other) ⇒ Boolean #eql?(other) ⇒ Boolean
Two procs are the same if, and only if, they were created from the same code block.
def return_block(&block)
block
end
def pass_block_twice(&block)
[return_block(&block), return_block(&block)]
end
block1, block2 = pass_block_twice { puts 'test' }
# Blocks might be instantiated into Proc's lazily, so they may, or may not,
# be the same object.
# But they are produced from the same code block, so they are equal
block1 == block2
#=> true
# Another Proc will never be equal, even if the code is the "same"
block1 == proc { puts 'test' }
#=> false
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 |
# File 'proc.c', line 1291 static VALUE proc_eq(VALUE self, VALUE other) { const rb_proc_t *self_proc, *other_proc; const struct rb_block *self_block, *other_block; if (rb_obj_class(self) != rb_obj_class(other)) { return Qfalse; } GetProcPtr(self, self_proc); GetProcPtr(other, other_proc); if (self_proc->is_from_method != other_proc->is_from_method || self_proc->is_lambda != other_proc->is_lambda) { return Qfalse; } self_block = &self_proc->block; other_block = &other_proc->block; if (vm_block_type(self_block) != vm_block_type(other_block)) { return Qfalse; } switch (vm_block_type(self_block)) { case block_type_iseq: if (self_block->as.captured.ep != \ other_block->as.captured.ep || self_block->as.captured.code.iseq != \ other_block->as.captured.code.iseq) { return Qfalse; } break; case block_type_ifunc: if (self_block->as.captured.code.ifunc != \ other_block->as.captured.code.ifunc) { return Qfalse; } if (memcmp( ((cfunc_proc_t *)self_proc)->env, ((cfunc_proc_t *)other_proc)->env, sizeof(((cfunc_proc_t *)self_proc)->env))) { return Qfalse; } break; case block_type_proc: if (self_block->as.proc != other_block->as.proc) { return Qfalse; } break; case block_type_symbol: if (self_block->as.symbol != other_block->as.symbol) { return Qfalse; } break; } return Qtrue; } |
#===(*args) ⇒ Object
call-seq:
proc === obj -> result_of_proc
Invokes the block with obj as the proc’s parameter like Proc#call. This allows a proc object to be the target of a when clause in a case statement.
952 953 954 955 956 |
# File 'proc.c', line 952 static VALUE proc_call(int argc, VALUE *argv, VALUE procval) { /* removed */ } |
#>>(g) ⇒ Proc
Returns a proc that is the composition of this proc and the given g. The returned proc takes a variable number of arguments, calls this proc with them then calls g with the result.
f = proc {|x| x * x }
g = proc {|x| x + x }
p (f >> g).call(2) #=> 8
g could be other Proc, or Method, or any other object responding to call method:
class Parser
def self.call(text)
# ...some complicated parsing logic...
end
end
pipeline = File.method(:read) >> Parser >> proc { |data| puts "data size: #{data.count}" }
pipeline.call('data.json')
See also Method#>> and Method#<<.
3802 3803 3804 3805 3806 |
# File 'proc.c', line 3802 static VALUE proc_compose_to_right(VALUE self, VALUE g) { return rb_proc_compose_to_right(self, to_callable(g)); } |
#[](*args) ⇒ Object
call-seq:
prc.call(params,...) -> obj
prc[params,...] -> obj
prc.(params,...) -> obj
prc.yield(params,...) -> obj
Invokes the block, setting the block’s parameters to the values in params using something close to method calling semantics. Returns the value of the last expression evaluated in the block.
a_proc = Proc.new {|scalar, *values| values.map {|value| value*scalar } }
a_proc.call(9, 1, 2, 3) #=> [9, 18, 27]
a_proc[9, 1, 2, 3] #=> [9, 18, 27]
a_proc.(9, 1, 2, 3) #=> [9, 18, 27]
a_proc.yield(9, 1, 2, 3) #=> [9, 18, 27]
Note that prc.() invokes prc.call() with the parameters given. It’s syntactic sugar to hide “call”.
For procs created using #lambda or ->() an error is generated if the wrong number of parameters are passed to the proc. For procs created using Proc.new or Kernel.proc, extra parameters are silently discarded and missing parameters are set to nil.
a_proc = proc {|a,b| [a,b] }
a_proc.call(1) #=> [1, nil]
a_proc = lambda {|a,b| [a,b] }
a_proc.call(1) # ArgumentError: wrong number of arguments (given 1, expected 2)
See also Proc#lambda?.
952 953 954 955 956 |
# File 'proc.c', line 952 static VALUE proc_call(int argc, VALUE *argv, VALUE procval) { /* removed */ } |
#arity ⇒ Integer
Returns the number of mandatory arguments. If the block is declared to take no arguments, returns 0. If the block is known to take exactly n arguments, returns n. If the block has optional arguments, returns -n-1, where n is the number of mandatory arguments, with the exception for blocks that are not lambdas and have only a finite number of optional arguments; in this latter case, returns n. Keyword arguments will be considered as a single additional argument, that argument being mandatory if any keyword argument is mandatory. A #proc with no argument declarations is the same as a block declaring || as its arguments.
proc {}.arity #=> 0
proc { || }.arity #=> 0
proc { |a| }.arity #=> 1
proc { |a, b| }.arity #=> 2
proc { |a, b, c| }.arity #=> 3
proc { |*a| }.arity #=> -1
proc { |a, *b| }.arity #=> -2
proc { |a, *b, c| }.arity #=> -3
proc { |x:, y:, z:0| }.arity #=> 1
proc { |*a, x:, y:0| }.arity #=> -2
proc { |a=0| }.arity #=> 0
lambda { |a=0| }.arity #=> -1
proc { |a=0, b| }.arity #=> 1
lambda { |a=0, b| }.arity #=> -2
proc { |a=0, b=0| }.arity #=> 0
lambda { |a=0, b=0| }.arity #=> -1
proc { |a, b=0| }.arity #=> 1
lambda { |a, b=0| }.arity #=> -2
proc { |(a, b), c=0| }.arity #=> 1
lambda { |(a, b), c=0| }.arity #=> -2
proc { |a, x:0, y:0| }.arity #=> 1
lambda { |a, x:0, y:0| }.arity #=> -2
1060 1061 1062 1063 1064 1065 |
# File 'proc.c', line 1060 static VALUE proc_arity(VALUE self) { int arity = rb_proc_arity(self); return INT2FIX(arity); } |
#binding ⇒ Binding
Returns the binding associated with prc.
def fred(param)
proc {}
end
b = fred(99)
eval("param", b.binding) #=> 99
3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 3497 3498 3499 3500 3501 3502 3503 3504 3505 3506 3507 3508 3509 3510 3511 3512 3513 3514 3515 3516 3517 3518 3519 3520 3521 3522 3523 3524 3525 3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 |
# File 'proc.c', line 3480 static VALUE proc_binding(VALUE self) { VALUE bindval, binding_self = Qundef; rb_binding_t *bind; const rb_proc_t *proc; const rb_iseq_t *iseq = NULL; const struct rb_block *block; const rb_env_t *env = NULL; GetProcPtr(self, proc); block = &proc->block; if (proc->is_isolated) rb_raise(rb_eArgError, "Can't create Binding from isolated Proc"); again: switch (vm_block_type(block)) { case block_type_iseq: iseq = block->as.captured.code.iseq; binding_self = block->as.captured.self; env = VM_ENV_ENVVAL_PTR(block->as.captured.ep); break; case block_type_proc: GetProcPtr(block->as.proc, proc); block = &proc->block; goto again; case block_type_ifunc: { const struct vm_ifunc *ifunc = block->as.captured.code.ifunc; if (IS_METHOD_PROC_IFUNC(ifunc)) { VALUE method = (VALUE)ifunc->data; VALUE name = rb_fstring_lit("<empty_iseq>"); rb_iseq_t *empty; binding_self = method_receiver(method); iseq = rb_method_iseq(method); env = VM_ENV_ENVVAL_PTR(block->as.captured.ep); env = env_clone(env, method_cref(method)); /* set empty iseq */ empty = rb_iseq_new(NULL, name, name, Qnil, 0, ISEQ_TYPE_TOP); RB_OBJ_WRITE(env, &env->iseq, empty); break; } } /* FALLTHROUGH */ case block_type_symbol: rb_raise(rb_eArgError, "Can't create Binding from C level Proc"); UNREACHABLE_RETURN(Qnil); } bindval = rb_binding_alloc(rb_cBinding); GetBindingPtr(bindval, bind); RB_OBJ_WRITE(bindval, &bind->block.as.captured.self, binding_self); RB_OBJ_WRITE(bindval, &bind->block.as.captured.code.iseq, env->iseq); rb_vm_block_ep_update(bindval, &bind->block, env->ep); RB_OBJ_WRITTEN(bindval, Qundef, VM_ENV_ENVVAL(env->ep)); if (iseq) { rb_iseq_check(iseq); RB_OBJ_WRITE(bindval, &bind->pathobj, ISEQ_BODY(iseq)->location.pathobj); bind->first_lineno = ISEQ_BODY(iseq)->location.first_lineno; } else { RB_OBJ_WRITE(bindval, &bind->pathobj, rb_iseq_pathobj_new(rb_fstring_lit("(binding)"), Qnil)); bind->first_lineno = 1; } return bindval; } |
#call(*args) ⇒ Object
call-seq:
prc.call(params,...) -> obj
prc[params,...] -> obj
prc.(params,...) -> obj
prc.yield(params,...) -> obj
Invokes the block, setting the block’s parameters to the values in params using something close to method calling semantics. Returns the value of the last expression evaluated in the block.
a_proc = Proc.new {|scalar, *values| values.map {|value| value*scalar } }
a_proc.call(9, 1, 2, 3) #=> [9, 18, 27]
a_proc[9, 1, 2, 3] #=> [9, 18, 27]
a_proc.(9, 1, 2, 3) #=> [9, 18, 27]
a_proc.yield(9, 1, 2, 3) #=> [9, 18, 27]
Note that prc.() invokes prc.call() with the parameters given. It’s syntactic sugar to hide “call”.
For procs created using #lambda or ->() an error is generated if the wrong number of parameters are passed to the proc. For procs created using Proc.new or Kernel.proc, extra parameters are silently discarded and missing parameters are set to nil.
a_proc = proc {|a,b| [a,b] }
a_proc.call(1) #=> [1, nil]
a_proc = lambda {|a,b| [a,b] }
a_proc.call(1) # ArgumentError: wrong number of arguments (given 1, expected 2)
See also Proc#lambda?.
952 953 954 955 956 |
# File 'proc.c', line 952 static VALUE proc_call(int argc, VALUE *argv, VALUE procval) { /* removed */ } |
#clone ⇒ Object
:nodoc:
125 126 127 128 129 130 |
# File 'proc.c', line 125 static VALUE proc_clone(VALUE self) { VALUE procval = rb_proc_dup(self); return rb_obj_clone_setup(self, procval, Qnil); } |
#curry ⇒ Proc #curry(arity) ⇒ Proc
Returns a curried proc. If the optional arity argument is given, it determines the number of arguments. A curried proc receives some arguments. If a sufficient number of arguments are supplied, it passes the supplied arguments to the original proc and returns the result. Otherwise, returns another curried proc that takes the rest of arguments.
The optional arity argument should be supplied when currying procs with variable arguments to determine how many arguments are needed before the proc is called.
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.inject(0, &:+) }
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.inject(0, &:+) }
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
3638 3639 3640 3641 3642 3643 3644 3645 3646 3647 3648 3649 3650 3651 3652 3653 3654 3655 |
# File 'proc.c', line 3638 static VALUE proc_curry(int argc, const VALUE *argv, VALUE self) { int sarity, max_arity, min_arity = rb_proc_min_max_arity(self, &max_arity); VALUE arity; if (rb_check_arity(argc, 0, 1) == 0 || NIL_P(arity = argv[0])) { arity = INT2FIX(min_arity); } else { sarity = FIX2INT(arity); if (rb_proc_lambda_p(self)) { rb_check_arity(sarity, min_arity, max_arity); } } return make_curry_proc(self, rb_ary_new(), arity); } |
#dup ⇒ Object
:nodoc:
133 134 135 136 137 138 |
# File 'proc.c', line 133 static VALUE proc_dup(VALUE self) { VALUE procval = rb_proc_dup(self); return rb_obj_dup_setup(self, procval); } |
#==(other) ⇒ Boolean #eql?(other) ⇒ Boolean
Two procs are the same if, and only if, they were created from the same code block.
def return_block(&block)
block
end
def pass_block_twice(&block)
[return_block(&block), return_block(&block)]
end
block1, block2 = pass_block_twice { puts 'test' }
# Blocks might be instantiated into Proc's lazily, so they may, or may not,
# be the same object.
# But they are produced from the same code block, so they are equal
block1 == block2
#=> true
# Another Proc will never be equal, even if the code is the "same"
block1 == proc { puts 'test' }
#=> false
1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 |
# File 'proc.c', line 1291 static VALUE proc_eq(VALUE self, VALUE other) { const rb_proc_t *self_proc, *other_proc; const struct rb_block *self_block, *other_block; if (rb_obj_class(self) != rb_obj_class(other)) { return Qfalse; } GetProcPtr(self, self_proc); GetProcPtr(other, other_proc); if (self_proc->is_from_method != other_proc->is_from_method || self_proc->is_lambda != other_proc->is_lambda) { return Qfalse; } self_block = &self_proc->block; other_block = &other_proc->block; if (vm_block_type(self_block) != vm_block_type(other_block)) { return Qfalse; } switch (vm_block_type(self_block)) { case block_type_iseq: if (self_block->as.captured.ep != \ other_block->as.captured.ep || self_block->as.captured.code.iseq != \ other_block->as.captured.code.iseq) { return Qfalse; } break; case block_type_ifunc: if (self_block->as.captured.code.ifunc != \ other_block->as.captured.code.ifunc) { return Qfalse; } if (memcmp( ((cfunc_proc_t *)self_proc)->env, ((cfunc_proc_t *)other_proc)->env, sizeof(((cfunc_proc_t *)self_proc)->env))) { return Qfalse; } break; case block_type_proc: if (self_block->as.proc != other_block->as.proc) { return Qfalse; } break; case block_type_symbol: if (self_block->as.symbol != other_block->as.symbol) { return Qfalse; } break; } return Qtrue; } |
#hash ⇒ Integer
Returns a hash value corresponding to proc body.
See also Object#hash.
1540 1541 1542 1543 1544 1545 1546 1547 1548 |
# File 'proc.c', line 1540 static VALUE proc_hash(VALUE self) { st_index_t hash; hash = rb_hash_start(0); hash = rb_hash_proc(hash, self); hash = rb_hash_end(hash); return ST2FIX(hash); } |
#lambda? ⇒ Boolean
Returns true if a Proc object is lambda. false if non-lambda.
The lambda-ness affects argument handling and the behavior of return and break.
A Proc object generated by proc ignores extra arguments.
proc {|a,b| [a,b] }.call(1,2,3) #=> [1,2]
It provides nil for missing arguments.
proc {|a,b| [a,b] }.call(1) #=> [1,nil]
It expands a single array argument.
proc {|a,b| [a,b] }.call([1,2]) #=> [1,2]
A Proc object generated by lambda doesn’t have such tricks.
lambda {|a,b| [a,b] }.call(1,2,3) #=> ArgumentError
lambda {|a,b| [a,b] }.call(1) #=> ArgumentError
lambda {|a,b| [a,b] }.call([1,2]) #=> ArgumentError
Proc#lambda? is a predicate for the tricks. It returns true if no tricks apply.
lambda {}.lambda? #=> true
proc {}.lambda? #=> false
Proc.new is the same as proc.
Proc.new {}.lambda? #=> false
lambda, proc and Proc.new preserve the tricks of a Proc object given by & argument.
lambda(&lambda {}).lambda? #=> true
proc(&lambda {}).lambda? #=> true
Proc.new(&lambda {}).lambda? #=> true
lambda(&proc {}).lambda? #=> false
proc(&proc {}).lambda? #=> false
Proc.new(&proc {}).lambda? #=> false
A Proc object generated by & argument has the tricks
def n(&b) b.lambda? end
n {} #=> false
The & argument preserves the tricks if a Proc object is given by & argument.
n(&lambda {}) #=> true
n(&proc {}) #=> false
n(&Proc.new {}) #=> false
A Proc object converted from a method has no tricks.
def m() end
method(:m).to_proc.lambda? #=> true
n(&method(:m)) #=> true
n(&method(:m).to_proc) #=> true
define_method is treated the same as method definition. The defined method has no tricks.
class C
define_method(:d) {}
end
C.new.d(1,2) #=> ArgumentError
C.new.method(:d).to_proc.lambda? #=> true
define_method always defines a method without the tricks, even if a non-lambda Proc object is given. This is the only exception for which the tricks are not preserved.
class C
define_method(:e, &proc {})
end
C.new.e(1,2) #=> ArgumentError
C.new.method(:e).to_proc.lambda? #=> true
This exception ensures that methods never have tricks and makes it easy to have wrappers to define methods that behave as usual.
class C
def self.def2(name, &body)
define_method(name, &body)
end
def2(:f) {}
end
C.new.f(1,2) #=> ArgumentError
The wrapper def2 defines a method which has no tricks.
243 244 245 246 247 248 249 250 |
# File 'proc.c', line 243 VALUE rb_proc_lambda_p(VALUE procval) { rb_proc_t *proc; GetProcPtr(procval, proc); return RBOOL(proc->is_lambda); } |
#parameters(lambda: nil) ⇒ Array
Returns the parameter information of this proc. If the lambda keyword is provided and not nil, treats the proc as a lambda if true and as a non-lambda if false.
prc = proc{|x, y=42, *other|}
prc.parameters #=> [[:opt, :x], [:opt, :y], [:rest, :other]]
prc = lambda{|x, y=42, *other|}
prc.parameters #=> [[:req, :x], [:opt, :y], [:rest, :other]]
prc = proc{|x, y=42, *other|}
prc.parameters(lambda: true) #=> [[:req, :x], [:opt, :y], [:rest, :other]]
prc = lambda{|x, y=42, *other|}
prc.parameters(lambda: false) #=> [[:opt, :x], [:opt, :y], [:rest, :other]]
1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 |
# File 'proc.c', line 1423 static VALUE rb_proc_parameters(int argc, VALUE *argv, VALUE self) { static ID keyword_ids[1]; VALUE opt, lambda; VALUE kwargs[1]; int is_proc ; const rb_iseq_t *iseq; iseq = rb_proc_get_iseq(self, &is_proc); if (!keyword_ids[0]) { CONST_ID(keyword_ids[0], "lambda"); } rb_scan_args(argc, argv, "0:", &opt); if (!NIL_P(opt)) { rb_get_kwargs(opt, keyword_ids, 0, 1, kwargs); lambda = kwargs[0]; if (!NIL_P(lambda)) { is_proc = !RTEST(lambda); } } if (!iseq) { return rb_unnamed_parameters(rb_proc_arity(self)); } return rb_iseq_parameters(iseq, is_proc); } |
#ruby2_keywords ⇒ Proc
Marks the proc as passing keywords through a normal argument splat. This should only be called on procs that accept an argument splat (*args) but not explicit keywords or a keyword splat. It marks the proc such that if the proc is called with keyword arguments, the final hash argument is marked with a special flag such that if it is the final element of a normal argument splat to another method call, and that method call does not include explicit keywords or a keyword splat, the final element is interpreted as keywords. In other words, keywords will be passed through the proc to other methods.
This should only be used for procs that delegate keywords to another method, and only for backwards compatibility with Ruby versions before 2.7.
This method will probably be removed at some point, as it exists only for backwards compatibility. As it does not exist in Ruby versions before 2.7, check that the proc responds to this method before calling it. Also, be aware that if this method is removed, the behavior of the proc will change so that it does not pass through keywords.
module Mod
foo = ->(meth, *args, &block) do
send(:"do_#{meth}", *args, &block)
end
foo.ruby2_keywords if foo.respond_to?(:ruby2_keywords)
end
3909 3910 3911 3912 3913 3914 3915 3916 3917 3918 3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 |
# File 'proc.c', line 3909 static VALUE proc_ruby2_keywords(VALUE procval) { rb_proc_t *proc; GetProcPtr(procval, proc); rb_check_frozen(procval); if (proc->is_from_method) { rb_warn("Skipping set of ruby2_keywords flag for proc (proc created from method)"); return procval; } switch (proc->block.type) { case block_type_iseq: if (ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.has_rest && !ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.has_kw && !ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.has_kwrest) { ISEQ_BODY(proc->block.as.captured.code.iseq)->param.flags.ruby2_keywords = 1; } else { rb_warn("Skipping set of ruby2_keywords flag for proc (proc accepts keywords or proc does not accept argument splat)"); } break; default: rb_warn("Skipping set of ruby2_keywords flag for proc (proc not defined in Ruby)"); break; } return procval; } |
#source_location ⇒ Array, Integer
Returns the Ruby source filename and line number containing this proc or nil if this proc was not defined in Ruby (i.e. native).
1380 1381 1382 1383 1384 |
# File 'proc.c', line 1380 VALUE rb_proc_location(VALUE self) { return iseq_location(rb_proc_get_iseq(self, 0)); } |
#to_proc ⇒ Proc
Part of the protocol for converting objects to Proc objects. Instances of class Proc simply return themselves.
1606 1607 1608 1609 1610 |
# File 'proc.c', line 1606 static VALUE proc_to_proc(VALUE self) { return self; } |
#to_s ⇒ String Also known as: inspect
Returns the unique identifier for this proc, along with an indication of where the proc was defined.
1590 1591 1592 1593 1594 1595 1596 |
# File 'proc.c', line 1590 static VALUE proc_to_s(VALUE self) { const rb_proc_t *proc; GetProcPtr(self, proc); return rb_block_to_s(self, &proc->block, proc->is_lambda ? " (lambda)" : NULL); } |
#yield(*args) ⇒ Object
call-seq:
prc.call(params,...) -> obj
prc[params,...] -> obj
prc.(params,...) -> obj
prc.yield(params,...) -> obj
Invokes the block, setting the block’s parameters to the values in params using something close to method calling semantics. Returns the value of the last expression evaluated in the block.
a_proc = Proc.new {|scalar, *values| values.map {|value| value*scalar } }
a_proc.call(9, 1, 2, 3) #=> [9, 18, 27]
a_proc[9, 1, 2, 3] #=> [9, 18, 27]
a_proc.(9, 1, 2, 3) #=> [9, 18, 27]
a_proc.yield(9, 1, 2, 3) #=> [9, 18, 27]
Note that prc.() invokes prc.call() with the parameters given. It’s syntactic sugar to hide “call”.
For procs created using #lambda or ->() an error is generated if the wrong number of parameters are passed to the proc. For procs created using Proc.new or Kernel.proc, extra parameters are silently discarded and missing parameters are set to nil.
a_proc = proc {|a,b| [a,b] }
a_proc.call(1) #=> [1, nil]
a_proc = lambda {|a,b| [a,b] }
a_proc.call(1) # ArgumentError: wrong number of arguments (given 1, expected 2)
See also Proc#lambda?.
952 953 954 955 956 |
# File 'proc.c', line 952 static VALUE proc_call(int argc, VALUE *argv, VALUE procval) { /* removed */ } |