Module: Enumerable
- Defined in:
- lib/quality_extensions/array/all_same.rb,
lib/quality_extensions/symbol/match.rb,
lib/quality_extensions/color/gradiate.rb,
lib/quality_extensions/enumerable/every.rb,
lib/quality_extensions/enumerable/all_same.rb,
lib/quality_extensions/enumerable/select_bang.rb,
lib/quality_extensions/enumerable/grep_indexes.rb,
lib/quality_extensions/enumerable/max_by_value.rb,
lib/quality_extensions/enumerable/select_while.rb,
lib/quality_extensions/enumerable/map_with_index.rb,
lib/quality_extensions/enumerable/grep_with_index.rb,
lib/quality_extensions/enumerable/grep_plus_offset.rb,
lib/quality_extensions/enumerable/group_by_and_map.rb,
lib/quality_extensions/enumerable/select_with_index.rb
Overview
–
- Author
-
Tyler Rick, Erik Veenstra
- Copyright
-
-
- License
-
-
- Submit to Facets?
-
Maybe
-
Created, based on Facets group_by
++
Instance Method Summary collapse
- #all_same? ⇒ Boolean
-
#every(n) ⇒ Object
Yields every nth object (if invoked with a block), or returns an array of every nth object.
-
#gradiate(options = {}) ⇒ Object
Sorts objects in the enumeration and applies a color scale to them.
-
#grep_indexes(regexp) ⇒ Object
Returns the indexes of the elements that match
regexp
. -
#grep_plus_offset(regexp, offset, wrap_around = false) ⇒ Object
For each element that matches
regexp
return the element that isoffset
elements forward. - #grep_with_index(pattern) ⇒ Object
- #grep_with_regexp_support_for_symbols(pattern, &block) ⇒ Object
-
#group_by_and_map ⇒ Object
#group_by_and_map is used to group items in a collection by something they have in common.
- #map_with_index(&block) ⇒ Object
- #map_with_index! ⇒ Object
-
#max_by_value(&block) ⇒ Object
Instead of returns the object in enum that gives the maximum value from the given block, like max_by does, returns the *maximum value* calculated by the given block (which is tested on each object in enum, just like in max_by).
- #reject_with_index ⇒ Object
- #reject_with_index! ⇒ Object
-
#select! ⇒ Object
end.
-
#select_from(inclusive = true) ⇒ Object
(also: #select_all_starting_with, #reject_until)
Returns all elements of
enum
starting at the first element for whichblock
is truthy, and continuing until the end. -
#select_until(inclusive = true) ⇒ Object
Returns an array containing all consecutive elements of
enum
for whichblock
is not false, starting at the first element. -
#select_until_last(inclusive = true) ⇒ Object
Whereas select_until goes until it reaches the first element for which
block
is true, select_until_last goes until it reaches the last element for whichblock
is true. - #select_until_last_with_index(inclusive = true) ⇒ Object
-
#select_until_with_index(inclusive = true) ⇒ Object
Same as select_until but each time an element of the enum is yielded, an index/counter is also included as an argument.
-
#select_while(include_first_false_element = false) ⇒ Object
Better name? select_consec?.
- #select_while_with_index(include_first_false_element = false) ⇒ Object
-
#select_with_index ⇒ Object
end.
- #select_with_index! ⇒ Object
Instance Method Details
#all_same? ⇒ Boolean
11 12 13 |
# File 'lib/quality_extensions/array/all_same.rb', line 11 def all_same? all? {|a| a == first} end |
#every(n) ⇒ Object
Yields every nth object (if invoked with a block), or returns an array of every nth object.
every(2), for example, would return every other element from the enumerable:
[1, 2, 3, 4, 5, 6].every(2) -> [1, 3, 5]
[1, 2, 3, 4, 5, 6].every(2) { |i| ... } -> nil
23 24 25 26 27 28 29 30 31 |
# File 'lib/quality_extensions/enumerable/every.rb', line 23 def every(n) result = [] unless block_given? each_with_index do |object, i| if i % n == 0 block_given?? yield(object) : result << object end end return block_given?? nil : result end |
#gradiate(options = {}) ⇒ Object
Sorts objects in the enumeration and applies a color scale to them.
Color ranges must be in the form [x, y], where x and y are either fixnums (e.g. 255, 0xFF) or hexadecimal strings (e.g. ‘FF’).
Ranges can be provided for each RGB color e.g.
gradiate(:red => red_range)
…and a default range (for all colors) can be set using :all e.g.
gradiate(:all => default_range, :green => green_range)
If no color ranges are supplied then the sorted enumeration will be returned.
Objects contained in the enumeration are expected to have a color (or colour) attribute/method that returns a Color::RGB
object (or similar).
By default, objects are sorted using :to_i
. This can be overidden by setting options[:compare_using]
to a different method symbol.
By default, objects are ordered “smallest” first. To reverse this set options[:order]
to either :desc
or :reverse
.
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/quality_extensions/color/gradiate.rb', line 42 def gradiate(={}) ranges = [:red, :green, :blue].map do |col| if range = ([col] || [:all]) a, b = range.map { |x| x.respond_to?(:hex) ? x.hex : x.to_i } a, b = b, a if a > b # smallest first c = b.diff(a) / (self.size - 1) next (a..b).every(c) else [] end end objects = sort_by { |object| object.send([:compare_using] || :to_i) } objects = objects.reverse if [:desc, :reverse].include?([:order]) objects.zip(*ranges).collect do |object, red, green, blue| color = object.respond_to?(:colour) ? object.colour : object.color color.red = red if red color.green = green if green color.blue = blue if blue next object end end |
#grep_indexes(regexp) ⇒ Object
Returns the indexes of the elements that match regexp
.
%w[a ab abc].grep_indexes(/a$/) => [0] %w[a ab abc].grep_indexes(/b/) => [1, 2]
17 18 19 20 21 22 23 |
# File 'lib/quality_extensions/enumerable/grep_indexes.rb', line 17 def grep_indexes(regexp) indexes = [] each_with_index {|el, i| indexes << i if el =~ regexp } indexes end |
#grep_plus_offset(regexp, offset, wrap_around = false) ⇒ Object
For each element that matches regexp
return the element that is offset
elements forward.
Examples:
%w[1 2 3].grep_plus_offset(/1/, -1) => [nil] %w[1 2 3].grep_plus_offset(/1/, 0) => [‘1’] %w[1 2 3].grep_plus_offset(/1/, 1) => [‘2’] %w[1 2 3].grep_plus_offset(/1/, 2) => [‘3’] %w[1 2 3].grep_plus_offset(/1/, 3) => [nil]
caller(0).grep_plus_offset(/in ‘synchronize’/, 1) => the line that called synchronize
28 29 30 31 32 33 34 35 36 |
# File 'lib/quality_extensions/enumerable/grep_plus_offset.rb', line 28 def grep_plus_offset(regexp, offset, wrap_around = false) indexes = grep_indexes(regexp).map_send(:+, offset) # If any indexes are negative, replace with (maximum index + 1) so that values_at will return # nil for that element (instead of returning an element from the end -- values_at(-1) returns # the last element, for example), the same as how providing a positive that results in an offset # > maximum_index (length - 1) results in a nil being returned for that index. indexes.map! {|_| _ < 0 ? length : _ } unless wrap_around values_at *indexes end |
#grep_with_index(pattern) ⇒ Object
24 25 26 27 28 |
# File 'lib/quality_extensions/enumerable/grep_with_index.rb', line 24 def grep_with_index(pattern) $debug = true each.with_index.grep(pattern) $debug = false end |
#grep_with_regexp_support_for_symbols(pattern, &block) ⇒ Object
87 88 89 90 91 |
# File 'lib/quality_extensions/symbol/match.rb', line 87 def grep_with_regexp_support_for_symbols(pattern, &block) map { |element| element.is_a?(Symbol) ? element.to_s : element }.grep_without_regexp_support_for_symbols(pattern, &block) end |
#group_by_and_map ⇒ Object
#group_by_and_map is used to group items in a collection by something they have in common. The common factor is the key in the resulting hash, the array of like elements is the value.
This differs from the normal group_by in that it lets you map the values (perhaps removing the key from the value since that would be redundant) all in one step.
# need better example
(1..6).group_by_and_map { |n| next n % 3, n }
# => { 0 => [3,6], 1 => [1, 4], 2 => [2,5] }
[
['31a4', 'v1.3'],
['9f2b', 'current'],
['9f2b', 'v2.0']
].group_by_and_map { |e| e[0], e[1] }
# => {"31a4"=>["v1.3"], "9f2b"=>["current", "v2.0"]}
results.group_by_and_map { |a| a[0], a[1..-1] }
CREDIT: Erik Veenstra, Tyler Rick
37 38 39 40 41 42 43 44 45 |
# File 'lib/quality_extensions/enumerable/group_by_and_map.rb', line 37 def group_by_and_map #:yield: h = Hash.new each { |e| result = yield(e) #p result (h[result[0]] ||= []) << result[1] } h end |
#map_with_index(&block) ⇒ Object
19 20 21 |
# File 'lib/quality_extensions/enumerable/map_with_index.rb', line 19 def map_with_index(&block) dup.map_with_index!(&block) end |
#map_with_index! ⇒ Object
13 14 15 16 17 |
# File 'lib/quality_extensions/enumerable/map_with_index.rb', line 13 def map_with_index! each_with_index do |e, i| self[i] = yield(e, i) end end |
#max_by_value(&block) ⇒ Object
Instead of returns the object in enum that gives the maximum value from the given block, like max_by does, returns the *maximum value* calculated by the given block (which is tested on each object in enum, just like in max_by).
Notice the difference:
['a','abc','ab'].max_by {|el| el.length}.should == 'abc'
['a','abc','ab'].max_by_value {|el| el.length}.should == 3
22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/quality_extensions/enumerable/max_by_value.rb', line 22 def max_by_value(&block) max_value = nil each do |el| value = yield el if max_value.nil? max_value = value else max_value = [value, max_value].max end end max_value end |
#reject_with_index ⇒ Object
42 43 44 45 46 47 48 49 |
# File 'lib/quality_extensions/enumerable/select_with_index.rb', line 42 def reject_with_index index = -1 if block_given? reject { |x| index += 1; yield(x, index) } else self end end |
#reject_with_index! ⇒ Object
51 52 53 54 55 56 57 58 |
# File 'lib/quality_extensions/enumerable/select_with_index.rb', line 51 def reject_with_index! index = -1 if block_given? reject! { |x| index += 1; yield(x, index) } else self end end |
#select! ⇒ Object
end
19 20 21 |
# File 'lib/quality_extensions/enumerable/select_bang.rb', line 19 def select! reject! { |x| !yield(x) } end |
#select_from(inclusive = true) ⇒ Object Also known as: select_all_starting_with, reject_until
Returns all elements of enum
starting at the first element for which block
is truthy, and continuing until the end.
Examples:
(0..3).select_from {|v| v == 1} # => [1, 2, 3] (0..3).select_from(false) {|v| v == 1} # => [2, 3]
‘b’=>2, ‘c’=>3, ‘d’=>1.select_from {|k, v| v == 2} ) # => “c”=>3, “d”=>1 ‘b’=>2, ‘c’=>3, ‘d’=>1.select_from(false) {|k, v| v == 2} ) # => “d”=>1
Compare to Array#from in ActiveSupport. (maybe should rename to #from?)
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/quality_extensions/enumerable/select_while.rb', line 221 def select_from(inclusive = true) return self unless block_given? selecting = false select do |*args| # Once we hit the first truthy result, selecting will be true to the end select_this_el = !!yield(*args) this_is_first_true = !selecting && select_this_el selecting = selecting || select_this_el if inclusive selecting else selecting && !this_is_first_true end end end |
#select_until(inclusive = true) ⇒ Object
Returns an array containing all consecutive elements of enum
for which block
is not false, starting at the first element. So it is very much like select
, but unlike select
, it stops searching as soon as block
ceases to be true. (That means it will stop searching immediately if the first element doesn’t match.)
This might be preferable to select
, for example, if:
-
you have a very large collection of elements
-
the desired elements are expected to all be consecutively occuring and are all at the beginning of the collection
-
it would be costly to continue iterating all the way to the very end
If inclusive
is false, only those elements occuring before the first element for which block
is true will be returned. If inclusive
is true (the default), those elements occuring up to and including the first element for which block
is true will be returned.
Examples:
(0..3).select_until {|v| v == 1} # => [0, 1] (0..3).select_until(false) {|v| v == 1} # => [0]
‘b’=>2, ‘c’=>3, ‘d’=>1.select_until {|k, v| v == 2} ) # => “b”=>2 ‘b’=>2, ‘c’=>3, ‘d’=>1.select_until(false) {|k, v| v == 2} ) # => “a”=>1
puts caller # => 30 lines of context, many of them so far removed that they are irrelevant puts caller.select_until {|l| l =~ %r(/app/) } # only print the stack back to the first frame from our own code
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/quality_extensions/enumerable/select_while.rb', line 57 def select_until(inclusive = true) return self unless block_given? done = false if inclusive select do |*args| returning = !done done = true if yield(*args) returning end else select do |*args| done = true if yield(*args) !done end end end |
#select_until_last(inclusive = true) ⇒ Object
Whereas select_until goes until it reaches the first element for which block
is true, select_until_last goes until it reaches the last element for which block
is true.
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/quality_extensions/enumerable/select_while.rb', line 138 def select_until_last(inclusive = true) return self unless block_given? # Find the index of the last-matching element last = nil #each_with_index do |item, i| # last = i if yield(item) #end each_with_index do |*args| i = args.pop last = i if yield(*args.first) end # If they want to exclude the last-matching element, adjust the index by -1 (if possible) #if last && !inclusive # if last == 0 # # If the last-matching element was also the first element, then we want to select *none* of the elements # last = nil # else # last -= 1 # end #end # Select all elements up to last-matching element #self.to_a[0 .. last] # (didn't work for hashes) #select_with_index do |item, i| # true if last && i <= last #end #select_while_with_index do |item, i| # #puts "#{i} <= #{last} => #{last && i <= last}" # last && i <= last #end # Select all elements up to last-matching element if last.nil? select do |*args| false end else select_until_with_index(inclusive) do |*args| i = args.last i == last end end end |
#select_until_last_with_index(inclusive = true) ⇒ Object
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 |
# File 'lib/quality_extensions/enumerable/select_while.rb', line 183 def select_until_last_with_index(inclusive = true) return self unless block_given? # Find the index of the last-matching element last = nil each_with_index do |*args| #p args i = args.last last = i if yield(*args) end # Select all elements up to last-matching element if last.nil? select do |*args| false end else select_until_with_index(inclusive) do |*args| i = args.last i == last end end end |
#select_until_with_index(inclusive = true) ⇒ Object
Same as select_until but each time an element of the enum is yielded, an index/counter is also included as an argument.
This is probably only useful for collections that have some kind of predictable ordering (such as Arrays). Fortunately, Hashes have a predictable order in Ruby 1.9.
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/quality_extensions/enumerable/select_while.rb', line 79 def select_until_with_index(inclusive = true) return self unless block_given? done = false if inclusive select_with_index do |*args| returning = !done done = true if yield(*args) returning end else select_with_index do |*args| done = true if yield(*args) !done end end end |
#select_while(include_first_false_element = false) ⇒ Object
Better name? select_consec?
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/quality_extensions/enumerable/select_while.rb', line 98 def select_while(include_first_false_element = false) return self unless block_given? done = false if include_first_false_element select do |*args| returning = !done done = true if !yield(*args) returning end else select do |*args| #puts "!done=#{!done}; !yield(#{args}) => #{!yield(*args)}" done = true if !yield(*args) !done end end end |
#select_while_with_index(include_first_false_element = false) ⇒ Object
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
# File 'lib/quality_extensions/enumerable/select_while.rb', line 117 def select_while_with_index(include_first_false_element = false) return self unless block_given? done = false if include_first_false_element select_with_index do |*args| returning = !done done = true if !yield(*args) returning end else select_with_index do |*args| #puts "!done=#{!done}; !yield(#{args}) => #{!yield(*args)}" done = true if !yield(*args) !done end end end |
#select_with_index ⇒ Object
end
23 24 25 26 27 28 29 30 31 |
# File 'lib/quality_extensions/enumerable/select_with_index.rb', line 23 def select_with_index index = -1 if block_given? #select { |x| index += 1; yield(x, index) } # not hash friendly? select { |*args| index += 1; yield(*(args + [index])) } else self end end |
#select_with_index! ⇒ Object
33 34 35 36 37 38 39 40 |
# File 'lib/quality_extensions/enumerable/select_with_index.rb', line 33 def select_with_index! index = -1 if block_given? select! { |x| index += 1; yield(x, index) } else self end end |