From 0e7bc6d765e3b13c4a00de6a0fa0f16f27115634 Mon Sep 17 00:00:00 2001 From: Paul Mucur Date: Sun, 14 Jun 2015 17:24:04 +0100 Subject: [PATCH 2/3] proc.c: Implement Method#* for Method composition * proc.c (rb_method_compose): Implement Method#* for Method composition, which delegates to Proc#*. * test/ruby/test_method.rb: Add test cases for Method composition. --- proc.c | 25 +++++++++++++++++++++++++ test/ruby/test_method.rb | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/proc.c b/proc.c index c73fcf1..9f68829 100644 --- a/proc.c +++ b/proc.c @@ -2871,6 +2871,30 @@ proc_compose(VALUE self, VALUE g) return proc; } + /* + * call-seq: + * meth * g -> a_proc + * + * Returns a proc that is the composition of this method and the given proc g. + * The returned proc takes a variable number of arguments, calls g with them + * then calls this method with the result. + * + * def f(x) + * x * 2 + * end + * + * f = self.method(:f) + * g = proc {|x, y| x + y } + * h = f * g + * p h.call(1, 2) #=> 6 + */ +static VALUE +rb_method_compose(VALUE self, VALUE g) +{ + VALUE proc = method_to_proc(self); + return proc_compose(proc, g); +} + /* * Document-class: LocalJumpError * @@ -2985,6 +3009,7 @@ Init_Proc(void) rb_define_method(rb_cMethod, "clone", method_clone, 0); rb_define_method(rb_cMethod, "call", rb_method_call, -1); rb_define_method(rb_cMethod, "curry", rb_method_curry, -1); + rb_define_method(rb_cMethod, "*", rb_method_compose, 1); rb_define_method(rb_cMethod, "[]", rb_method_call, -1); rb_define_method(rb_cMethod, "arity", method_arity_m, 0); rb_define_method(rb_cMethod, "inspect", method_inspect, 0); diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb index 1e5f054..739dbbb 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -953,4 +953,38 @@ def test_define_method_with_symbol assert_equal('1', obj.foo(1)) assert_equal('1', obj.bar(1)) end + + def test_compose_with_method + c = Class.new { + def f(x) x * 2 end + def g(x) x + 1 end + } + f = c.new.method(:f) + g = c.new.method(:g) + h = f * g + + assert_equal(6, h.call(2)) + end + + def test_compose_with_proc + c = Class.new { + def f(x) x * 2 end + } + f = c.new.method(:f) + g = proc{|x| x + 1} + h = f * g + + assert_equal(6, h.call(2)) + end + + def test_compose_with_nonproc_or_method + c = Class.new { + def f(x) x * 2 end + } + f = c.new.method(:f) + + assert_raise(TypeError) { + f * 5 + } + end end -- 2.6.4