ruby-changes:55004
From: knu <ko1@a...>
Date: Mon, 11 Mar 2019 18:49:20 +0900 (JST)
Subject: [ruby-changes:55004] knu:r67211 (trunk): Implement Enumerator::Yielder#to_proc
knu 2019-03-11 18:49:14 +0900 (Mon, 11 Mar 2019) New Revision: 67211 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=67211 Log: Implement Enumerator::Yielder#to_proc A Yielder object can now be directly passed to another method as a block argument. ```ruby enum = Enumerator.new { |y| Dir.glob("*.rb") { |file| File.open(file) { |f| f.each_line(&y) } } } ``` Modified files: trunk/enumerator.c trunk/test/ruby/test_enumerator.rb Index: test/ruby/test_enumerator.rb =================================================================== --- test/ruby/test_enumerator.rb (revision 67210) +++ test/ruby/test_enumerator.rb (revision 67211) @@ -493,6 +493,21 @@ class TestEnumerator < Test::Unit::TestC https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enumerator.rb#L493 assert_equal([1, 2, 3], y.yield(2, 3)) assert_raise(LocalJumpError) { Enumerator::Yielder.new } + + # to_proc (explicit) + a = [] + y = Enumerator::Yielder.new {|x| a << x } + b = y.to_proc + assert_kind_of(Proc, b) + assert_equal([1], b.call(1)) + assert_equal([1], a) + + # to_proc (implicit) + e = Enumerator.new { |y| + assert_kind_of(Enumerator::Yielder, y) + [1, 2, 3].each(&y) + } + assert_equal([1, 2, 3], e.to_a) end def test_size Index: enumerator.c =================================================================== --- enumerator.c (revision 67210) +++ enumerator.c (revision 67211) @@ -110,8 +110,8 @@ VALUE rb_cEnumerator; https://github.com/ruby/ruby/blob/trunk/enumerator.c#L110 static VALUE rb_cLazy; static ID id_rewind, id_new, id_to_enum; static ID id_next, id_result, id_receiver, id_arguments, id_memo, id_method, id_force; -static ID id_begin, id_end, id_step, id_exclude_end; -static VALUE sym_each, sym_cycle; +static ID id_begin, id_end, id_step, id_exclude_end, id_to_proc; +static VALUE sym_each, sym_cycle, sym_yield; #define id_call idCall #define id_each idEach @@ -1288,6 +1288,26 @@ yielder_yield_push(VALUE obj, VALUE arg) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L1288 return obj; } +/* + * Returns a Proc object that takes an argument and yields it. + * + * This method is implemented so that a Yielder object can be directly + * passed to another method as a block argument. + * + * enum = Enumerator.new { |y| + * Dir.glob("*.rb") { |file| + * File.open(file) { |f| f.each_line(&y) } + * } + * } + */ +static VALUE +yielder_to_proc(VALUE obj) +{ + VALUE method = rb_obj_method(obj, sym_yield); + + return rb_funcall(method, id_to_proc, 0); +} + static VALUE yielder_yield_i(RB_BLOCK_CALL_FUNC_ARGLIST(obj, memo)) { @@ -3380,6 +3400,7 @@ InitVM_Enumerator(void) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L3400 rb_define_method(rb_cYielder, "initialize", yielder_initialize, 0); rb_define_method(rb_cYielder, "yield", yielder_yield, -2); rb_define_method(rb_cYielder, "<<", yielder_yield_push, 1); + rb_define_method(rb_cYielder, "to_proc", yielder_to_proc, 0); /* Chain */ rb_cEnumChain = rb_define_class_under(rb_cEnumerator, "Chain", rb_cEnumerator); @@ -3430,8 +3451,10 @@ Init_Enumerator(void) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L3451 id_end = rb_intern("end"); id_step = rb_intern("step"); id_exclude_end = rb_intern("exclude_end"); + id_to_proc = rb_intern("to_proc"); sym_each = ID2SYM(id_each); sym_cycle = ID2SYM(rb_intern("cycle")); + sym_yield = ID2SYM(rb_intern("yield")); InitVM(Enumerator); } -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/