Module: Nuggets::Hash::DeepFetchMixin

Included in:
Hash
Defined in:
lib/nuggets/hash/deep_fetch_mixin.rb

Instance Method Summary collapse

Instance Method Details

#deep_fetch(path, separator = '/') ⇒ Object Also known as: %

call-seq:

hash.deep_fetch(path[, separator]) => anObject
hash.deep_fetch(path[, separator]) { |key| ... } => anObject

Recursively fetches keys in path, separated by separator if path is not an array, from hash. Maps each individual key according to the block if provided.

Examples:

hash = { 'foo' => { 'bar' => { 'baz' => 42 }, 'bay' => 23 } }
hash.deep_fetch('foo/bar/baz') #=> 42
hash.deep_fetch('foo/bar/bax') #=> nil
hash.deep_fetch('foo/bax/baz') #=> KeyError
hash.deep_fetch('foo/bay/baz') #=> TypeError
hash % 'foo/bar/baz' #=> 42
hash % %w[foo bar baz] #=> 42

hash = { foo: { bar: { baz: 42 } } }
hash.deep_fetch('foo/bar/baz', &:to_sym) #=> 42
hash % [:foo, :bar, :baz] #=> 42

Raises:

  • (::ArgumentError)


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/nuggets/hash/deep_fetch_mixin.rb', line 52

def deep_fetch(path, separator = '/')
  keys = path.is_a?(::Array) ? path : path.split(separator)
  raise ::ArgumentError, 'no keys given' if keys.empty?

  hash, klass = self, self.class

  loop {
    key = keys.shift
    key = yield key if block_given?

    return hash[key] if keys.empty?

    unless (hash = hash.fetch(key)).is_a?(klass)
      raise ::TypeError, '%p: %s expected, got %s' % [key, klass, hash.class]
    end
  }
end