ruby-changes:57726
From: Akinori <ko1@a...>
Date: Thu, 12 Sep 2019 20:19:38 +0900 (JST)
Subject: [ruby-changes:57726] ac3e8834e0 (master): Document and test Enumerator.produce
https://git.ruby-lang.org/ruby.git/commit/?id=ac3e8834e0 From ac3e8834e030f62d2d313ec60cd7ed3c14c9ea5e Mon Sep 17 00:00:00 2001 From: Akinori MUSHA <knu@i...> Date: Thu, 12 Sep 2019 20:15:03 +0900 Subject: Document and test Enumerator.produce Co-authored-by: Victor Shepelev <zverok.offline@g...> diff --git a/enumerator.c b/enumerator.c index fcf49b3..43008bc 100644 --- a/enumerator.c +++ b/enumerator.c @@ -2890,6 +2890,28 @@ producer_size(VALUE obj, VALUE args, VALUE eobj) https://github.com/ruby/ruby/blob/trunk/enumerator.c#L2890 return DBL2NUM(HUGE_VAL); } +/* + * call-seq: + * Enumerator.produce(initial = nil) { |val| } -> enumerator + * + * Creates an infinite enumerator from any block, just called over and + * over. Result of the previous iteration is passed to the next one. + * If +initial+ is provided, it is passed to the first iteration, and + * becomes the first element of the enumerator; if it is not provided, + * first iteration receives +nil+, and its result becomes first + * element of the iterator. + * + * Raising StopIteration from the block stops an iteration. + * + * Examples of usage: + * + * Enumerator.produce(1, &:succ) # => enumerator of 1, 2, 3, 4, .... + * + * Enumerator.produce { rand(10) } # => infinite random number sequence + * + * ancestors = Enumerator.produce(node) { |prev| node = prev.parent or raise StopIteration } + * enclosing_section = ancestors.find { |n| n.type == :section } + */ static VALUE enumerator_s_produce(int argc, VALUE *argv, VALUE klass) { diff --git a/test/ruby/test_enumerator.rb b/test/ruby/test_enumerator.rb index 54dfebb..1e306c3 100644 --- a/test/ruby/test_enumerator.rb +++ b/test/ruby/test_enumerator.rb @@ -811,4 +811,49 @@ class TestEnumerator < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_enumerator.rb#L811 e5.inspect ) end + + def test_produce + assert_raise(ArgumentError) { Enumerator.produce } + + # Without initial object + passed_args = [] + enum = Enumerator.produce { |obj| passed_args << obj; (obj || 0).succ } + assert_instance_of(Enumerator, enum) + assert_equal Float::INFINITY, enum.size + assert_equal [1, 2, 3], enum.take(3) + assert_equal [nil, 1, 2], passed_args + + # With initial object + passed_args = [] + enum = Enumerator.produce(1) { |obj| passed_args << obj; obj.succ } + assert_instance_of(Enumerator, enum) + assert_equal Float::INFINITY, enum.size + assert_equal [1, 2, 3], enum.take(3) + assert_equal [1, 2], passed_args + + # Raising StopIteration + words = "The quick brown fox jumps over the lazy dog.".scan(/\w+/) + enum = Enumerator.produce { words.shift or raise StopIteration } + assert_equal Float::INFINITY, enum.size + assert_instance_of(Enumerator, enum) + assert_equal %w[The quick brown fox jumps over the lazy dog], enum.to_a + + # Raising StopIteration + object = [[[["abc", "def"], "ghi", "jkl"], "mno", "pqr"], "stuv", "wxyz"] + enum = Enumerator.produce(object) { |obj| + obj.respond_to?(:first) or raise StopIteration + obj.first + } + assert_equal Float::INFINITY, enum.size + assert_instance_of(Enumerator, enum) + assert_nothing_raised { + assert_equal [ + [[[["abc", "def"], "ghi", "jkl"], "mno", "pqr"], "stuv", "wxyz"], + [[["abc", "def"], "ghi", "jkl"], "mno", "pqr"], + [["abc", "def"], "ghi", "jkl"], + ["abc", "def"], + "abc", + ], enum.to_a + } + end end -- cgit v0.10.2 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/