module KeyTree::Refine::DeepHash

Refinements to Hash for deep_ methods, for traversing nested structures

Public Instance Methods

deep → Enumerator click to toggle source

Return a deep enumerator for all (key_path, value) pairs in a nested hash structure.

# File lib/key_tree/refine/deep_hash.rb, line 13
def deep
  Enumerator.new do |yielder|
    deep_enumerator(yielder)
  end
end
deep_delete(key_path) click to toggle source

Delete a leaf value in a nested hash structure

Raises KeyError if a prefix of the key_path has a value.

# File lib/key_tree/refine/deep_hash.rb, line 63
def deep_delete(key_path)
  *prefix_path, last_key = key_path
  result = prefix_path.reduce(self) do |hash, key|
    result = hash.fetch(key, nil)
    next result if result.is_a?(Hash)

    raise KeyError, %(prefix has value: "#{key_path}")
  end
  result.delete(last_key)
end
deep_enumerator(yielder, prefix = []) click to toggle source
# File lib/key_tree/refine/deep_hash.rb, line 145
def deep_enumerator(yielder, prefix = [])
  each do |key, value|
    key_path = prefix + [key]
    yielder << [key_path, value]
    value.deep_enumerator(yielder, key_path) if value.is_a?(Hash)
  end
end
deep_fetch(key_path) → value click to toggle source
deep_fetch(key_path, default) → value || default
deep_fetch(key_path) { |key_path| block } → value || block

Fetch a leaf value from a nested hash structure

# File lib/key_tree/refine/deep_hash.rb, line 25
def deep_fetch(key_path, *default)
  catch do |ball|
    result = key_path.reduce(self) do |hash, key|
      throw ball unless hash.is_a?(Hash)
      hash.fetch(key) { throw ball }
    end
    return result unless result.is_a?(Hash)
  end
  return yield(key_path) if block_given?
  return default.first unless default.empty?

  raise KeyError, %(key path invalid: "#{key_path}")
end
deep_key_pathify → Hash click to toggle source

Comvert any keys containing a . in a hash structure to nested hashes.

# File lib/key_tree/refine/deep_hash.rb, line 137
def deep_key_pathify
  each_with_object({}) do |(key, value), result|
    key_path = Path[key]
    value = value.deep_key_pathify if value.is_a?(Hash)
    result.deep_store(key_path, value)
  end
end
deep_merge(other) → self click to toggle source
deep_merge(other) { |key_path, lhs, rhs| } → self

Deeply merge nested hash structures

# File lib/key_tree/refine/deep_hash.rb, line 95
def deep_merge(other, prefix = [], &block)
  merge(other) do |key, lhs, rhs|
    key_path = prefix + [key]
    both_are_hashes = lhs.is_a?(Hash) && rhs.is_a?(Hash)
    next lhs.deep_merge(rhs, key_path, &block) if both_are_hashes
    next yield(key_path, lhs, rhs) unless block.nil?

    rhs
  end
end
deep_merge!(other) → self click to toggle source
deep_merge!(other) { |key_path, lhs, rhs| } → self

Deeply merge nested hash structures

# File lib/key_tree/refine/deep_hash.rb, line 79
def deep_merge!(other, prefix = [], &block)
  merge!(other) do |key, lhs, rhs|
    key_path = prefix + [key]
    both_are_hashes = lhs.is_a?(Hash) && rhs.is_a?(Hash)
    next lhs.deep_merge!(rhs, key_path, &block) if both_are_hashes
    next yield(key_path, lhs, rhs) unless block.nil?

    rhs
  end
end
deep_store(key_path, new_value) → new_value click to toggle source

Store a new value in a nested hash structure, expanding it if necessary.

Raises KeyError if a prefix of the key_path has a value.

# File lib/key_tree/refine/deep_hash.rb, line 46
def deep_store(key_path, new_value)
  *prefix_path, last_key = key_path
  result = prefix_path.reduce(self) do |hash, key|
    result = hash.fetch(key) { hash[key] = {} }
    next result if result.is_a?(Hash)

    raise KeyError, %(prefix has value: "#{key_path}")
  end
  result[last_key] = new_value
end
deep_transform_keys { |key| block } click to toggle source

Transform keys in a nested hash structure

# File lib/key_tree/refine/deep_hash.rb, line 110
def deep_transform_keys(&block)
  result = transform_keys(&block)
  result.transform_values! do |value|
    next value unless value.is_a?(Hash)

    value.deep_transform_keys(&block)
  end
end
deep_transform_keys! { |key| block } click to toggle source

Transform keys in a nested hash structure

# File lib/key_tree/refine/deep_hash.rb, line 123
def deep_transform_keys!(&block)
  result = transform_keys!(&block)
  result.transform_values! do |value|
    next value unless value.is_a?(Hash)

    value.deep_transform_keys!(&block)
  end
end