Proc#<< and Proc#>>
[Feature #6284] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65914 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
3b7b70650c
commit
c71cc2db7f
10
NEWS
10
NEWS
@ -171,6 +171,12 @@ sufficient information, see the ChangeLog file or Redmine
|
|||||||
* KeyError.new accepts +:receiver+ and +:key+ options to set receiver and
|
* KeyError.new accepts +:receiver+ and +:key+ options to set receiver and
|
||||||
key in Ruby code. [Feature #14313]
|
key in Ruby code. [Feature #14313]
|
||||||
|
|
||||||
|
[Method]
|
||||||
|
|
||||||
|
[New methods]
|
||||||
|
|
||||||
|
* added Method#<< and Method#>> for Proc composition. [Feature #6284]
|
||||||
|
|
||||||
[Module]
|
[Module]
|
||||||
|
|
||||||
[New methods]
|
[New methods]
|
||||||
@ -203,6 +209,10 @@ sufficient information, see the ChangeLog file or Redmine
|
|||||||
|
|
||||||
[Proc]
|
[Proc]
|
||||||
|
|
||||||
|
[New methods]
|
||||||
|
|
||||||
|
* added Proc#<< and Proc#>> for Proc composition. [Feature #6284]
|
||||||
|
|
||||||
[Incompatible changes]
|
[Incompatible changes]
|
||||||
|
|
||||||
* Proc#call doesn't change <code>$SAFE</code> any more. [Feature #14250]
|
* Proc#call doesn't change <code>$SAFE</code> any more. [Feature #14250]
|
||||||
|
95
proc.c
95
proc.c
@ -3052,14 +3052,21 @@ compose(VALUE dummy, VALUE args, int argc, VALUE *argv, VALUE passed_proc)
|
|||||||
VALUE f, g, fargs;
|
VALUE f, g, fargs;
|
||||||
f = RARRAY_AREF(args, 0);
|
f = RARRAY_AREF(args, 0);
|
||||||
g = RARRAY_AREF(args, 1);
|
g = RARRAY_AREF(args, 1);
|
||||||
fargs = rb_ary_new3(1, rb_funcall_with_block(g, idCall, argc, argv, passed_proc));
|
|
||||||
|
|
||||||
return rb_proc_call(f, fargs);
|
if (rb_obj_is_proc(g))
|
||||||
|
fargs = rb_proc_call_with_block(g, argc, argv, passed_proc);
|
||||||
|
else
|
||||||
|
fargs = rb_funcall_with_block(g, idCall, argc, argv, passed_proc);
|
||||||
|
|
||||||
|
if (rb_obj_is_proc(f))
|
||||||
|
return rb_proc_call(f, rb_ary_new3(1, fargs));
|
||||||
|
else
|
||||||
|
return rb_funcallv(f, idCall, 1, &fargs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* prc * g -> a_proc
|
* prc << g -> a_proc
|
||||||
*
|
*
|
||||||
* Returns a proc that is the composition of this proc and the given <i>g</i>.
|
* Returns a proc that is the composition of this proc and the given <i>g</i>.
|
||||||
* The returned proc takes a variable number of arguments, calls <i>g</i> with them
|
* The returned proc takes a variable number of arguments, calls <i>g</i> with them
|
||||||
@ -3067,17 +3074,19 @@ compose(VALUE dummy, VALUE args, int argc, VALUE *argv, VALUE passed_proc)
|
|||||||
*
|
*
|
||||||
* f = proc {|x| x * 2 }
|
* f = proc {|x| x * 2 }
|
||||||
* g = proc {|x, y| x + y }
|
* g = proc {|x, y| x + y }
|
||||||
* h = f * g
|
* h = f << g
|
||||||
* p h.call(1, 2) #=> 6
|
* p h.call(1, 2) #=> 6
|
||||||
*/
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
proc_compose(VALUE self, VALUE g)
|
proc_compose_to_left(VALUE self, VALUE g)
|
||||||
{
|
{
|
||||||
VALUE proc, args;
|
VALUE proc, args, procs[2];
|
||||||
rb_proc_t *procp;
|
rb_proc_t *procp;
|
||||||
int is_lambda;
|
int is_lambda;
|
||||||
|
|
||||||
args = rb_ary_new3(2, self, g);
|
procs[0] = self;
|
||||||
|
procs[1] = g;
|
||||||
|
args = rb_ary_tmp_new_from_values(0, 2, procs);
|
||||||
|
|
||||||
GetProcPtr(self, procp);
|
GetProcPtr(self, procp);
|
||||||
is_lambda = procp->is_lambda;
|
is_lambda = procp->is_lambda;
|
||||||
@ -3091,7 +3100,41 @@ proc_compose(VALUE self, VALUE g)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* meth * g -> a_proc
|
* prc >> g -> a_proc
|
||||||
|
*
|
||||||
|
* Returns a proc that is the composition of this proc and the given <i>g</i>.
|
||||||
|
* The returned proc takes a variable number of arguments, calls <i>g</i> with them
|
||||||
|
* then calls this proc with the result.
|
||||||
|
*
|
||||||
|
* f = proc {|x, y| x + y }
|
||||||
|
* g = proc {|x| x * 2 }
|
||||||
|
* h = f >> g
|
||||||
|
* p h.call(1, 2) #=> 6
|
||||||
|
*/
|
||||||
|
static VALUE
|
||||||
|
proc_compose_to_right(VALUE self, VALUE g)
|
||||||
|
{
|
||||||
|
VALUE proc, args, procs[2];
|
||||||
|
rb_proc_t *procp;
|
||||||
|
int is_lambda;
|
||||||
|
|
||||||
|
procs[0] = g;
|
||||||
|
procs[1] = self;
|
||||||
|
args = rb_ary_tmp_new_from_values(0, 2, procs);
|
||||||
|
|
||||||
|
GetProcPtr(self, procp);
|
||||||
|
is_lambda = procp->is_lambda;
|
||||||
|
|
||||||
|
proc = rb_proc_new(compose, args);
|
||||||
|
GetProcPtr(proc, procp);
|
||||||
|
procp->is_lambda = is_lambda;
|
||||||
|
|
||||||
|
return proc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* meth << g -> a_proc
|
||||||
*
|
*
|
||||||
* Returns a proc that is the composition of this method and the given <i>g</i>.
|
* Returns a proc that is the composition of this method and the given <i>g</i>.
|
||||||
* The returned proc takes a variable number of arguments, calls <i>g</i> with them
|
* The returned proc takes a variable number of arguments, calls <i>g</i> with them
|
||||||
@ -3103,14 +3146,38 @@ proc_compose(VALUE self, VALUE g)
|
|||||||
*
|
*
|
||||||
* f = self.method(:f)
|
* f = self.method(:f)
|
||||||
* g = proc {|x, y| x + y }
|
* g = proc {|x, y| x + y }
|
||||||
* h = f * g
|
* h = f << g
|
||||||
* p h.call(1, 2) #=> 6
|
* p h.call(1, 2) #=> 6
|
||||||
*/
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_method_compose(VALUE self, VALUE g)
|
rb_method_compose_to_left(VALUE self, VALUE g)
|
||||||
{
|
{
|
||||||
VALUE proc = method_to_proc(self);
|
VALUE proc = method_to_proc(self);
|
||||||
return proc_compose(proc, g);
|
return proc_compose_to_left(proc, g);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* call-seq:
|
||||||
|
* meth >> g -> a_proc
|
||||||
|
*
|
||||||
|
* Returns a proc that is the composition of this method and the given <i>g</i>.
|
||||||
|
* The returned proc takes a variable number of arguments, calls <i>g</i> with them
|
||||||
|
* then calls this method with the result.
|
||||||
|
*
|
||||||
|
* def f(x, y)
|
||||||
|
* x + y
|
||||||
|
* end
|
||||||
|
*
|
||||||
|
* f = self.method(:f)
|
||||||
|
* g = proc {|x| x * 2 }
|
||||||
|
* h = f >> g
|
||||||
|
* p h.call(1, 2) #=> 6
|
||||||
|
*/
|
||||||
|
static VALUE
|
||||||
|
rb_method_compose_to_right(VALUE self, VALUE g)
|
||||||
|
{
|
||||||
|
VALUE proc = method_to_proc(self);
|
||||||
|
return proc_compose_to_right(proc, g);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3209,7 +3276,8 @@ Init_Proc(void)
|
|||||||
rb_define_method(rb_cProc, "lambda?", rb_proc_lambda_p, 0);
|
rb_define_method(rb_cProc, "lambda?", rb_proc_lambda_p, 0);
|
||||||
rb_define_method(rb_cProc, "binding", proc_binding, 0);
|
rb_define_method(rb_cProc, "binding", proc_binding, 0);
|
||||||
rb_define_method(rb_cProc, "curry", proc_curry, -1);
|
rb_define_method(rb_cProc, "curry", proc_curry, -1);
|
||||||
rb_define_method(rb_cProc, "*", proc_compose, 1);
|
rb_define_method(rb_cProc, "<<", proc_compose_to_left, 1);
|
||||||
|
rb_define_method(rb_cProc, ">>", proc_compose_to_right, 1);
|
||||||
rb_define_method(rb_cProc, "source_location", rb_proc_location, 0);
|
rb_define_method(rb_cProc, "source_location", rb_proc_location, 0);
|
||||||
rb_define_method(rb_cProc, "parameters", rb_proc_parameters, 0);
|
rb_define_method(rb_cProc, "parameters", rb_proc_parameters, 0);
|
||||||
|
|
||||||
@ -3236,7 +3304,8 @@ Init_Proc(void)
|
|||||||
rb_define_method(rb_cMethod, "call", rb_method_call, -1);
|
rb_define_method(rb_cMethod, "call", rb_method_call, -1);
|
||||||
rb_define_method(rb_cMethod, "===", rb_method_call, -1);
|
rb_define_method(rb_cMethod, "===", rb_method_call, -1);
|
||||||
rb_define_method(rb_cMethod, "curry", rb_method_curry, -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_compose_to_left, 1);
|
||||||
|
rb_define_method(rb_cMethod, ">>", rb_method_compose_to_right, 1);
|
||||||
rb_define_method(rb_cMethod, "[]", rb_method_call, -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, "arity", method_arity_m, 0);
|
||||||
rb_define_method(rb_cMethod, "inspect", method_inspect, 0);
|
rb_define_method(rb_cMethod, "inspect", method_inspect, 0);
|
||||||
|
@ -1048,9 +1048,9 @@ class TestMethod < Test::Unit::TestCase
|
|||||||
}
|
}
|
||||||
f = c.new.method(:f)
|
f = c.new.method(:f)
|
||||||
g = c.new.method(:g)
|
g = c.new.method(:g)
|
||||||
h = f * g
|
|
||||||
|
|
||||||
assert_equal(6, h.call(2))
|
assert_equal(6, (f << g).call(2))
|
||||||
|
assert_equal(6, (g >> f).call(2))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compose_with_proc
|
def test_compose_with_proc
|
||||||
@ -1059,9 +1059,9 @@ class TestMethod < Test::Unit::TestCase
|
|||||||
}
|
}
|
||||||
f = c.new.method(:f)
|
f = c.new.method(:f)
|
||||||
g = proc {|x| x + 1}
|
g = proc {|x| x + 1}
|
||||||
h = f * g
|
|
||||||
|
|
||||||
assert_equal(6, h.call(2))
|
assert_equal(6, (f << g).call(2))
|
||||||
|
assert_equal(6, (g >> f).call(2))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compose_with_callable
|
def test_compose_with_callable
|
||||||
@ -1072,9 +1072,10 @@ class TestMethod < Test::Unit::TestCase
|
|||||||
def call(x) x + 1 end
|
def call(x) x + 1 end
|
||||||
}
|
}
|
||||||
f = c.new.method(:f)
|
f = c.new.method(:f)
|
||||||
g = f * c2.new
|
g = c2.new
|
||||||
|
|
||||||
assert_equal(6, g.call(2))
|
assert_equal(6, (f << g).call(2))
|
||||||
|
assert_equal(5, (f >> g).call(2))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compose_with_noncallable
|
def test_compose_with_noncallable
|
||||||
@ -1082,10 +1083,12 @@ class TestMethod < Test::Unit::TestCase
|
|||||||
def f(x) x * 2 end
|
def f(x) x * 2 end
|
||||||
}
|
}
|
||||||
f = c.new.method(:f)
|
f = c.new.method(:f)
|
||||||
g = f * 5
|
|
||||||
|
|
||||||
assert_raise(NoMethodError) {
|
assert_raise(NoMethodError) {
|
||||||
g.call(2)
|
(f << 5).call(2)
|
||||||
|
}
|
||||||
|
assert_raise(NoMethodError) {
|
||||||
|
(f >> 5).call(2)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1420,33 +1420,33 @@ class TestProc < Test::Unit::TestCase
|
|||||||
def test_compose
|
def test_compose
|
||||||
f = proc {|x| x * 2}
|
f = proc {|x| x * 2}
|
||||||
g = proc {|x| x + 1}
|
g = proc {|x| x + 1}
|
||||||
h = f * g
|
|
||||||
|
|
||||||
assert_equal(6, h.call(2))
|
assert_equal(6, (f << g).call(2))
|
||||||
|
assert_equal(6, (g >> f).call(2))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compose_with_multiple_args
|
def test_compose_with_multiple_args
|
||||||
f = proc {|x| x * 2}
|
f = proc {|x| x * 2}
|
||||||
g = proc {|x, y| x + y}
|
g = proc {|x, y| x + y}
|
||||||
h = f * g
|
|
||||||
|
|
||||||
assert_equal(6, h.call(1, 2))
|
assert_equal(6, (f << g).call(1, 2))
|
||||||
|
assert_equal(6, (g >> f).call(1, 2))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compose_with_block
|
def test_compose_with_block
|
||||||
f = proc {|x| x * 2}
|
f = proc {|x| x * 2}
|
||||||
g = proc {|&blk| blk.call(1) }
|
g = proc {|&blk| blk.call(1) }
|
||||||
h = f * g
|
|
||||||
|
|
||||||
assert_equal(8, h.call { |x| x + 3 })
|
assert_equal(8, (f << g).call { |x| x + 3 })
|
||||||
|
assert_equal(8, (g >> f).call { |x| x + 3 })
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compose_with_lambda
|
def test_compose_with_lambda
|
||||||
f = lambda {|x| x * 2}
|
f = lambda {|x| x * 2}
|
||||||
g = lambda {|x| x}
|
g = lambda {|x| x}
|
||||||
h = f * g
|
|
||||||
|
|
||||||
assert_predicate(h, :lambda?)
|
assert_predicate((f << g), :lambda?)
|
||||||
|
assert_predicate((g >> f), :lambda?)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compose_with_method
|
def test_compose_with_method
|
||||||
@ -1455,9 +1455,9 @@ class TestProc < Test::Unit::TestCase
|
|||||||
def g(x) x + 1 end
|
def g(x) x + 1 end
|
||||||
}
|
}
|
||||||
g = c.new.method(:g)
|
g = c.new.method(:g)
|
||||||
h = f * g
|
|
||||||
|
|
||||||
assert_equal(6, h.call(2))
|
assert_equal(6, (f << g).call(2))
|
||||||
|
assert_equal(5, (f >> g).call(2))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compose_with_callable
|
def test_compose_with_callable
|
||||||
@ -1465,17 +1465,20 @@ class TestProc < Test::Unit::TestCase
|
|||||||
c = Class.new {
|
c = Class.new {
|
||||||
def call(x) x + 1 end
|
def call(x) x + 1 end
|
||||||
}
|
}
|
||||||
g = f * c.new
|
g = c.new
|
||||||
|
|
||||||
assert_equal(6, g.call(2))
|
assert_equal(6, (f << g).call(2))
|
||||||
|
assert_equal(5, (f >> g).call(2))
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_compose_with_noncallable
|
def test_compose_with_noncallable
|
||||||
f = proc {|x| x * 2}
|
f = proc {|x| x * 2}
|
||||||
g = f * 5
|
|
||||||
|
|
||||||
assert_raise(NoMethodError) {
|
assert_raise(NoMethodError) {
|
||||||
g.call(2)
|
(f << 5).call(2)
|
||||||
|
}
|
||||||
|
assert_raise(NoMethodError) {
|
||||||
|
(f >> 5).call(2)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user