Module: HashPick

Defined in:
lib/hash_pick.rb,
lib/hash_pick/version.rb

Overview

Fetch a value from a nested dictionary

Provides methods for fetching a value from a nested dictionary (an object structure whose root and branch nodes are Enumerable and implement []), using a key path expressed as a list (an Enumerable object whose each method yields a path key).

The key path is iterated. In each iteration, the key is looked up in the dictionary, and the value found is used as the dictionary for the next iteration. Lookup failure immediately returns nil.

Examples:

Indifferent hash path


require "hash_pick"

dict = {
  people: {
    "sheldon": {
      first_name: "Sheldon",
      last_name: "Hearn",
      contacts: {
        "email": "sheldonh@starjuice",
      }
    },
    "charles": {
      first_name: "Charles",
      last_name: "Mulder",
    }
  }
}

HashPick[dict, %w{people sheldon contacts email}] # -> "sheldonh@starjuice"
HashPick[dict, %w{people charles contacts email}] # -> nil

Constant Summary collapse

VERSION =
"1.0.0"

Class Method Summary collapse

Class Method Details

.indifferent(hash, path) ⇒ Object? Also known as: []

Fetch value from dictionary using string or symbol key path

Each value in the path is used as a symbol or, if symbol lookup fails, a string.

Parameters:

  • hash (Hash)

    the dictionary to apply the path to.

  • path (Array)

    an ordered list of keys that implement to_s and to_sym.

Returns:

  • (Object)

    the value found at the path in the dictionary.

  • (nil)

    if any key lookup failed.

Raises:

  • (ArgumentError)

    if hash isn’t a dictionary.

  • (ArgumentError)

    if path isn’t a list.

  • (ArgumentError)

    if any key in path is nil.



53
54
55
56
57
58
59
# File 'lib/hash_pick.rb', line 53

def self.indifferent(hash, path)
  assert_non_nil_path_keys(path)

  pick(hash, path) do |acc, p|
    acc[p.to_sym].nil? ? acc[p.to_s] : acc[p.to_sym]
  end
end

.object(hash, path) ⇒ Object?

Fetch value from dictionary using object key path

Each value in the path is used as is.

Parameters:

  • hash (Hash)

    the dictionary to apply the path to.

  • path (Array)

    an ordered list of object keys.

Returns:

  • (Object)

    the value found at the path in the dictionary.

  • (nil)

    if any key lookup failed.

Raises:

  • (ArgumentError)

    if hash isn’t a dictionary.

  • (ArgumentError)

    if path isn’t a list.



151
152
153
# File 'lib/hash_pick.rb', line 151

def self.object(hash, path)
  pick(hash, path) { |acc, p| acc[p] }
end

.pick(hash, path, &block) ⇒ Object?

General form of hash path iteration

Passes to block, the dictionary and hash key for each iteration of the hash path, using the return value of the block as the dictionary for the next iteration, or in the case of the last iteration, as the return value. If the block returns a non-dictionary in any but the last iteration, or if the block throws :break, iteration is aborted and nil is returned.

Examples:

Complex hash path semantics


require "hash_pick"

dict = {
  live: true,
  sheldon: {
    live: true,
    first_name: "Sheldon",
    last_name: "Hearn",
  },
  charles: {
    first_name: "Charles",
    last_name: "Mulder",
  }
}

HashPick.pick(dict, [:sheldon, :first_name]) { |p, k| p[k] if p[:live] }
# => "Sheldon"

HashPick.pick(dict, [:charles, :first_name]) { |p, k| p[k] if p[:live] }
# => nil

Parameters:

  • hash (Hash)

    the dictionary to apply the path to.

  • path (Array)

    an ordered list of path keys.

Returns:

  • (Object)

    the value of the last iteration.

  • (nil)

    if block throws :break in any iteration.

  • (nil)

    if block returns a non-dictionary for any but the last iteration.

Raises:

  • (ArgumentError)

    if hash isn’t a dictionary.

  • (ArgumentError)

    if path isn’t a list.



103
104
105
106
107
108
109
110
111
112
# File 'lib/hash_pick.rb', line 103

def self.pick(hash, path, &block)
  assert_dictionary(hash)
  assert_enumerable_path(path)
  catch(:break) do
    path.inject(hash) do |acc, p|
      break unless dictionary?(acc)
      block.call(acc, p)
    end
  end
end

.string(hash, path) ⇒ Object?

Fetch value from dictionary using string key path

Each value in the path is used as a string.

Parameters:

  • hash (Hash)

    the dictionary to apply the path to.

  • path (Array)

    an ordered list of keys that implement to_s.

Returns:

  • (Object)

    the value found at the path in the dictionary.

  • (nil)

    if any key lookup failed.

Raises:

  • (ArgumentError)

    if hash isn’t a dictionary.

  • (ArgumentError)

    if path isn’t a list.

  • (ArgumentError)

    if any key in path is nil.



190
191
192
193
# File 'lib/hash_pick.rb', line 190

def self.string(hash, path)
  assert_non_nil_path_keys(path)
  pick(hash, path) { |acc, p| acc[p.to_s] }
end

.symbol(hash, path) ⇒ Object?

Fetch value from dictionary using symbol key path

Each value in the path is used as a symbol.

Parameters:

  • hash (Hash)

    the dictionary to apply the path to.

  • path (Array)

    an ordered list of keys that implement to_sym.

Returns:

  • (Object)

    the value found at the path in the dictionary.

  • (nil)

    if any key lookup failed.

Raises:

  • (ArgumentError)

    if hash isn’t a dictionary.

  • (ArgumentError)

    if path isn’t a list.

  • (ArgumentError)

    if any key in path is nil.



170
171
172
173
# File 'lib/hash_pick.rb', line 170

def self.symbol(hash, path)
  assert_non_nil_path_keys(path)
  pick(hash, path) { |acc, p| acc[p.to_sym] }
end