module Enumerable
def chain(*args)
Enumerator::Chain.new(self, *args)
end
end
class Enumerator
def +(other)
Chain.new(self, other)
end
class Chain
include Enumerable
def initialize(*args)
@enums = args.freeze
@pos = -1
end
def each(&block)
return to_enum unless block
i = 0
while i < @enums.size
@pos = i
@enums[i].each(&block)
i += 1
end
self
end
def size
@enums.reduce(0) do |a, e|
return nil unless e.respond_to?(:size)
a + e.size
end
end
def rewind
while 0 <= @pos && @pos < @enums.size
e = @enums[@pos]
e.rewind if e.respond_to?(:rewind)
@pos -= 1
end
self
end
def +(other)
self.class.new(self, other)
end
def inspect
"#<#{self.class}: #{@enums.inspect}>"
end
end
end