## # Enumerable # # The Enumerable mixin provides collection classes with # several traversal and searching methods, and with the ability to # sort. The class must provide a method `each`, which # yields successive members of the collection. If # {Enumerable#max}, {#min}, or # {#sort} is used, the objects in the collection must also # implement a meaningful `<=>` operator, as these methods # rely on an ordering between members of the collection. # # @ISO 15.3.2 module Enumerable ## # Call the given block for each element # which is yield by +each+. Return false # if one block value is false. Otherwise # return true. If no block is given and # +self+ is false return false. # # ISO 15.3.2.2.1 def all?(&block) if block self.each{|*val| return false unless block.call(*val)} else self.each{|*val| return false unless val.__svalue} end true end ## # Call the given block for each element # which is yield by +each+. Return true # if one block value is true. Otherwise # return false. If no block is given and # +self+ is true object return true. # # ISO 15.3.2.2.2 def any?(&block) if block self.each{|*val| return true if block.call(*val)} else self.each{|*val| return true if val.__svalue} end false end ## # Call the given block for each element # which is yield by +each+. Append all # values of each block together and # return this value. # # ISO 15.3.2.2.3 def collect(&block) return to_enum :collect unless block ary = [] self.each{|*val| ary.push(block.call(*val))} ary end ## # Call the given block for each element # which is yield by +each+. Return # +ifnone+ if no block value was true. # Otherwise return the first block value # which had was true. # # ISO 15.3.2.2.4 def detect(ifnone=nil, &block) ret = ifnone self.each{|*val| if block.call(*val) ret = val.__svalue break end } ret end ## # Call the given block for each element # which is yield by +each+. Pass an # index to the block which starts at 0 # and increase by 1 for each element. # # ISO 15.3.2.2.5 def each_with_index(&block) return to_enum :each_with_index unless block i = 0 self.each{|*val| block.call(val.__svalue, i) i += 1 } self end ## # Return an array of all elements which # are yield by +each+. # # ISO 15.3.2.2.6 def entries ary = [] self.each{|*val| # __svalue is an internal method ary.push val.__svalue } ary end ## # Alias for find # # ISO 15.3.2.2.7 alias find detect ## # Call the given block for each element # which is yield by +each+. Return an array # which contains all elements whose block # value was true. # # ISO 15.3.2.2.8 def find_all(&block) return to_enum :find_all unless block ary = [] self.each{|*val| ary.push(val.__svalue) if block.call(*val) } ary end ## # Call the given block for each element # which is yield by +each+ and which return # value was true when invoking === with # +pattern+. Return an array with all # elements or the respective block values. # # ISO 15.3.2.2.9 def grep(pattern, &block) ary = [] self.each{|*val| sv = val.__svalue if pattern === sv ary.push((block)? block.call(*val): sv) end } ary end ## # Return true if at least one element which # is yield by +each+ returns a true value # by invoking == with +obj+. Otherwise return # false. # # ISO 15.3.2.2.10 def include?(obj) self.each{|*val| return true if val.__svalue == obj } false end ## # Call the given block for each element # which is yield by +each+. Return value # is the sum of all block values. Pass # to each block the current sum and the # current element. # # ISO 15.3.2.2.11 def inject(*args, &block) raise ArgumentError, "too many arguments" if args.size > 2 if Symbol === args[-1] sym = args[-1] block = ->(x,y){x.__send__(sym,y)} args.pop end if args.empty? flag = true # no initial argument result = nil else flag = false result = args[0] end self.each{|*val| val = val.__svalue if flag # push first element as initial flag = false result = val else result = block.call(result, val) end } result end alias reduce inject ## # Alias for collect # # ISO 15.3.2.2.12 alias map collect ## # Return the maximum value of all elements # yield by +each+. If no block is given <=> # will be invoked to define this value. If # a block is given it will be used instead. # # ISO 15.3.2.2.13 def max(&block) flag = true # 1st element? result = nil self.each{|*val| val = val.__svalue if flag # 1st element result = val flag = false else if block result = val if block.call(val, result) > 0 else result = val if (val <=> result) > 0 end end } result end ## # Return the minimum value of all elements # yield by +each+. If no block is given <=> # will be invoked to define this value. If # a block is given it will be used instead. # # ISO 15.3.2.2.14 def min(&block) flag = true # 1st element? result = nil self.each{|*val| val = val.__svalue if flag # 1st element result = val flag = false else if block result = val if block.call(val, result) < 0 else result = val if (val <=> result) < 0 end end } result end ## # Alias for include? # # ISO 15.3.2.2.15 alias member? include? ## # Call the given block for each element # which is yield by +each+. Return an # array which contains two arrays. The # first array contains all elements # whose block value was true. The second # array contains all elements whose # block value was false. # # ISO 15.3.2.2.16 def partition(&block) ary_T = [] ary_F = [] self.each{|*val| if block.call(*val) ary_T.push(val.__svalue) else ary_F.push(val.__svalue) end } [ary_T, ary_F] end ## # Call the given block for each element # which is yield by +each+. Return an # array which contains only the elements # whose block value was false. # # ISO 15.3.2.2.17 def reject(&block) ary = [] self.each{|*val| ary.push(val.__svalue) unless block.call(*val) } ary end ## # Alias for find_all. # # ISO 15.3.2.2.18 alias select find_all ## # TODO # Does this OK? Please test it. def __sort_sub__(sorted, work, src_ary, head, tail, &block) if head == tail sorted[head] = work[head] if src_ary == 1 return end # on current step, which is a src ary? if src_ary == 0 src, dst = sorted, work else src, dst = work, sorted end key = src[head] # key value for dividing values i, j = head, tail # position to store on the dst ary (head + 1).upto(tail){|idx| if ((block)? block.call(src[idx], key): (src[idx] <=> key)) > 0 # larger than key dst[j] = src[idx] j -= 1 else dst[i] = src[idx] i += 1 end } sorted[i] = key # sort each sub-array src_ary = (src_ary + 1) % 2 # exchange a src ary __sort_sub__(sorted, work, src_ary, head, i - 1, &block) if i > head __sort_sub__(sorted, work, src_ary, i + 1, tail, &block) if i < tail end # private :__sort_sub__ ## # Return a sorted array of all elements # which are yield by +each+. If no block # is given <=> will be invoked on each # element to define the order. Otherwise # the given block will be used for # sorting. # # ISO 15.3.2.2.19 def sort(&block) ary = [] self.each{|*val| ary.push(val.__svalue)} if ary.size > 1 __sort_sub__(ary, ::Array.new(ary.size), 0, 0, ary.size - 1, &block) end ary end ## # Alias for entries. # # ISO 15.3.2.2.20 alias to_a entries # redefine #hash 15.3.1.3.15 def hash h = 12347 i = 0 self.each do |e| n = e.hash << (i % 16) h ^= n i += 1 end h end end