Class: Hash
Class Method Summary collapse
-
.lazy! ⇒ Object
Hash keys become methods, kinda like OpenStruct.
-
.of_arrays ⇒ Object
Returns a new Hash whose values default to empty arrays.
-
.of_integers ⇒ Object
Returns a new Hash whose values default to 0.
-
.of_sets ⇒ Object
Returns a new Hash whose values default to empty sets.
-
.of_unique_ids ⇒ Object
Returns a new Hash which automatically assigns each unique key to an increasing counter.
Instance Method Summary collapse
-
#+(other) ⇒ Object
‘hash1 + hash2` merge the two hashes, returning a new hash.
-
#-(other) ⇒ Object
‘hash1 - hash2` removes keys from hash1 that exist in hash2, returning a new hash.
-
#apply_diff(changes) ⇒ Object
Applies a Hash#diff changeset and returns the transformed hash.
-
#apply_diff!(changes) ⇒ Object
Applies a Hash#diff changeset to this hash.
-
#blank? ⇒ Boolean
‘true’ if the Hash has no entries.
-
#deep_dup ⇒ Object
Duplicate this hash, including hashes nested inside of it.
-
#diff(other) ⇒ Object
Return all the changes necessary to transform ‘self` into `other`.
-
#map_keys(&block) ⇒ Object
(also: #transform_keys)
Transforms the keys of the hash by passing them into the supplied block, and then using the blocks result as the new key.
-
#map_keys!(&block) ⇒ Object
(also: #transform_keys!)
Runs map_keys on self.
-
#map_values(&block) ⇒ Object
Transforms the values of the hash by passing them into the supplied block, and then using the block’s result as the new value.
-
#map_values!(&block) ⇒ Object
Runs map_values on self.
-
#mkdir_p(path) ⇒ Object
Makes each element in the ‘path` array point to a hash containing the next element in the `path`.
-
#print_tree(level = 0, indent = " ", &block) ⇒ Object
Print the result of ‘tree`.
-
#query(template) ⇒ Object
(also: #mql)
Query a hash using MQL (see: wiki.freebase.com/wiki/MQL_operators for reference).
-
#remove_blank_values ⇒ Object
Returns a new Hash where blank values have been removed.
-
#remove_blank_values! ⇒ Object
Runs “remove_blank_values” on self.
-
#slice(*keys) ⇒ Object
Returns a hash containing only the keys passed as arguments.
-
#slice!(*keys) ⇒ Object
Alters the hash so it contains only the keys passed as arguments.
-
#symbolize_keys ⇒ Object
Return a hash with its keys converted to symbols, for great justice.
-
#symbolize_keys! ⇒ Object
Convert the keys to symbols in-place, for fun and profit.
-
#to_nicejson ⇒ Object
(also: #to_nice_json)
Convert this Hash to indented JSON (using JSON.pretty_generate).
-
#to_ostruct ⇒ Object
Convert this Hash (and all nested Hashes, and all nested Arrays containing Hashes) to OpenStruct(s).
-
#to_query ⇒ Object
Convert the hash into a GET query.
-
#translate_keys(mapping) ⇒ Object
Same as ‘translate_keys!`, except it returns a copy of the hash.
-
#translate_keys!(mapping) ⇒ Object
Translate keys to other keys, given a hash of old-key to new-key mappings.
-
#tree(level = 0, indent = " ") ⇒ Object
Turn some nested hashes into a tree (returns an array of strings, padded on the left with indents.).
Class Method Details
.lazy! ⇒ Object
Hash keys become methods, kinda like OpenStruct. These methods have the lowest priority, so be careful. They will be overridden by any methods on Hash.
190 191 192 193 194 195 196 197 198 199 200 |
# File 'lib/epitools/core_ext/hash.rb', line 190 def self.lazy! Hash.class_eval do def method_missing(name, *args) if args.any? super else self[name] || self[name.to_s] end end end end |
.of_arrays ⇒ Object
Returns a new Hash whose values default to empty arrays. (Good for collecting things!)
eg:
Hash.of_arrays[:yays] << "YAY!"
145 146 147 |
# File 'lib/epitools/core_ext/hash.rb', line 145 def self.of_arrays new {|h,k| h[k] = [] } end |
.of_integers ⇒ Object
Returns a new Hash whose values default to 0. (Good for counting things!)
eg:
Hash.of_integers[:yays] += 1
165 166 167 |
# File 'lib/epitools/core_ext/hash.rb', line 165 def self.of_integers new(0) end |
.of_sets ⇒ Object
Returns a new Hash whose values default to empty sets. (Good for collecting unique things!)
eg:
Hash.of_sets[:yays] << "Yay!"
155 156 157 |
# File 'lib/epitools/core_ext/hash.rb', line 155 def self.of_sets new {|h,k| h[k] = Set.new } end |
.of_unique_ids ⇒ Object
Returns a new Hash which automatically assigns each unique key to an increasing counter.
eg:
> h = Hash.of_unique_ids
=> {}
> h["Person"] #=> 0
> h["Another Person"] #=> 1
> h["Yet Another Person"] #=> 2
> h["Person"] #=> 0
> h
=> {"Person"=>0, "Another Person"=>1, "Yet Another Person"=>2}
182 183 184 |
# File 'lib/epitools/core_ext/hash.rb', line 182 def self.of_unique_ids new { |h,k| h[k] = h.size } end |
Instance Method Details
#+(other) ⇒ Object
‘hash1 + hash2` merge the two hashes, returning a new hash
7 8 9 |
# File 'lib/epitools/core_ext/hash.rb', line 7 def +(other) merge(other) end |
#-(other) ⇒ Object
‘hash1 - hash2` removes keys from hash1 that exist in hash2, returning a new hash
14 15 16 |
# File 'lib/epitools/core_ext/hash.rb', line 14 def -(other) dup.delete_if { |k,v| other.includes?(k) } end |
#apply_diff(changes) ⇒ Object
Applies a Hash#diff changeset and returns the transformed hash.
353 354 355 |
# File 'lib/epitools/core_ext/hash.rb', line 353 def apply_diff(changes) deep_dup.apply_diff!(changes) end |
#apply_diff!(changes) ⇒ Object
Applies a Hash#diff changeset to this hash.
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
# File 'lib/epitools/core_ext/hash.rb', line 327 def apply_diff!(changes) path = [[self, changes]] pos, local_changes = path.pop while local_changes local_changes.each_pair do |key, change| if change.kind_of?(Array) if change[1].nil? pos.delete key else pos[key] = change[1] end else path.push([pos[key], change]) end end pos, local_changes = path.pop end self end |
#blank? ⇒ Boolean
‘true’ if the Hash has no entries
21 22 23 |
# File 'lib/epitools/core_ext/hash.rb', line 21 def blank? not any? end |
#deep_dup ⇒ Object
Duplicate this hash, including hashes nested inside of it.
360 361 362 363 364 365 366 367 |
# File 'lib/epitools/core_ext/hash.rb', line 360 def deep_dup duplicate = self.dup duplicate.each_pair do |k,v| tv = duplicate[k] duplicate[k] = tv.is_a?(Hash) && v.is_a?(Hash) ? tv.deep_dup : v end duplicate end |
#diff(other) ⇒ Object
Return all the changes necessary to transform ‘self` into `other`. (Works on nested hashes.) The result is a hash of => [old value, new value] pairs.
(NOTE: Since “nil” is used to denote a value was removed, you can’t use this method to diff hashes where a value is “nil”.)
311 312 313 314 315 316 317 318 319 320 321 322 |
# File 'lib/epitools/core_ext/hash.rb', line 311 def diff(other) (self.keys + other.keys).uniq.inject({}) do |memo, key| unless self[key] == other[key] if self[key].kind_of?(Hash) && other[key].kind_of?(Hash) memo[key] = self[key].diff(other[key]) else memo[key] = [self[key], other[key]] end end memo end end |
#map_keys(&block) ⇒ Object Also known as: transform_keys
Transforms the keys of the hash by passing them into the supplied block, and then using the blocks result as the new key.
76 77 78 |
# File 'lib/epitools/core_ext/hash.rb', line 76 def map_keys(&block) dup.map_keys!(&block) end |
#map_keys!(&block) ⇒ Object Also known as: transform_keys!
Runs map_keys on self.
63 64 65 66 67 68 69 |
# File 'lib/epitools/core_ext/hash.rb', line 63 def map_keys!(&block) keys.each do |key| value = delete(key) self[yield(key)] = value end self end |
#map_values(&block) ⇒ Object
Transforms the values of the hash by passing them into the supplied block, and then using the block’s result as the new value.
56 57 58 |
# File 'lib/epitools/core_ext/hash.rb', line 56 def map_values(&block) dup.map_values!(&block) end |
#map_values!(&block) ⇒ Object
Runs map_values on self.
44 45 46 47 48 49 50 |
# File 'lib/epitools/core_ext/hash.rb', line 44 def map_values!(&block) keys.each do |key| value = self[key] self[key] = yield(value) end self end |
#mkdir_p(path) ⇒ Object
Makes each element in the ‘path` array point to a hash containing the next element in the `path`. Useful for turning a bunch of strings (paths, module names, etc.) into a tree.
Example:
h = {}
h.mkdir_p(["a", "b", "c"]) #=> {"a"=>{"b"=>{"c"=>{}}}}
h.mkdir_p(["a", "b", "whoa"]) #=> {"a"=>{"b"=>{"c"=>{}, "whoa"=>{}}}}
217 218 219 220 221 222 223 |
# File 'lib/epitools/core_ext/hash.rb', line 217 def mkdir_p(path) return if path.empty? dir = path.first self[dir] ||= {} self[dir].mkdir_p(path[1..-1]) self end |
#print_tree(level = 0, indent = " ", &block) ⇒ Object
Print the result of ‘tree`
241 242 243 244 245 246 247 248 |
# File 'lib/epitools/core_ext/hash.rb', line 241 def print_tree(level=0, indent=" ", &block) dent = indent * level each do |key, val| puts block_given? ? yield(key, level) : "#{dent}#{key}" val.print_tree(level+1, indent, &block) if val.any? end end |
#query(template) ⇒ Object Also known as: mql
Query a hash using MQL (see: wiki.freebase.com/wiki/MQL_operators for reference)
Examples:
> query(name: /steve/)
> query(/title/ => ??)
> query(articles: [{title: ??}])
> query(responses: [])
> query("date_of_birth<" => "2000")
289 290 291 292 293 294 295 296 297 298 299 300 301 302 |
# File 'lib/epitools/core_ext/hash.rb', line 289 def query(template) results = [] template.each do |key,val| case key when Regexp, String when Array when Hash results += hash.query(template) end end map do |key,val| end end |
#remove_blank_values ⇒ Object
Returns a new Hash where blank values have been removed. (It checks if the value is blank by calling #blank? on it)
37 38 39 |
# File 'lib/epitools/core_ext/hash.rb', line 37 def remove_blank_values dup.remove_blank_values! end |
#remove_blank_values! ⇒ Object
Runs “remove_blank_values” on self.
28 29 30 31 |
# File 'lib/epitools/core_ext/hash.rb', line 28 def remove_blank_values! delete_if{|k,v| v.blank?} self end |
#slice(*keys) ⇒ Object
Returns a hash containing only the keys passed as arguments.
125 126 127 |
# File 'lib/epitools/core_ext/hash.rb', line 125 def slice(*keys) dup.slice!(*keys) end |
#slice!(*keys) ⇒ Object
Alters the hash so it contains only the keys passed as arguments.
133 134 135 136 137 |
# File 'lib/epitools/core_ext/hash.rb', line 133 def slice!(*keys) keys = Set.new keys delete_if { |k,v| not keys.include? k } self end |
#symbolize_keys ⇒ Object
Return a hash with its keys converted to symbols, for great justice
118 119 120 |
# File 'lib/epitools/core_ext/hash.rb', line 118 def symbolize_keys dup.symbolize_keys! end |
#symbolize_keys! ⇒ Object
Convert the keys to symbols in-place, for fun and profit
111 112 113 |
# File 'lib/epitools/core_ext/hash.rb', line 111 def symbolize_keys! map_keys! { |k| k.to_sym } end |
#to_nicejson ⇒ Object Also known as: to_nice_json
Convert this Hash to indented JSON (using JSON.pretty_generate)
381 382 383 |
# File 'lib/epitools/core_ext/hash.rb', line 381 def to_nicejson JSON.pretty_generate(self) end |
#to_ostruct ⇒ Object
Convert this Hash (and all nested Hashes, and all nested Arrays containing Hashes) to OpenStruct(s)
372 373 374 375 376 |
# File 'lib/epitools/core_ext/hash.rb', line 372 def to_ostruct OpenStruct.new(self.map_values do |v| v.respond_to?(:to_ostruct) ? v.to_ostruct : v end) end |
#to_query ⇒ Object
Convert the hash into a GET query.
253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 |
# File 'lib/epitools/core_ext/hash.rb', line 253 def to_query params = '' stack = [] each do |k, v| if v.is_a?(Hash) stack << [k,v] else params << "#{k}=#{v}&" end end stack.each do |parent, hash| hash.each do |k, v| if v.is_a?(Hash) stack << ["#{parent}[#{k}]", v] else params << "#{parent}[#{k}]=#{v}&" end end end params.chop! # trailing & params end |
#translate_keys(mapping) ⇒ Object
Same as ‘translate_keys!`, except it returns a copy of the hash
104 105 106 |
# File 'lib/epitools/core_ext/hash.rb', line 104 def translate_keys(mapping) dup.translate_keys!(mapping) end |
#translate_keys!(mapping) ⇒ Object
Translate keys to other keys, given a hash of old-key to new-key mappings.
eg: hash.translate_keys!(
"Extreme Sports!!!!" => :extreme_sports,
"Mediocre sports" => :sports,
"Pretty okay sports" => :sports,
"Golf" => :liesure_activities,
)
91 92 93 94 95 96 97 98 99 |
# File 'lib/epitools/core_ext/hash.rb', line 91 def translate_keys!(mapping) # TODO: Allow regexes and lambdas (eg: translate_keys!(/.+/ => ->(key) { key.to_sym }) mapping.each do |src,dest| if includes? src self[dest] = delete(src) end end self end |
#tree(level = 0, indent = " ") ⇒ Object
Turn some nested hashes into a tree (returns an array of strings, padded on the left with indents.)
228 229 230 231 232 233 234 235 236 |
# File 'lib/epitools/core_ext/hash.rb', line 228 def tree(level=0, indent=" ") result = [] dent = indent * level each do |key, val| result << dent+key.to_s result += val.tree(level+1) if val.any? end result end |