# Pure Ruby replacement for enumerator.so
# Author: Brian Blackwell (brianblackwell@realemail.net)

class Object
  def to_enum(method = :each, *args)
    Enumerable::Enumerator.new(self, method, args)
  end
  
  def enum_for(method = :each, *args)
    to_enum(method, args)
  end
end

module Enumerable
  attr_accessor :obj, :method, :args
    
  def each_slice(n, &block)
    if n <= 0
      raise ArgumentError, "invalid size"
    end
    
    ary = []
    each do |a|
      ary.push(a)
      if ary.length == n
        yield ary
        ary = []
      end
    end
    
    if ary.length > 0
      yield ary
    end
  end
  
  def each_cons(n, &block)
    if n <= 0
      raise ArgumentError, "invalid size"
    end
    
    ary = []
    each do |a|
      if ary.length == n
        ary.shift
      end
      ary.push(a)
      if ary.length == n
        yield ary.dup
      end
    end
  end
      
  def enum_slice(n)
    Enumerable::Enumerator.new(self, :each_slice, n)
  end
  
  def enum_cons(n)
    Enumerable::Enumerator.new(self, :each_cons, n)
  end
  
  def enum_with_index(n)
    Enumerable::Enumerator.new(self, :each_with_index)
  end
  
  class Enumerator
    include Enumerable
        
    def initialize(o, m = :each, *a)
      @obj = o
      @method = m
      @args = a
    end
    
    def each(&block)
      if @method == :each
        return @obj.each(&block)
      elsif @method == :each_slice
        return @obj.each_slice(@args[0], &block)
      elsif @method == :each_cons
        return @obj.each_cons(@args[0], &block)
      elsif @method == :each_with_index
        return @obj.each_with_index(&block)
      end
    end
  end
  
end
