module Enumerable
class StopIteration < IndexError
end

class Enumerator
include Enumerable

def initialize(obj, method = :each, *args)
@obj = obj
@meth = method
@iter = method(method)
end

def each(&block)
if block_given?
@obj.each(&block)
else
self
end
end

def with_index
n = 0
each do |e|
yield(e, n)
n += 1
end
end

alias each_with_index with_index

def next
# Generator
end

def rewind
# Generator
end
end

def each_slice(n)
raise(ArgumentError, "invalid slice size") if n <= 0

sum = []

each do |e|
sum.push(e)
if sum.size == n
yield(sum)
sum = []
end
end

yield(sum) if sum.size > 0

return nil
end

alias enum_slice each_slice

def each_cons(n)
raise(ArgumentError, "invalid size") if n <= 0

sum = []

each do |e|
sum.shift if sum.size == n
sum.push(e)
if sum.size == n
yield(sum)
end
end

return nil
end

alias enum_cons each_cons
end

module Kernel
def enum_for(*args)
Enumerable::Enumerator.new(self, *args)
end

alias to_enum enum_for
end

[1,2,3].enum_for(:each).map{|n| n + 1 }
[1,2,3].enum_for(:each).with_index{|n, i| p n => i }

puts '', "each_cons(3):"
(1..10).each_cons(3){|n| p n }

puts '', "each_slice(3):"
(1..10).each_slice(3){|n| p n }