module Collapsium::RecursiveFetch

Provides recursive (deep) fetch function for hashes.

Public Instance Methods

recursive_fetch(key, default = nil, &block)
Alias for: recursive_fetch_all
recursive_fetch_all(key, default = nil) { |self, ret, default| ... } click to toggle source

Fetches all matching keys as an array, or the default value if no match was found. Blocks work as in `#recursive_fetch`

# File lib/collapsium/recursive_fetch.rb, line 66
def recursive_fetch_all(key, default = nil, &block)
  result = []

  # Start simple at the top level.
  # rubocop:disable Lint/HandleExceptions
  begin
    ret = fetch(key, default)
    if ret != default
      if not block.nil?
        ret = yield self, ret, default
      end
      result << ret
    end
  rescue TypeError
    # Happens if self is an Array and key is a String that cannot
    # be converted to Integer.
  end
  # rubocop:enable Lint/HandleExceptions

  # We have to recurse for nested values
  result += map do |_, v|
    # If we have a Hash or Array, we need to recurse.
    if not (v.is_a? Hash or v.is_a? Array)
      next
    end

    enhanced = ViralCapabilities.enhance_value(self, v)
    inner = enhanced.recursive_fetch_all(key, default, &block)
    if inner != default
      next inner
    end
  end

  # Flatten and compact results to weed out non-matches
  result = result.flatten
  result.compact!

  if result.empty?
    return default
  end
  return result
end
Also aliased as: recursive_fetch
recursive_fetch_one(key, default = nil) { |self, result, default| ... } click to toggle source

Fetches the first matching key, or the default value if no match was found. If a block is given, it is passed the value containing the key (the parent), the value at the key, and the default value in that order. Note: Be careful when using blocks: it's return value becomes the match value. The typically correct behaviour is to return the match value passed to the block.

# File lib/collapsium/recursive_fetch.rb, line 28
def recursive_fetch_one(key, default = nil, &block)
  # Start simple at the top level.
  # rubocop:disable Lint/HandleExceptions
  begin
    result = fetch(key, default)
    if result != default
      if not block.nil?
        result = yield self, result, default
      end
      return result
    end
  rescue TypeError
    # Happens if self is an Array and key is a String that cannot
    # be converted to Integer.
  end
  # rubocop:enable Lint/HandleExceptions

  # We have to recurse for nested values
  result = map do |_, v|
    # If we have a Hash or Array, we need to recurse.
    if not (v.is_a? Hash or v.is_a? Array)
      next
    end

    enhanced = ViralCapabilities.enhance_value(self, v)
    inner = enhanced.recursive_fetch_one(key, default, &block)
    if inner != default
      next inner
    end
  end

  result.compact!
  return result[0] || default
end