Feature #6284 ยป 0001proc.cImplementProcforProccomposition.patch
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 
* callseq: 

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 
* Documentclass: 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 
 