summaryrefslogtreecommitdiffhomepage
path: root/mrbgems/mruby-enumerator
diff options
context:
space:
mode:
authorHiroshi Mimaki <[email protected]>2019-10-18 14:46:03 +0900
committerHiroshi Mimaki <[email protected]>2019-10-18 14:46:03 +0900
commitb6546835457d1935a9c77965686b2a1256874d96 (patch)
tree724cfd71a7c956b0648e8c58f3717d797fff5f29 /mrbgems/mruby-enumerator
parent8ee516436b8d174a50764939bee23a442aa00b3f (diff)
parent20d01f118ddb7e7f2f36926a7a3db35573611857 (diff)
downloadmruby-b6546835457d1935a9c77965686b2a1256874d96.tar.gz
mruby-b6546835457d1935a9c77965686b2a1256874d96.zip
Merge master.
Diffstat (limited to 'mrbgems/mruby-enumerator')
-rw-r--r--mrbgems/mruby-enumerator/mrbgem.rake1
-rw-r--r--mrbgems/mruby-enumerator/mrblib/enumerator.rb60
-rw-r--r--mrbgems/mruby-enumerator/test/enumerator.rb53
3 files changed, 97 insertions, 17 deletions
diff --git a/mrbgems/mruby-enumerator/mrbgem.rake b/mrbgems/mruby-enumerator/mrbgem.rake
index 8757a15ea..abcc54e7a 100644
--- a/mrbgems/mruby-enumerator/mrbgem.rake
+++ b/mrbgems/mruby-enumerator/mrbgem.rake
@@ -2,6 +2,5 @@ MRuby::Gem::Specification.new('mruby-enumerator') do |spec|
spec.license = 'MIT'
spec.author = 'mruby developers'
spec.add_dependency('mruby-fiber', :core => 'mruby-fiber')
- spec.add_dependency 'mruby-enum-ext', :core => 'mruby-enum-ext'
spec.summary = 'Enumerator class'
end
diff --git a/mrbgems/mruby-enumerator/mrblib/enumerator.rb b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
index 457687268..5a98dc964 100644
--- a/mrbgems/mruby-enumerator/mrblib/enumerator.rb
+++ b/mrbgems/mruby-enumerator/mrblib/enumerator.rb
@@ -89,7 +89,6 @@ class Enumerator
include Enumerable
##
- # @overload initialize(size = nil, &block)
# @overload initialize(obj, method = :each, *args)
#
# Creates a new Enumerator object, which can be used as an
@@ -244,9 +243,10 @@ class Enumerator
#
# === Examples
#
- # "Hello, world!".scan(/\w+/) #=> ["Hello", "world"]
- # "Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"]
- # "Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
+ # Array.new(3) #=> [nil, nil, nil]
+ # Array.new(3) { |i| i } #=> [0, 1, 2]
+ # Array.to_enum(:new, 3).to_a #=> [0, 1, 2]
+ # Array.to_enum(:new).each(3).to_a #=> [0, 1, 2]
#
# obj = Object.new
#
@@ -555,6 +555,46 @@ class Enumerator
self
end
end
+
+ ##
+ # 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 }
+ def Enumerator.produce(init=NONE, &block)
+ raise ArgumentError, "no block given" if block.nil?
+ Enumerator.new do |y|
+ if init == NONE
+ val = nil
+ else
+ val = init
+ y.yield(val)
+ end
+ begin
+ while true
+ y.yield(val = block.call(val))
+ end
+ rescue StopIteration
+ # do nothing
+ end
+ end
+ end
end
module Kernel
@@ -562,15 +602,10 @@ module Kernel
# call-seq:
# obj.to_enum(method = :each, *args) -> enum
# obj.enum_for(method = :each, *args) -> enum
- # obj.to_enum(method = :each, *args) {|*args| block} -> enum
- # obj.enum_for(method = :each, *args){|*args| block} -> enum
#
# Creates a new Enumerator which will enumerate by calling +method+ on
# +obj+, passing +args+ if any.
#
- # If a block is given, it will be used to calculate the size of
- # the enumerator without the need to iterate it (see Enumerator#size).
- #
# === Examples
#
# str = "xyz"
@@ -588,17 +623,14 @@ module Kernel
# It is typical to call to_enum when defining methods for
# a generic Enumerable, in case no block is passed.
#
- # Here is such an example, with parameter passing and a sizing block:
+ # Here is such an example with parameter passing:
#
# module Enumerable
# # a generic method to repeat the values of any enumerable
# def repeat(n)
# raise ArgumentError, "#{n} is negative!" if n < 0
# unless block_given?
- # return to_enum(__method__, n) do # __method__ is :repeat here
- # sz = size # Call size and multiply by n...
- # sz * n if sz # but return nil if size itself is nil
- # end
+ # return to_enum(__method__, n) # __method__ is :repeat here
# end
# each do |*val|
# n.times { yield *val }
diff --git a/mrbgems/mruby-enumerator/test/enumerator.rb b/mrbgems/mruby-enumerator/test/enumerator.rb
index d609cadb5..ecd6c4d65 100644
--- a/mrbgems/mruby-enumerator/test/enumerator.rb
+++ b/mrbgems/mruby-enumerator/test/enumerator.rb
@@ -6,6 +6,17 @@ class << @obj
end
end
+def assert_take(exp, enumerator)
+ result = []
+ n = exp.size
+ enumerator.each do |v|
+ result << v
+ n -= 1
+ break if n == 0
+ end if n > 0
+ assert_equal exp, result
+end
+
assert 'Enumerator.class' do
assert_equal Class, Enumerator.class
end
@@ -19,7 +30,7 @@ assert 'Enumerator.new' do
assert_equal [:x,:y,:z], [:x,:y,:z].each.map{|i| i}.sort
assert_equal [[:x,1],[:y,2]], {x:1, y:2}.each.map{|i| i}.sort
assert_equal [1,2,3], @obj.to_enum(:foo, 1,2,3).to_a
- assert_equal [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }.take(3)
+ assert_take [1,2,3], Enumerator.new { |y| i = 0; loop { y << (i += 1) } }
assert_raise(ArgumentError) { Enumerator.new }
# examples
@@ -30,7 +41,7 @@ assert 'Enumerator.new' do
a, b = b, a + b
end
end
- assert_equal [1,1,2,3,5,8,13,21,34,55], fib.take(10)
+ assert_take [1,1,2,3,5,8,13,21,34,55], fib
end
assert 'Enumerator#initialize_copy' do
@@ -549,3 +560,41 @@ assert 'Enumerable#zip' do
assert_raise(TypeError) { [1].zip(1) }
end
+
+assert 'Enumerator.produce' do
+ assert_raise(ArgumentError) { Enumerator.produce }
+
+ # Without initial object
+ passed_args = []
+ enum = Enumerator.produce {|obj| passed_args << obj; (obj || 0).succ }
+ assert_equal Enumerator, enum.class
+ assert_take [1, 2, 3], enum
+ assert_equal [nil, 1, 2], passed_args
+
+ # With initial object
+ passed_args = []
+ enum = Enumerator.produce(1) {|obj| passed_args << obj; obj.succ }
+ assert_take [1, 2, 3], enum
+ assert_equal [1, 2], passed_args
+
+ # Raising StopIteration
+ words = %w[The quick brown fox jumps over the lazy dog]
+ enum = Enumerator.produce { words.shift or raise StopIteration }
+ 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_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