Project

General

Profile

Feature #6284 ยป 0001-proc.c-Implement-Proc-for-Proc-composition.patch

mudge (Paul Mucur), 12/30/2015 12:27 PM

View differences:

proc.c
2818 2818
    return proc_curry(argc, argv, proc);
2819 2819
}
2820 2820

  
2821
static VALUE
2822
compose(VALUE dummy, VALUE args, int argc, VALUE *argv, VALUE passed_proc)
2823
{
2824
    VALUE f, g, fargs;
2825
    f = RARRAY_AREF(args, 0);
2826
    g = RARRAY_AREF(args, 1);
2827
    fargs = rb_ary_new3(1, rb_proc_call_with_block(g, argc, argv, passed_proc));
2828

  
2829
    return rb_proc_call(f, fargs);
2830
}
2831

  
2832
 /*
2833
  *  call-seq:
2834
  *     prc * g -> a_proc
2835
  *
2836
  *  Returns a proc that is the composition of this proc and the given proc <i>g</i>.
2837
  *  The returned proc takes a variable number of arguments, calls <i>g</i> with them
2838
  *  then calls this proc with the result.
2839
  *
2840
  *     f = proc {|x| x * 2 }
2841
  *     g = proc {|x, y| x + y }
2842
  *     h = f * g
2843
  *     p h.call(1, 2) #=> 6
2844
  */
2845
static VALUE
2846
proc_compose(VALUE self, VALUE g)
2847
{
2848
    VALUE proc, args;
2849
    rb_proc_t *procp;
2850
    int is_lambda;
2851

  
2852
    if (!rb_obj_is_method(g) && !rb_obj_is_proc(g)) {
2853
        rb_raise(rb_eTypeError,
2854
                "wrong argument type %s (expected Proc/Method)",
2855
                rb_obj_classname(g));
2856
    }
2857

  
2858
    if (rb_obj_is_method(g)) {
2859
        g = method_to_proc(g);
2860
    }
2861

  
2862
    args = rb_ary_new3(2, self, g);
2863

  
2864
    GetProcPtr(self, procp);
2865
    is_lambda = procp->is_lambda;
2866

  
2867
    proc = rb_proc_new(compose, args);
2868
    GetProcPtr(proc, procp);
2869
    procp->is_lambda = is_lambda;
2870

  
2871
    return proc;
2872
}
2873

  
2821 2874
/*
2822 2875
 *  Document-class: LocalJumpError
2823 2876
 *
......
2906 2959
    rb_define_method(rb_cProc, "lambda?", rb_proc_lambda_p, 0);
2907 2960
    rb_define_method(rb_cProc, "binding", proc_binding, 0);
2908 2961
    rb_define_method(rb_cProc, "curry", proc_curry, -1);
2962
    rb_define_method(rb_cProc, "*", proc_compose, 1);
2909 2963
    rb_define_method(rb_cProc, "source_location", rb_proc_location, 0);
2910 2964
    rb_define_method(rb_cProc, "parameters", rb_proc_parameters, 0);
2911 2965

  
test/ruby/test_proc.rb
1341 1341
      e.each {}
1342 1342
    EOS
1343 1343
  end
1344

  
1345
  def test_compose
1346
    f = proc{|x| x * 2}
1347
    g = proc{|x| x + 1}
1348
    h = f * g
1349

  
1350
    assert_equal(6, h.call(2))
1351
  end
1352

  
1353
  def test_compose_with_multiple_args
1354
    f = proc{|x| x * 2}
1355
    g = proc{|x, y| x + y}
1356
    h = f * g
1357

  
1358
    assert_equal(6, h.call(1, 2))
1359
  end
1360

  
1361
  def test_compose_with_block
1362
    f = proc{|x| x * 2}
1363
    g = proc{|&blk| blk.call(1) }
1364
    h = f * g
1365

  
1366
    assert_equal(8, h.call { |x| x + 3 })
1367
  end
1368

  
1369
  def test_compose_with_lambda
1370
    f = lambda{|x| x * 2}
1371
    g = lambda{|x| x}
1372
    h = f * g
1373

  
1374
    assert(h.lambda?)
1375
  end
1376

  
1377
  def test_compose_with_method
1378
    f = proc{|x| x * 2}
1379
    c = Class.new {
1380
      def g(x) x + 1 end
1381
    }
1382
    g = c.new.method(:g)
1383
    h = f * g
1384

  
1385
    assert_equal(6, h.call(2))
1386
  end
1387

  
1388
  def test_compose_with_nonproc_or_method
1389
    f = proc{|x| x * 2}
1390

  
1391
    assert_raise(TypeError) {
1392
      f * 5
1393
    }
1394
  end
1344 1395
end
1345
-