module ObjectTraverser
  def extract_value(keys, value)
    return nil if value.nil?

    key = keys.shift
    return nil if key.nil?

    # if the current value is not a Hash or Array, it is undefined
    # behavior so value will be assigned nil by default.
    value = if value.is_a?(Array)
              extract_from_array(key, value)
            elsif value.is_a?(Hash)
              extract_from_hash(key, value)
            end

    # if there are no more keys, just return the value
    return value if keys.first.nil?

    # if there are more keys, extract more
    extract_value(keys.clone, value)
  end

  private

  # If the values to return from is an Array, allow returning by index.
  # Otherwise, support methods on the Array itself.
  def extract_from_array(key, value)
    if key.is_a?(Integer)
      value[key]
    elsif value.respond_to?(key.to_sym)
      value.send(key.to_sym)
    end
  end

  # for Hashes, try to return the value by the key.
  # We first try to find by the raw key before we stringify
  # if the keys themselves are symbols, for example.
  #
  # This will return nil default if we can't find the key.
  def extract_from_hash(key, value)
    if value.key?(key)
      value[key]
    elsif value.key?(key.to_s)
      value[key.to_s]
    end
  end
end
