Permalink
Fetching contributors…
Cannot retrieve contributors at this time
199 lines (179 sloc) 5.67 KB
require "forwardable"
module Faraday
module NestedParamsEncoder
class << self
extend Forwardable
def_delegators :'Faraday::Utils', :escape, :unescape
end
def self.encode(params)
return nil if params == nil
if !params.is_a?(Array)
if !params.respond_to?(:to_hash)
raise TypeError,
"Can't convert #{params.class} into Hash."
end
params = params.to_hash
params = params.map do |key, value|
key = key.to_s if key.kind_of?(Symbol)
[key, value]
end
# Useful default for OAuth and caching.
# Only to be used for non-Array inputs. Arrays should preserve order.
params.sort!
end
# Helper lambda
to_query = lambda do |parent, value|
if value.is_a?(Hash)
value = value.map do |key, val|
key = escape(key)
[key, val]
end
value.sort!
buffer = ""
value.each do |key, val|
new_parent = "#{parent}%5B#{key}%5D"
buffer << "#{to_query.call(new_parent, val)}&"
end
return buffer.chop
elsif value.is_a?(Array)
new_parent = "#{parent}%5B%5D"
return new_parent if value.empty?
buffer = ""
value.each_with_index do |val, i|
buffer << "#{to_query.call(new_parent, val)}&"
end
return buffer.chop
elsif value.nil?
return parent
else
encoded_value = escape(value)
return "#{parent}=#{encoded_value}"
end
end
# The params have form [['key1', 'value1'], ['key2', 'value2']].
buffer = ''
params.each do |parent, value|
encoded_parent = escape(parent)
buffer << "#{to_query.call(encoded_parent, value)}&"
end
return buffer.chop
end
def self.decode(query)
return nil if query == nil
params = {}
query.split("&").each do |pair|
next if pair.empty?
key, value = pair.split("=", 2)
key = unescape(key)
value = unescape(value.gsub(/\+/, ' ')) if value
subkeys = key.scan(/[^\[\]]+(?:\]?\[\])?/)
context = params
subkeys.each_with_index do |subkey, i|
is_array = subkey =~ /[\[\]]+\Z/
subkey = $` if is_array
last_subkey = i == subkeys.length - 1
if !last_subkey || is_array
value_type = is_array ? Array : Hash
if context[subkey] && !context[subkey].is_a?(value_type)
raise TypeError, "expected %s (got %s) for param `%s'" % [
value_type.name,
context[subkey].class.name,
subkey
]
end
context = (context[subkey] ||= value_type.new)
end
if context.is_a?(Array) && !is_array
if !context.last.is_a?(Hash) || context.last.has_key?(subkey)
context << {}
end
context = context.last
end
if last_subkey
if is_array
context << value
else
context[subkey] = value
end
end
end
end
dehash(params, 0)
end
# Internal: convert a nested hash with purely numeric keys into an array.
# FIXME: this is not compatible with Rack::Utils.parse_nested_query
def self.dehash(hash, depth)
hash.each do |key, value|
hash[key] = dehash(value, depth + 1) if value.kind_of?(Hash)
end
if depth > 0 && !hash.empty? && hash.keys.all? { |k| k =~ /^\d+$/ }
hash.keys.sort.inject([]) { |all, key| all << hash[key] }
else
hash
end
end
end
module FlatParamsEncoder
class << self
extend Forwardable
def_delegators :'Faraday::Utils', :escape, :unescape
end
def self.encode(params)
return nil if params == nil
if !params.is_a?(Array)
if !params.respond_to?(:to_hash)
raise TypeError,
"Can't convert #{params.class} into Hash."
end
params = params.to_hash
params = params.map do |key, value|
key = key.to_s if key.kind_of?(Symbol)
[key, value]
end
# Useful default for OAuth and caching.
# Only to be used for non-Array inputs. Arrays should preserve order.
params.sort!
end
# The params have form [['key1', 'value1'], ['key2', 'value2']].
buffer = ''
params.each do |key, value|
encoded_key = escape(key)
value = value.to_s if value == true || value == false
if value == nil
buffer << "#{encoded_key}&"
elsif value.kind_of?(Array)
value.each do |sub_value|
encoded_value = escape(sub_value)
buffer << "#{encoded_key}=#{encoded_value}&"
end
else
encoded_value = escape(value)
buffer << "#{encoded_key}=#{encoded_value}&"
end
end
return buffer.chop
end
def self.decode(query)
empty_accumulator = {}
return nil if query == nil
split_query = (query.split('&').map do |pair|
pair.split('=', 2) if pair && !pair.empty?
end).compact
return split_query.inject(empty_accumulator.dup) do |accu, pair|
pair[0] = unescape(pair[0])
pair[1] = true if pair[1].nil?
if pair[1].respond_to?(:to_str)
pair[1] = unescape(pair[1].to_str.gsub(/\+/, " "))
end
if accu[pair[0]].kind_of?(Array)
accu[pair[0]] << pair[1]
elsif accu[pair[0]]
accu[pair[0]] = [accu[pair[0]], pair[1]]
else
accu[pair[0]] = pair[1]
end
accu
end
end
end
end