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 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,
return
andbreak
means exit from this lambda; -
In non-lambda procs,
return
means exit from embracing method
(and will throw +LocalJumpError+ if invoked outside the method);
-
In non-lambda procs,
break
means 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, 2]
[[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 con 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(*args) ⇒ Object
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.
-
#===(*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
-
#hash ⇒ Integer
Returns a hash value corresponding to proc body.
-
#lambda? ⇒ Boolean
Returns
true
if a Proc object is lambda. -
#parameters ⇒ 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
nil
if 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 .new ⇒ Proc
Creates a new Proc object, bound to the current context. Proc::new may be called without a block only within a method with an attached block, in which case that block is converted to the Proc object.
def proc_from
Proc.new
end
proc = proc_from { "hello" }
proc.call #=> "hello"
827 828 829 830 831 832 833 834 |
# File 'proc.c', line 827
static VALUE
rb_proc_s_new(int argc, VALUE *argv, VALUE klass)
{
VALUE block = proc_new(klass, FALSE, 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.
3366 3367 3368 3369 3370 |
# File 'proc.c', line 3366
static VALUE
proc_compose_to_left(VALUE self, VALUE g)
{
return rb_proc_compose_to_left(self, to_callable(g));
}
|
#===(*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.
926 927 928 929 930 |
# File 'proc.c', line 926
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#<<.
3419 3420 3421 3422 3423 |
# File 'proc.c', line 3419
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?.
926 927 928 929 930 |
# File 'proc.c', line 926
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
1053 1054 1055 1056 1057 1058 |
# File 'proc.c', line 1053
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
3106 3107 3108 3109 3110 3111 3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 |
# File 'proc.c', line 3106
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;
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_symbol:
goto error;
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;
}
else {
error:
rb_raise(rb_eArgError, "Can't create Binding from C level Proc");
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->location.pathobj);
bind->first_lineno = FIX2INT(rb_iseq_first_lineno(iseq));
}
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?.
926 927 928 929 930 |
# File 'proc.c', line 926
static VALUE
proc_call(int argc, VALUE *argv, VALUE procval)
{
/* removed */
}
|
#clone ⇒ Object
:nodoc:
163 164 165 166 167 168 169 |
# File 'proc.c', line 163
static VALUE
proc_clone(VALUE self)
{
VALUE procval = rb_proc_dup(self);
CLONESETUP(procval, self);
return procval;
}
|
#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.
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
3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 |
# File 'proc.c', line 3261
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
919 920 921 922 923 924 925 926 927 928 929 |
# File 'vm.c', line 919
VALUE
rb_proc_dup(VALUE self)
{
VALUE procval;
rb_proc_t *src;
GetProcPtr(self, src);
procval = proc_create(rb_cProc, &src->block, src->is_from_method, src->is_lambda);
RB_GC_GUARD(self); /* for: body = rb_proc_dup(body) */
return procval;
}
|
#hash ⇒ Integer
Returns a hash value corresponding to proc body.
See also Object#hash.
1349 1350 1351 1352 1353 1354 1355 1356 1357 |
# File 'proc.c', line 1349
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.
274 275 276 277 278 279 280 281 |
# File 'proc.c', line 274
VALUE
rb_proc_lambda_p(VALUE procval)
{
rb_proc_t *proc;
GetProcPtr(procval, proc);
return proc->is_lambda ? Qtrue : Qfalse;
}
|
#parameters ⇒ Array
Returns the parameter information of this proc.
prc = lambda{|x, y=42, *other|}
prc.parameters #=> [[:req, :x], [:opt, :y], [:rest, :other]]
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 |
# File 'proc.c', line 1290
static VALUE
rb_proc_parameters(VALUE self)
{
int is_proc;
const rb_iseq_t *iseq = rb_proc_get_iseq(self, &is_proc);
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
3526 3527 3528 3529 3530 3531 3532 3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547 3548 3549 3550 3551 3552 3553 3554 3555 3556 |
# File 'proc.c', line 3526
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 (proc->block.as.captured.code.iseq->body->param.flags.has_rest &&
!proc->block.as.captured.code.iseq->body->param.flags.has_kw &&
!proc->block.as.captured.code.iseq->body->param.flags.has_kwrest) {
proc->block.as.captured.code.iseq->body->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).
1255 1256 1257 1258 1259 |
# File 'proc.c', line 1255
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.
1415 1416 1417 1418 1419 |
# File 'proc.c', line 1415
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.
1399 1400 1401 1402 1403 1404 1405 |
# File 'proc.c', line 1399
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?.
926 927 928 929 930 |
# File 'proc.c', line 926
static VALUE
proc_call(int argc, VALUE *argv, VALUE procval)
{
/* removed */
}
|