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 that implements include? and fetch), using a key path expressed as a list (an object that implements inject).

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": "[email protected]",
      }
    },
    "charles": {
      first_name: "Charles",
      last_name: "Mulder",
    }
  }
}

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

Constant Summary collapse

VERSION =
"0.2.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.


52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/hash_pick.rb', line 52

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

  pick(hash, path) do |acc, p|
    if acc.include?(p.to_sym)
      acc.fetch(p.to_sym)
    elsif acc.include?(p.to_s)
      acc[p.to_s]
    else
      throw :break
    end
  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.


159
160
161
# File 'lib/hash_pick.rb', line 159

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 as the return value of the last iteration. If the block throws :break, iteration is aborted.

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]) do |p, k|
  throw :break unless p[:live] and p.include?(k)
  p[k]
end
# => "Sheldon"

HashPick.pick(dict, [:charles, :first_name]) do |p, k|
  throw :break unless p[:live] and p.include?(k)
  p[k]
end
# => "Hearn"

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.

Raises:

  • (ArgumentError)

    if hash isn't a dictionary.

  • (ArgumentError)

    if path isn't a list.


111
112
113
114
115
116
117
118
119
120
# File 'lib/hash_pick.rb', line 111

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.


198
199
200
201
# File 'lib/hash_pick.rb', line 198

def self.string(hash, path)
  assert_non_nil_path_keys(path)
  object(hash, path.map(&: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.


178
179
180
181
# File 'lib/hash_pick.rb', line 178

def self.symbol(hash, path)
  assert_non_nil_path_keys(path)
  object(hash, path.map(&:to_sym))
end