summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-06-19 04:42:16 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-06-19 04:42:16 +0000
commitb2066b11d85fc312381b9f4bd4ff4da7cd0dd07b (patch)
tree5cfda819fe0f582bb30630994cf1617cef05abf3
parent2443fbcccfbf4c56d1bbaa2040535ad806b6e6a1 (diff)
proc.c: Implement Method#curry
* proc.c (rb_method_curry): Implement Method#curry, which delegates to to_proc.curry. [ruby-core:62212] [Feature #9783] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@46461 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog5
-rw-r--r--NEWS4
-rw-r--r--proc.c42
-rw-r--r--test/ruby/test_method.rb51
4 files changed, 101 insertions, 1 deletions
diff --git a/ChangeLog b/ChangeLog
index 8b1bbe45ed..07ee94fad8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Thu Jun 19 13:39:11 2014 Arne Brasseur <arne@arnebrasseur.net>
+
+ * 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@ruby-lang.org>
* lib/net/ftp.rb (gets, readline): read lines without LF properly.
diff --git a/NEWS b/NEWS
index f599cc2d7d..84413d99e7 100644
--- a/NEWS
+++ b/NEWS
@@ -55,6 +55,10 @@ with all sufficient information, see the ChangeLog file.
* 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
diff --git a/proc.c b/proc.c
index 48aaf863e6..befa8834cd 100644
--- a/proc.c
+++ b/proc.c
@@ -2584,7 +2584,7 @@ curry(VALUE dummy, VALUE args, int argc, VALUE *argv, VALUE passed_proc)
* 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 self)
}
/*
+ * 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)
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);
diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb
index f478e11486..9b2291ffe5 100644
--- a/test/ruby/test_method.rb
+++ b/test/ruby/test_method.rb
@@ -755,4 +755,55 @@ class TestMethod < Test::Unit::TestCase
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