diff options
| author | Hiroshi Mimaki <[email protected]> | 2019-10-18 14:46:03 +0900 |
|---|---|---|
| committer | Hiroshi Mimaki <[email protected]> | 2019-10-18 14:46:03 +0900 |
| commit | b6546835457d1935a9c77965686b2a1256874d96 (patch) | |
| tree | 724cfd71a7c956b0648e8c58f3717d797fff5f29 /mrbgems/mruby-enumerator | |
| parent | 8ee516436b8d174a50764939bee23a442aa00b3f (diff) | |
| parent | 20d01f118ddb7e7f2f36926a7a3db35573611857 (diff) | |
| download | mruby-b6546835457d1935a9c77965686b2a1256874d96.tar.gz mruby-b6546835457d1935a9c77965686b2a1256874d96.zip | |
Merge master.
Diffstat (limited to 'mrbgems/mruby-enumerator')
| -rw-r--r-- | mrbgems/mruby-enumerator/mrbgem.rake | 1 | ||||
| -rw-r--r-- | mrbgems/mruby-enumerator/mrblib/enumerator.rb | 60 | ||||
| -rw-r--r-- | mrbgems/mruby-enumerator/test/enumerator.rb | 53 |
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 |
