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

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/

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