Project

General

Profile

Feature #15357 ยป proc-parameters-req-15357.patch

jeremyevans0 (Jeremy Evans), 08/28/2019 02:11 AM

View differences:

proc.c
1220 1220
/*
1221 1221
 * call-seq:
1222 1222
 *    prc.parameters  -> array
1223
 *    prc.parameters(lambda: true)  -> array
1223 1224
 *
1224
 * Returns the parameter information of this proc.
1225
 * Returns the parameter information of this proc.  If the lambda
1226
 * keyword is provided, treats the proc as a lambda if true and
1227
 * as a non-lambda if false.
1225 1228
 *
1229
 *    prc = proc{|x, y=42, *other|}
1230
 *    prc.parameters  #=> [[:opt, :x], [:opt, :y], [:rest, :other]]
1226 1231
 *    prc = lambda{|x, y=42, *other|}
1227 1232
 *    prc.parameters  #=> [[:req, :x], [:opt, :y], [:rest, :other]]
1233
 *    prc = proc{|x, y=42, *other|}
1234
 *    prc.parameters(lambda: true)  #=> [[:req, :x], [:opt, :y], [:rest, :other]]
1228 1235
 */
1229 1236

  
1230 1237
static VALUE
1231
rb_proc_parameters(VALUE self)
1238
rb_proc_parameters(int argc, VALUE *argv, VALUE self)
1232 1239
{
1233
    int is_proc;
1234
    const rb_iseq_t *iseq = rb_proc_get_iseq(self, &is_proc);
1240
    static ID keyword_ids[1];
1241
    VALUE opt, lambda;
1242
    VALUE kwargs[1];
1243
    int is_proc ;
1244
    const rb_iseq_t *iseq;
1245

  
1246
    iseq = rb_proc_get_iseq(self, &is_proc);
1247

  
1248
    if (!keyword_ids[0]) {
1249
        CONST_ID(keyword_ids[0], "lambda");
1250
    }
1251

  
1252
    rb_scan_args(argc, argv, "0:", &opt);
1253
    if (!NIL_P(opt)) {
1254
        rb_get_kwargs(opt, keyword_ids, 0, 1, kwargs);
1255
        lambda = kwargs[0];
1256
        if (!NIL_P(lambda)) {
1257
            is_proc = !RTEST(lambda);
1258
        }
1259
    }
1260

  
1235 1261
    if (!iseq) {
1236 1262
	return rb_unnamed_parameters(rb_proc_arity(self));
1237 1263
    }
......
3612 3638
    rb_define_method(rb_cProc, "<<", proc_compose_to_left, 1);
3613 3639
    rb_define_method(rb_cProc, ">>", proc_compose_to_right, 1);
3614 3640
    rb_define_method(rb_cProc, "source_location", rb_proc_location, 0);
3615
    rb_define_method(rb_cProc, "parameters", rb_proc_parameters, 0);
3641
    rb_define_method(rb_cProc, "parameters", rb_proc_parameters, -1);
3616 3642

  
3617 3643
    /* Exceptions */
3618 3644
    rb_eLocalJumpError = rb_define_class("LocalJumpError", rb_eStandardError);
spec/ruby/core/proc/parameters_spec.rb
20 20
    proc {|x| }.parameters.first.first.should == :opt
21 21
  end
22 22

  
23
  ruby_version_is "2.7" do
24
    it "sets the first element of each sub-Array to :req if argument would be required if a lambda if lambda keyword used" do
25
      proc {|x| }.parameters(lambda: true).first.first.should == :req
26
      proc {|y,*x| }.parameters(lambda: true).first.first.should == :req
27
    end
28

  
29
    it "regards named parameters in procs as required if lambda keyword used" do
30
      proc {|x| }.parameters(lambda: true).first.first.should == :req
31
    end
32
  end
33

  
23 34
  it "regards optional keyword parameters in procs as optional" do
24 35
    proc {|x: :y| }.parameters.first.first.should == :key
25 36
  end
test/ruby/test_proc.rb
1142 1142
    assert_empty(pr.parameters.map{|_,n|n}.compact)
1143 1143
  end
1144 1144

  
1145
  def test_parameters_lambda
1146
    assert_equal([], proc {}.parameters(lambda: true))
1147
    assert_equal([], proc {||}.parameters(lambda: true))
1148
    assert_equal([[:req, :a]], proc {|a|}.parameters(lambda: true))
1149
    assert_equal([[:req, :a], [:req, :b]], proc {|a, b|}.parameters(lambda: true))
1150
    assert_equal([[:opt, :a], [:block, :b]], proc {|a=:a, &b|}.parameters(lambda: true))
1151
    assert_equal([[:req, :a], [:opt, :b]], proc {|a, b=:b|}.parameters(lambda: true))
1152
    assert_equal([[:rest, :a]], proc {|*a|}.parameters(lambda: true))
1153
    assert_equal([[:req, :a], [:rest, :b], [:block, :c]], proc {|a, *b, &c|}.parameters(lambda: true))
1154
    assert_equal([[:req, :a], [:rest, :b], [:req, :c]], proc {|a, *b, c|}.parameters(lambda: true))
1155
    assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], proc {|a, *b, c, &d|}.parameters(lambda: true))
1156
    assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], proc {|a, b=:b, *c, d, &e|}.parameters(lambda: true))
1157
    assert_equal([[:req], [:block, :b]], proc {|(a), &b|a}.parameters(lambda: true))
1158
    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))
1159

  
1160
    pr = eval("proc{|"+"(_),"*30+"|}")
1161
    assert_empty(pr.parameters(lambda: true).map{|_,n|n}.compact)
1162
  end
1163

  
1145 1164
  def pm0() end
1146 1165
  def pm1(a) end
1147 1166
  def pm2(a, b) end