class Hash

Public Class Methods

lazy!() click to toggle source

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.

# 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() click to toggle source

Returns a new Hash whose values default to empty arrays. (Good for collecting things!)

eg:

Hash.of_arrays[:yays] << "YAY!"
# File lib/epitools/core_ext/hash.rb, line 145
def self.of_arrays
  new {|h,k| h[k] = [] }
end
of_integers() click to toggle source

Returns a new Hash whose values default to 0. (Good for counting things!)

eg:

Hash.of_integers[:yays] += 1
# File lib/epitools/core_ext/hash.rb, line 165
def self.of_integers
  new(0)
end
of_sets() click to toggle source

Returns a new Hash whose values default to empty sets. (Good for collecting unique things!)

eg:

Hash.of_sets[:yays] << "Yay!"
# File lib/epitools/core_ext/hash.rb, line 155
def self.of_sets
  new {|h,k| h[k] = Set.new }
end
of_unique_ids() click to toggle source

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}
# File lib/epitools/core_ext/hash.rb, line 182
def self.of_unique_ids
  new { |h,k| h[k] = h.size }
end

Public Instance Methods

+(other) click to toggle source

`hash1 + hash2` merge the two hashes, returning a new hash

# File lib/epitools/core_ext/hash.rb, line 7
def +(other)
  merge(other)
end
-(other) click to toggle source

`hash1 - hash2` removes keys from hash1 that exist in hash2, returning a new hash

# File lib/epitools/core_ext/hash.rb, line 14
def -(other)
  dup.delete_if { |k,v| other.includes?(k) }
end
apply_diff(changes) click to toggle source

Applies a Hash#diff changeset and returns the transformed hash.

# File lib/epitools/core_ext/hash.rb, line 353
def apply_diff(changes)
  deep_dup.apply_diff!(changes)
end
apply_diff!(changes) click to toggle source

Applies a Hash#diff changeset to this hash.

# 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?() click to toggle source

'true' if the Hash has no entries

# File lib/epitools/core_ext/hash.rb, line 21
def blank?
  not any?
end
deep_dup() click to toggle source

Duplicate this hash, including hashes nested inside of it.

# 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) click to toggle source

Return all the changes necessary to transform `self` into `other`. (Works on nested hashes.) The result is a hash of {:key => [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”.)

# 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) click to toggle source

Transforms the keys of the hash by passing them into the supplied block, and then using the blocks result as the new key.

# File lib/epitools/core_ext/hash.rb, line 76
def map_keys(&block)
  dup.map_keys!(&block)
end
Also aliased as: transform_keys
map_keys!() { |key| ... } click to toggle source

Runs map_keys on self.

# 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
Also aliased as: transform_keys!
map_values(&block) click to toggle source

Transforms the values of the hash by passing them into the supplied block, and then using the block's result as the new value.

# File lib/epitools/core_ext/hash.rb, line 56
def map_values(&block)
  dup.map_values!(&block)
end
map_values!() { |value| ... } click to toggle source

Runs map_values on self.

# 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
method_missing(name, *args) click to toggle source
Calls superclass method
# File lib/epitools/core_ext/hash.rb, line 192
def method_missing(name, *args)
  if args.any?
    super
  else
    self[name] || self[name.to_s]
  end
end
mkdir_p(path) click to toggle source

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"=>{}}}}
# 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
mql(template)
Alias for: query
print_tree(level=0, indent=" ") { |key, level| ... } click to toggle source

Print the result of `tree`

query(template) click to toggle source

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")
# 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
Also aliased as: mql
remove_blank_values() click to toggle source

Returns a new Hash where blank values have been removed. (It checks if the value is blank by calling blank? on it)

# File lib/epitools/core_ext/hash.rb, line 37
def remove_blank_values
  dup.remove_blank_values!
end
remove_blank_values!() click to toggle source

Runs “remove_blank_values” on self.

# File lib/epitools/core_ext/hash.rb, line 28
def remove_blank_values!
  delete_if{|k,v| v.blank?}
  self
end
slice(*keys) click to toggle source

Returns a hash containing only the keys passed as arguments.

# File lib/epitools/core_ext/hash.rb, line 125
def slice(*keys)
  dup.slice!(*keys)
end
slice!(*keys) click to toggle source

Alters the hash so it contains only the keys passed as arguments.

# 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() click to toggle source

Return a hash with its keys converted to symbols, for great justice

# File lib/epitools/core_ext/hash.rb, line 118
def symbolize_keys
  dup.symbolize_keys!
end
symbolize_keys!() click to toggle source

Convert the keys to symbols in-place, for fun and profit

# File lib/epitools/core_ext/hash.rb, line 111
def symbolize_keys!
  map_keys! { |k| k.to_sym }
end
to_nice_json()
Alias for: to_nicejson
to_nicejson() click to toggle source

Convert this Hash to indented JSON (using JSON.pretty_generate)

# File lib/epitools/core_ext/hash.rb, line 381
def to_nicejson
  JSON.pretty_generate(self)
end
Also aliased as: to_nice_json
to_ostruct() click to toggle source

Convert this Hash (and all nested Hashes, and all nested Arrays containing Hashes) to OpenStruct(s)

# 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() click to toggle source

Convert the hash into a GET query.

# 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
transform_keys(&block)
Alias for: map_keys
transform_keys!(&block)
Alias for: map_keys!
translate_keys(mapping) click to toggle source

Same as `translate_keys!`, except it returns a copy of the hash

# File lib/epitools/core_ext/hash.rb, line 104
def translate_keys(mapping)
  dup.translate_keys!(mapping)
end
translate_keys!(mapping) click to toggle source

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,
)
# 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=" ") click to toggle source

Turn some nested hashes into a tree (returns an array of strings, padded on the left with indents.)

# 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