[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]