Project

General

Profile

Feature #14781 » enumerator_from.rb

knu (Akinori MUSHA), 10/18/2018 02:12 PM

 
class Enumerator
class From < Enumerator
def initialize(seeds, drop: 0, allow_nil: false, &block)
@block = block or
raise ArgumentError, "block not given"
@seeds = Array.try_convert(seeds) or
raise ArgumentError, "seeds must be an array"
drop.is_a?(Integer) && drop >= 0 or
raise ArgumentError, "drop must be a non-negative integer"
@drop = drop
allow_nil.equal?(true) || allow_nil.equal?(false) or
raise ArgumentError, "allow_nil must be boolean"
@allow_nil = allow_nil
end

def each
drop = @drop
allow_nil = @allow_nil
nterms = @seeds.size
block = @block
if drop < nterms
(drop...nterms).each { |i|
value = @seeds[i]
return if value.nil? && !allow_nil
yield value
}
drop = 0
else
drop -= nterms
end
preceding_terms = [*@seeds]
loop {
value = block.call(*preceding_terms)
break if value.nil? && !allow_nil
yield value if drop == 0
preceding_terms.shift
preceding_terms.push(value)
drop -= 1 if drop > 0
}
end

def size
nil
end
end

# Enumerator.from(seeds, after: 0, allow_nil: false) { |*preceding_terms|
# next_term
# }
def self.from(seeds, drop: 0, allow_nil: false, &block)
From.new(seeds, drop: drop, allow_nil: allow_nil, &block)
end
end

require 'test/unit'
require 'ostruct'

class TestEnumerator < Test::Unit::TestCase
def test_s_from
assert_kind_of(Enumerator, Enumerator.from([1], &:succ))

assert_equal([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], Enumerator.from([]) { 0 }.take(10))

assert_equal([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], Enumerator.from([1], &:succ).take(10))

assert_equal([0, 1, 1, 2, 3, 5, 8, 13, 21, 34], Enumerator.from([0, 1]) { |i, j| i + j }.take(10))
assert_equal([1, 1, 2, 3, 5, 8, 13, 21, 34, 55], Enumerator.from([0, 1], drop: 1) { |i, j| i + j }.take(10))
assert_equal([1, 2, 3, 5, 8, 13, 21, 34, 55, 89], Enumerator.from([0, 1], drop: 2) { |i, j| i + j }.take(10))
assert_equal([2, 3, 5, 8, 13, 21, 34, 55, 89, 144], Enumerator.from([0, 1], drop: 3) { |i, j| i + j }.take(10))

root = OpenStruct.new(name: "Root", parent: nil)
node = ("A".."E").inject(root) { |parent, name|
OpenStruct.new(name: name, parent: parent)
}

assert_equal(["E", "D", "C", "B", "A", "Root"], Enumerator.from([node], &:parent).map(&:name))
assert_equal(["D", "C", "B", "A", "Root"], Enumerator.from([node], drop: 1, &:parent).map(&:name))
assert_equal(["C", "B", "A", "Root"], Enumerator.from([node], drop: 2, &:parent).map(&:name))
assert_equal(["B", "A", "Root"], Enumerator.from([node], drop: 3, &:parent).map(&:name))
assert_equal(["E", "D", "C", "B", "A", "Root", nil], Enumerator.from([node], allow_nil: true) { |n|
raise StopIteration if n.nil?
n.parent
}.map { |n| n&.name })
assert_equal([], Enumerator.from([nil], &:parent).map(&:name))

assert_equal([nil, nil, nil, nil, nil], Enumerator.from([nil], allow_nil: true, &:itself).take(5))
assert_equal([1, nil, 1, nil, 1], Enumerator.from([1, nil], allow_nil: true) { |i, j| i }.take(5))
end
end
(1-1/3)