## # Enumerable # # ISO 15.3.2 # # 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. 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) st = true if block self.each{|val| unless block.call(val) st = false break end } else self.each{|val| unless val st = false break end } end st 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) st = false if block self.each{|val| if block.call(val) st = true break end } else self.each{|val| if val st = true break end } end st 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) 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 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) i = 0 self.each{|val| block.call(val, 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| ary.push val } 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) ary = [] self.each{|val| ary.push(val) 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| if pattern === val ary.push((block)? block.call(val): val) 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) st = false self.each{|val| if val == obj st = true break end } st 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| 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| 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| 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) else ary_F.push(val) 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) 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)} unless ary.empty? __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 end