module Hamster::Enumerable

def all?

def all?
  return all? { |item| item } unless block_given?
  each { |item| return false unless yield(item) }
  true
end

def any?

def any?
  return any? { |item| item } unless block_given?
  each { |item| return true if yield(item) }
  false
end

def compact

def compact
  remove(&:nil?)
end

def count(&block)

def count(&block)
  return size unless block_given?
  reduce(0) { |count, item| yield(item) ? count + 1 : count }
end

def each

def each
  fail NoMethodError, "undefined method `each' for #{self.class.name}"
end

def each_with_index(&block)

def each_with_index(&block)
  return self unless block_given?
  reduce(0) do |index, item|
    yield(item, index)
    index + 1
  end
  nil
end

def filter

def filter
  fail NoMethodError, "undefined method `filter' for #{self.class.name}"
end

def find

def find
  return nil unless block_given?
  each { |item| return item if yield(item) }
end

def grep(pattern, &block)

def grep(pattern, &block)
  filter { |item| pattern === item  }.map(&block)
end

def include?(object)

def include?(object)
  any? { |item| item == object }
end

def maximum(&block)

def maximum(&block)
  return maximum { |maximum, item| item <=> maximum } unless block_given?
  reduce { |maximum, item| yield(maximum, item) > 0 ? item : maximum }
end

def minimum(&block)

def minimum(&block)
  return minimum { |minimum, item| item <=> minimum } unless block_given?
  reduce { |minimum, item| yield(minimum, item) < 0 ? item : minimum }
end

def none?

def none?
  return none? { |item| item } unless block_given?
  each { |item| return false if yield(item) }
  true
end

def one?

def one?
  return one? { |item| !!item } unless block_given?
  reduce(false) do |previously_matched, item|
    if yield(item)
      return false if previously_matched
      true
    else
      previously_matched
    end
  end
end

def partition(&block)

def partition(&block)
  return self unless block_given?
  Tuple.new(filter(&block), remove(&block))
end

def product

def product
  reduce(1, &:*)
end

def reduce(memo = Undefined)

def reduce(memo = Undefined)
  each do |item|
    memo = memo.equal?(Undefined) ? item : yield(memo, item)
  end if block_given?
  Undefined.erase(memo)
end

def remove

def remove
  return self unless block_given?
  filter { |item| !yield(item) }
end

def sum

def sum
  reduce(0, &:+)
end

def to_a

def to_a
  reduce([]) { |a, item| a << item }
end