зеркало из https://github.com/github/ruby.git
Make Proc#parameters support lambda keyword for returning parameters as if lambda
This makes it easier to use Proc#parameters to build wrappers. Implements [Feature #15357]
This commit is contained in:
Родитель
29b68b89a0
Коммит
b6804d62f8
2
NEWS.md
2
NEWS.md
|
@ -69,6 +69,7 @@ Note: We're only listing outstanding class updates.
|
|||
|
||||
* Proc
|
||||
* Proc#dup returns an instance of subclass. [[Bug #17545]]
|
||||
* Proc#parameters now accepts lambda keyword. [[Feature #15357]]
|
||||
|
||||
* Refinement
|
||||
* Refinement#refined_class has been added. [[Feature #12737]]
|
||||
|
@ -170,6 +171,7 @@ The following deprecated APIs are removed.
|
|||
[Feature #13110]: https://bugs.ruby-lang.org/issues/13110
|
||||
[Feature #14332]: https://bugs.ruby-lang.org/issues/14332
|
||||
[Feature #15231]: https://bugs.ruby-lang.org/issues/15231
|
||||
[Feature #15357]: https://bugs.ruby-lang.org/issues/15357
|
||||
[Bug #15928]: https://bugs.ruby-lang.org/issues/15928
|
||||
[Feature #16131]: https://bugs.ruby-lang.org/issues/16131
|
||||
[Feature #16806]: https://bugs.ruby-lang.org/issues/16806
|
||||
|
|
39
proc.c
39
proc.c
|
@ -1415,19 +1415,46 @@ rb_unnamed_parameters(int arity)
|
|||
|
||||
/*
|
||||
* call-seq:
|
||||
* prc.parameters -> array
|
||||
* prc.parameters(lambda: nil) -> array
|
||||
*
|
||||
* Returns the parameter information of this proc.
|
||||
* 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(lamdba: false) #=> [[:opt, :x], [:opt, :y], [:rest, :other]]
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_proc_parameters(VALUE self)
|
||||
rb_proc_parameters(int argc, VALUE *argv, VALUE self)
|
||||
{
|
||||
int is_proc;
|
||||
const rb_iseq_t *iseq = rb_proc_get_iseq(self, &is_proc);
|
||||
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));
|
||||
}
|
||||
|
@ -4248,7 +4275,7 @@ Init_Proc(void)
|
|||
rb_define_method(rb_cProc, "==", proc_eq, 1);
|
||||
rb_define_method(rb_cProc, "eql?", proc_eq, 1);
|
||||
rb_define_method(rb_cProc, "source_location", rb_proc_location, 0);
|
||||
rb_define_method(rb_cProc, "parameters", rb_proc_parameters, 0);
|
||||
rb_define_method(rb_cProc, "parameters", rb_proc_parameters, -1);
|
||||
rb_define_method(rb_cProc, "ruby2_keywords", proc_ruby2_keywords, 0);
|
||||
// rb_define_method(rb_cProc, "isolate", rb_proc_isolate, 0); is not accepted.
|
||||
|
||||
|
|
|
@ -20,6 +20,21 @@ describe "Proc#parameters" do
|
|||
proc {|x| }.parameters.first.first.should == :opt
|
||||
end
|
||||
|
||||
ruby_version_is "3.2" do
|
||||
it "sets the first element of each sub-Array to :req if argument would be required if a lambda if lambda keyword used" do
|
||||
proc {|x| }.parameters(lambda: true).first.first.should == :req
|
||||
proc {|y,*x| }.parameters(lambda: true).first.first.should == :req
|
||||
end
|
||||
|
||||
it "regards named parameters in procs as required if lambda keyword used" do
|
||||
proc {|x| }.parameters(lambda: true).first.first.should == :req
|
||||
end
|
||||
|
||||
it "regards named parameters in lambda as optional if lambda: false keyword used" do
|
||||
lambda {|x| }.parameters(lambda: false).first.first.should == :opt
|
||||
end
|
||||
end
|
||||
|
||||
it "regards optional keyword parameters in procs as optional" do
|
||||
proc {|x: :y| }.parameters.first.first.should == :key
|
||||
end
|
||||
|
|
|
@ -1234,6 +1234,28 @@ class TestProc < Test::Unit::TestCase
|
|||
assert_empty(pr.parameters.map{|_,n|n}.compact)
|
||||
end
|
||||
|
||||
def test_parameters_lambda
|
||||
assert_equal([], proc {}.parameters(lambda: true))
|
||||
assert_equal([], proc {||}.parameters(lambda: true))
|
||||
assert_equal([[:req, :a]], proc {|a|}.parameters(lambda: true))
|
||||
assert_equal([[:req, :a], [:req, :b]], proc {|a, b|}.parameters(lambda: true))
|
||||
assert_equal([[:opt, :a], [:block, :b]], proc {|a=:a, &b|}.parameters(lambda: true))
|
||||
assert_equal([[:req, :a], [:opt, :b]], proc {|a, b=:b|}.parameters(lambda: true))
|
||||
assert_equal([[:rest, :a]], proc {|*a|}.parameters(lambda: true))
|
||||
assert_equal([[:req, :a], [:rest, :b], [:block, :c]], proc {|a, *b, &c|}.parameters(lambda: true))
|
||||
assert_equal([[:req, :a], [:rest, :b], [:req, :c]], proc {|a, *b, c|}.parameters(lambda: true))
|
||||
assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], proc {|a, *b, c, &d|}.parameters(lambda: true))
|
||||
assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], proc {|a, b=:b, *c, d, &e|}.parameters(lambda: true))
|
||||
assert_equal([[:req], [:block, :b]], proc {|(a), &b|a}.parameters(lambda: true))
|
||||
assert_equal([[:req, :a], [:req, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:req, :f], [:req, :g], [:block, :h]], proc {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters(lambda: true))
|
||||
|
||||
pr = eval("proc{|"+"(_),"*30+"|}")
|
||||
assert_empty(pr.parameters(lambda: true).map{|_,n|n}.compact)
|
||||
|
||||
assert_equal([[:opt, :a]], lambda {|a|}.parameters(lambda: false))
|
||||
assert_equal([[:opt, :a], [:opt, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:opt, :f], [:opt, :g], [:block, :h]], lambda {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters(lambda: false))
|
||||
end
|
||||
|
||||
def pm0() end
|
||||
def pm1(a) end
|
||||
def pm2(a, b) end
|
||||
|
|
Загрузка…
Ссылка в новой задаче