Module: HashTools

Extended by:
HashTools
Included in:
HashTools
Defined in:
lib/hash_tools/indifferent.rb,
lib/hash_tools.rb,
lib/hash_tools/version.rb

Overview

A tiny version of HashWithIndifferentAccess. Works like a wrapper proxy around a Ruby Hash. Does not support all of the methods for a Ruby Hash object, but nevertheless can be useful for checking params and for working with parsed JSON.

Defined Under Namespace

Classes: Indifferent

Constant Summary collapse

FWD_SLASH =

Used as the default separator for deep_fetch

"/"
INT_KEY_RE =

Regular expression to detect array indices in the path (“phones/0/code”)

/^-?\d+$/.freeze
VERSION =
"1.2.5"

Instance Method Summary collapse

Instance Method Details

#deep_fetch(hash, path, separator: FWD_SLASH, &default_blk) ⇒ Object

Fetch a deeply-nested hash key from a hash, using a String representing a path

deep_fetch({
  'a' => {
    'b' => {
      'c' => value}}
}, 'a/b/c') #=> value

numbers for deeply nested arrays (‘foo/0/bar’)

Parameters:

  • hash (Hash)

    the (potentially deep) string-keyed Hash to fetch the value from

  • path (String)

    the path to the item in ‘hash`. The path may contain

  • separator (String) (defaults to: FWD_SLASH)

    the path separator, defaults to ‘/’

  • default_blk

    The default value block for when there is no value.

Returns:

  • the fetched value or the value of the default_block



23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/hash_tools.rb', line 23

def deep_fetch(hash, path, separator: FWD_SLASH, &default_blk)
  keys = path.split(separator)
  keys.inject(hash) do |hash_or_array, k|
    if !hash_or_array.respond_to?(:fetch)
      raise "#{hash_or_array.inspect} does not respond to #fetch"
    elsif hash_or_array.is_a?(Array) && k =~ INT_KEY_RE
      hash_or_array.fetch(k.to_i, &default_blk)
    else
      hash_or_array.fetch(k, &default_blk)
    end
  end
end

#deep_fetch_multi(hash, *key_paths, separator: FWD_SLASH) ⇒ Array

Fetches multiple keys from a deep hash, using a Strings representing paths

deep_fetch({
  'z' => 1,
  'a' => {
    'b' => {
      'c' => value}}
}, 'a/b', 'z') #=> [value, 1]

contain numbers for deeply nested arrays (‘foo/0/bar’)

Parameters:

  • hash (Hash)

    the (potentially deep) string-keyed Hash to fetch the value from

  • key_paths (String)

    the paths to the items in ‘hash`. The paths may

  • separator (String) (defaults to: FWD_SLASH)

    the path separator, defaults to ‘/’

Returns:

  • (Array)

    the fetched values



50
51
52
# File 'lib/hash_tools.rb', line 50

def deep_fetch_multi(hash, *key_paths, separator: FWD_SLASH)
  key_paths.map { |k| deep_fetch(hash, k, separator: separator) }
end

#deep_map_value(enum_of_hashes, path, separator: FWD_SLASH) ⇒ Array

Fetches a deeply nested key from each of the Hashes in a given Array.

arr = [
  {'age' => 12, 'name' => 'Jack'},
  {'age' => 25, 'name' => 'Joe'},
]
deep_map_value(arr, 'age') => [12, 25]

Parameters:

  • enum_of_hashes (Enumerable)

    a list of Hash objects to fetch the values from

  • path (String)

    the paths to the value. Paths may contain numbers for deeply nested arrays (‘foo/0/bar’)

  • separator (String) (defaults to: FWD_SLASH)

    the path separator, defaults to ‘/’

Returns:

  • (Array)

    the fetched values



66
67
68
# File 'lib/hash_tools.rb', line 66

def deep_map_value(enum_of_hashes, path, separator: FWD_SLASH)
  enum_of_hashes.map { |h| deep_fetch(h, path, separator: separator) }
end

#indifferent(hash) ⇒ Indifferent

Returns an Indifferent wrapper for the given Hash.

Parameters:

  • hash (Hash)

    the Hash to wrap

Returns:



134
135
136
# File 'lib/hash_tools.rb', line 134

def indifferent(hash)
  Indifferent.new(hash)
end

#transform_keys_of(any, &transformer) ⇒ Hash

Recursively convert hash keys using a block. using a passed block. The block will receive a hash key to be transformed and should return a transformed key For example, to go from uderscored notation to camelized:

h = {'foo_bar' => 1}
transform_keys_of(h) {|k| k.to_s.camelize(:lower) } # => {'fooBar' => 1}

Parameters:

  • any (Hash)

    the Hash to transform

  • transformer

    the block to apply to each key, recursively

Returns:

  • (Hash)

    the transformed Hash



115
116
117
118
119
120
121
122
123
124
125
126
127
128
# File 'lib/hash_tools.rb', line 115

def transform_keys_of(any, &transformer)
  case any
  when Array
    any.map { |e| transform_keys_of(e, &transformer) }
  when Hash
    h = {}
    any.each_pair do |k, v|
      h[transformer.call(k.to_s)] = transform_keys_of(v, &transformer)
    end
    h
  else
    any
  end
end

#transform_string_keys_and_values_of(any, &transformer) ⇒ Object

Recursively transform string keys and values of a passed Hash or Array using the passed transformer

Parameters:

  • any (Hash, String, Array)

    the value to transform the contained items in

  • transformer

    The block applied to each string key and value, recursively

Returns:

  • the transformed value



76
77
78
# File 'lib/hash_tools.rb', line 76

def transform_string_keys_and_values_of(any, &transformer)
  transform_string_values_of(transform_keys_of(any, &transformer), &transformer)
end

#transform_string_values_of(any, &transformer) ⇒ Object

Recursively convert string values in nested hashes and arrays using a passed block. The block will receive the String to transform and should return a transformed string.

Parameters:

  • any (Hash, String, Array)

    the value to transform the contained items in

  • transformer

    The block applied to each string value, recursively

Returns:

  • the transformed value



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/hash_tools.rb', line 87

def transform_string_values_of(any, &transformer)
  case any
  when String
    transformer.call(any)
  when Array
    any.map { |e| transform_string_values_of(e, &transformer) }
  when Hash
    h = {}
    any.each_pair do |k, v|
      h[k] = transform_string_values_of(v, &transformer)
    end
    h
  else
    any
  end
end