require "forwardable" require "hamster/undefined" require "hamster/tuple" module Hamster module Enumerable extend Forwardable def each fail NoMethodError, "undefined method `each' for #{self.class.name}" end def_delegator :self, :each, :foreach def filter fail NoMethodError, "undefined method `filter' for #{self.class.name}" end def_delegator :self, :filter, :select def_delegator :self, :filter, :find_all def each_with_index(&block) return self unless block_given? reduce(0) do |index, item| yield(item, index) index + 1 end nil end def reduce(memo = Undefined) each do |item| memo = memo.equal?(Undefined) ? item : yield(memo, item) end if block_given? Undefined.erase(memo) end def_delegator :self, :reduce, :inject def_delegator :self, :reduce, :fold def_delegator :self, :reduce, :foldr def partition(&block) return self unless block_given? Tuple.new(filter(&block), remove(&block)) end def find return nil unless block_given? each { |item| return item if yield(item) } end def_delegator :self, :find, :detect def include?(object) any? { |item| item == object } end def_delegator :self, :include?, :member? def_delegator :self, :include?, :contains? def_delegator :self, :include?, :elem? def any? return any? { |item| item } unless block_given? each { |item| return true if yield(item) } false end def_delegator :self, :any?, :exist? def_delegator :self, :any?, :exists? def all? return all? { |item| item } unless block_given? each { |item| return false unless yield(item) } true end def_delegator :self, :all?, :forall? def none? return none? { |item| item } unless block_given? each { |item| return false if yield(item) } true end 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 minimum(&block) return minimum { |minimum, item| item <=> minimum } unless block_given? reduce { |minimum, item| yield(minimum, item) < 0 ? item : minimum } end def_delegator :self, :minimum, :min def maximum(&block) return maximum { |maximum, item| item <=> maximum } unless block_given? reduce { |maximum, item| yield(maximum, item) > 0 ? item : maximum } end def_delegator :self, :maximum, :max def grep(pattern, &block) filter { |item| pattern === item }.map(&block) end def count(&block) return size unless block_given? reduce(0) { |count, item| yield(item) ? count + 1 : count } end def product reduce(1, &:*) end def sum reduce(0, &:+) end def remove return self unless block_given? filter { |item| !yield(item) } end def_delegator :self, :remove, :reject def_delegator :self, :remove, :delete_if def compact remove(&:nil?) end def to_a reduce([]) { |a, item| a << item } end def_delegator :self, :to_a, :entries def_delegator :self, :to_a, :to_ary end end