ruby-changes:34380
From: nobu <ko1@a...>
Date: Thu, 19 Jun 2014 13:42:31 +0900 (JST)
Subject: [ruby-changes:34380] nobu:r46461 (trunk): proc.c: Implement Method#curry
nobu 2014-06-19 13:42:16 +0900 (Thu, 19 Jun 2014) New Revision: 46461 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=46461 Log: proc.c: Implement Method#curry * proc.c (rb_method_curry): Implement Method#curry, which delegates to to_proc.curry. [ruby-core:62212] [Feature #9783] Modified files: trunk/ChangeLog trunk/NEWS trunk/proc.c trunk/test/ruby/test_method.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 46460) +++ ChangeLog (revision 46461) @@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Thu Jun 19 13:39:11 2014 Arne Brasseur <arne@a...> + + * proc.c (rb_method_curry): Implement Method#curry, which delegates + to to_proc.curry. [ruby-core:62212] [Feature #9783] + Tue Jun 17 16:41:49 2014 Shugo Maeda <shugo@r...> * lib/net/ftp.rb (gets, readline): read lines without LF properly. Index: proc.c =================================================================== --- proc.c (revision 46460) +++ proc.c (revision 46461) @@ -2584,7 +2584,7 @@ curry(VALUE dummy, VALUE args, int argc, https://github.com/ruby/ruby/blob/trunk/proc.c#L2584 * p b.curry[] #=> :foo */ static VALUE -proc_curry(int argc, VALUE *argv, VALUE self) +proc_curry(int argc, const VALUE *argv, VALUE self) { int sarity, max_arity, min_arity = rb_proc_min_max_arity(self, &max_arity); VALUE arity; @@ -2604,6 +2604,45 @@ proc_curry(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/proc.c#L2604 } /* + * call-seq: + * meth.curry -> proc + * meth.curry(arity) -> proc + * + * Returns a curried proc based on the method. When the proc is called with a number of + * arguments that is lower than the method's arity, then another curried proc is returned. + * Only when enough arguments have been supplied to satisfy the method signature, will the + * method actually be called. + * + * The optional <i>arity</i> argument should be supplied when currying methods with + * variable arguments to determine how many arguments are needed before the method is + * called. + * + * def foo(a,b,c) + * [a, b, c] + * end + * + * proc = self.method(:foo).curry + * proc2 = proc.call(1, 2) #=> #<Proc> + * proc2.call(3) #=> [1,2,3] + * + * def vararg(*args) + * args + * end + * + * proc = self.method(:vararg).curry(4) + * proc2 = proc.call(:x) #=> #<Proc> + * proc3 = proc2.call(:y, :z) #=> #<Proc> + * proc3.call(:a) #=> [:x, :y, :z, :a] + */ + +static VALUE +rb_method_curry(int argc, const VALUE *argv, VALUE self) +{ + VALUE proc = method_proc(self); + return proc_curry(argc, argv, proc); +} + +/* * Document-class: LocalJumpError * * Raised when Ruby can't yield as requested. @@ -2723,6 +2762,7 @@ Init_Proc(void) https://github.com/ruby/ruby/blob/trunk/proc.c#L2762 rb_define_method(rb_cMethod, "hash", method_hash, 0); 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_call, -1); rb_define_method(rb_cMethod, "arity", method_arity_m, 0); rb_define_method(rb_cMethod, "inspect", method_inspect, 0); Index: NEWS =================================================================== --- NEWS (revision 46460) +++ NEWS (revision 46461) @@ -55,6 +55,10 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L55 * Matrix#cofactor(row, column) returns the (row, column) cofactor which is obtained by multiplying the first minor by (-1)**(row + column). +* Method + * New methods: + * Method#curry([arity]) returns a curried Proc. + === Core classes compatibility issues (excluding feature bug fixes) * IO Index: test/ruby/test_method.rb =================================================================== --- test/ruby/test_method.rb (revision 46460) +++ test/ruby/test_method.rb (revision 46461) @@ -755,4 +755,55 @@ class TestMethod < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_method.rb#L755 m = assert_nothing_raised(NameError, feature8391) {break o.singleton_method(:bar)} assert_equal(:bar, m.call, feature8391) end + + Feature9783 = '[ruby-core:62212] [Feature #9783]' + + def assert_curry_three_args(m) + curried = m.curry + assert_equal(6, curried.(1).(2).(3), Feature9783) + + curried = m.curry(3) + assert_equal(6, curried.(1).(2).(3), Feature9783) + + assert_raise_with_message(ArgumentError, /wrong number/) {m.curry(2)} + end + + def test_curry_method + c = Class.new { + def three_args(a,b,c) a + b + c end + } + assert_curry_three_args(c.new.method(:three_args)) + end + + def test_curry_from_proc + c = Class.new { + define_method(:three_args) {|a,b,c| a + b + c} + } + assert_curry_three_args(c.new.method(:three_args)) + end + + def assert_curry_var_args(m) + curried = m.curry(3) + assert_equal([1, 2, 3], curried.(1).(2).(3), Feature9783) + + curried = m.curry(2) + assert_equal([1, 2], curried.(1).(2), Feature9783) + + curried = m.curry(0) + assert_equal([1], curried.(1), Feature9783) + end + + def test_curry_var_args + c = Class.new { + def var_args(*args) args end + } + assert_curry_var_args(c.new.method(:var_args)) + end + + def test_curry_from_proc_var_args + c = Class.new { + define_method(:var_args) {|*args| args} + } + assert_curry_var_args(c.new.method(:var_args)) + end end -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/