Module: Aha::AugmentedHash

Extended by:
AugmentedHash
Included in:
AugmentedHash
Defined in:
lib/aha/augmented_hash.rb

Overview

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'

Instance Method Summary collapse

Instance Method Details

#delete_in!(hash, *keys) ⇒ Object

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.



127
128
129
130
# 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) ⇒ Object

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.



145
146
147
148
149
150
151
152
153
154
# 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) ⇒ Object

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



70
71
72
# File 'lib/aha/augmented_hash.rb', line 70

def get_in(hash, *keys)
  keys.reduce(hash) { |acc, k| acc[k] }
end

#only(hash, *keys) ⇒ Object

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.



170
171
172
173
174
175
176
177
178
179
180
181
182
183
# 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) ⇒ Object

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.



89
90
91
92
# 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) ⇒ Object

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.



109
110
111
# 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) ⇒ Object

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.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
# 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