module Aha::AugmentedHash

Public: Provides functionality for dealing with nested hashes.

Nested keys are represented by an array where the first element represents the the key to access the sub hash and the rest represent keys for that hash.

These arrays can be nested allowing us to represent keys for an arbitrarily nested hash. This way of representing keys is used throughout Aha and is heavily inspired by the Prismatic’s Clojure fnk style destructuring as seen here: github.com/Prismatic/plumbing/tree/master/src/plumbing/fnk

For example:

Given the hash {a: 'hello', b: {c: 'augmented', d: {e: 'hash'}}}
the keys :a, [:b, :c, [:d, :e]] would correspond to the values
'hello', 'augmented', 'hash'

Public Instance Methods

delete_in!(hash, *keys) click to toggle source

Public: Deletes a value within a nested hash. Equivalent to hash[..][kn-1].delete(kn)

hash - The nested hash to delete the value in. keys - They keys to the value to delete in order of depth.

Examples:

h = {:a => {'b' => {:c => 'hello', :d => 'world'}}}
delete_in! h, :a, 'b', :c
h
# => {:a => {'b' => {:d => 'world'}}}

Returns nothing.

# File lib/aha/augmented_hash.rb, line 127
def delete_in!(hash, *keys)
  last_key = keys.pop
  get_in(hash, *keys).delete last_key
end
exclude!(hash, *keys) click to toggle source

Public: Removes the excluded keys from the hash.

hash - The hash to exclude keys from. keys - The keys to be excluded from the hash. Supports nested key syntax.

Examples:

h = {:a => {'b' => {:c => 'hello', :d => 'augmented'}}, :e => 'hash'}
exclude! h, [:a, ['b', :d]], :e
h
# => {:a => {'b' => {:c => 'hello'}}}

Returns nothing.

# File lib/aha/augmented_hash.rb, line 145
def exclude!(hash, *keys)
  keys.each do |k|
    if k.is_a? Array
      subkey, *keys = k
      exclude!(hash[subkey], *keys)
    else
      hash.delete k
    end
  end
end
get_in(hash, *keys) click to toggle source

Public: Retrieves a value from a nested hash. Equivalent to hash[..][kn]

hash - The hash to retrieve the value from. keys - The keys to the value in order of depth.

Examples:

h = {:a => {'b' => {:c => 'value'}}}
get_in h, :a, 'b', :c
# => 'value'

Returns the value if it exists and nil otherwise

# File lib/aha/augmented_hash.rb, line 70
def get_in(hash, *keys)
  keys.reduce(hash) { |acc, k| acc[k] }
end
only(hash, *keys) click to toggle source

Public: Creates a new hash consisting only keys given and their corresponding values.

hash - The hash to base the result on. keys - The keys that the new hash will contain. Supports nested key

syntax.

Examples:

h = {:a => {'b' => {:c => 'hello', :d => 'augmented'}}, :e => 'hash'}
only h, [:a, ['b', :d]]
# => {:a => {'b' => {:d => 'augmented'}}}

Returns the new, smaller hash.

# File lib/aha/augmented_hash.rb, line 170
def only(hash, *keys)
  result = {}

  result.tap do |r|
    keys.each do |k|
      if k.is_a? Array
        subkey, *keys = k
        r[subkey] = only(hash[subkey], *keys)
      else
        r[k] = hash[k]
      end
    end
  end
end
put_in!(hash, *keys, val) click to toggle source

Public: Sets a value within a nested hash. Equivalent to hash[..][kn] = val

hash - The nested hash to set the value in. keys - The keys to the value to set in order of depth. val - The new value to set.

Examples:

h = {:a => {'b' => {:c => 'value'}}}
put_in! h, :a, 'b', :c, 'new_value'
h
# => {:a => {'b' => {:c => 'new_value'}}}

Returns nothing.

# File lib/aha/augmented_hash.rb, line 89
def put_in!(hash, *keys, val)
  last_key = keys.pop
  get_in(hash, *keys)[last_key] = val
end
update_in!(hash, *keys) { |get_in(hash, *keys)| ... } click to toggle source

Public: Updates a value within a nested hash.

hash - The nested hash to update the value in. keys - The keys to the current value in order of depth block - A required block that is given the current value and should return

the updated value to be set.

Examples:

h = {:a => {'b' => {:c => 33}}}
update_in!(h, :a, 'b', :c) { |v| v + 9}
h
# => {:a => {'b' => {:c => 42}}}

Returns nothing.

# File lib/aha/augmented_hash.rb, line 109
def update_in!(hash, *keys)
  put_in!(hash, *keys, yield(get_in(hash, *keys))) if block_given?
end
vals_at(hash, *keys) click to toggle source

Public: Similar to Hash#values_at except that it supports nested key syntax and is primarily intented to be used for destructuring assignment.

hash - The nested hash to extract values from. keys - They keys corresponding to the values to be extracted. Supports

nested key syntax.

Examples:

h = {'a' => 3, :b => {:c => 2, 'd' => {:e => 1}}}
value_1, value_2, value_3 = vals_at h, 'a', [:b, :c, ['d', :e]]

value_1
# => 3
value_2
# => 2
value_3
# => 1

Returns an array of values corresponding to the given keys.

# File lib/aha/augmented_hash.rb, line 42
def vals_at(hash, *keys)
  result = Aha::Helper::extract_option(:acc, keys) || []

  result.tap do |acc|
    keys.each do |k|
      if k.is_a? Array
        subkey, *keys = k
        vals_at(hash[subkey], *keys, {acc: acc})
      else
        acc << hash[k]
      end
    end
  end
end