lib/pact/consumer_contract/query.rb in pact-support-1.15.1 vs lib/pact/consumer_contract/query.rb in pact-support-1.15.2
- old
+ new
@@ -1,14 +1,112 @@
require 'pact/consumer_contract/query_hash'
require 'pact/consumer_contract/query_string'
module Pact
class Query
+ DEFAULT_SEP = /[&;] */n
+ COMMON_SEP = { ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n }
+
def self.create query
if query.is_a? Hash
Pact::QueryHash.new(query)
else
Pact::QueryString.new(query)
end
+ end
+
+ def self.parse_string query_string
+ parsed_query = parse_query(query_string)
+
+ # If Rails nested params...
+ if parsed_query.keys.any?{ | key| key.include?("[") }
+ parse_nested_query(query_string)
+ else
+ parsed_query.each_with_object({}) do | (key, value), new_hash |
+ new_hash[key] = [*value]
+ end
+ end
+ end
+
+ # Ripped from Rack to avoid adding an unnecessary dependency, thank you Rack
+ # https://github.com/rack/rack/blob/649c72bab9e7b50d657b5b432d0c205c95c2be07/lib/rack/utils.rb
+ def self.parse_query(qs, d = nil, &unescaper)
+ unescaper ||= method(:unescape)
+
+ params = {}
+
+ (qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
+ next if p.empty?
+ k, v = p.split('=', 2).map!(&unescaper)
+
+ if cur = params[k]
+ if cur.class == Array
+ params[k] << v
+ else
+ params[k] = [cur, v]
+ end
+ else
+ params[k] = v
+ end
+ end
+
+ return params.to_h
+ end
+
+ def self.parse_nested_query(qs, d = nil)
+ params = {}
+
+ unless qs.nil? || qs.empty?
+ (qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
+ k, v = p.split('=', 2).map! { |s| unescape(s) }
+
+ normalize_params(params, k, v)
+ end
+ end
+
+ return params.to_h
+ end
+
+ def self.normalize_params(params, name, v)
+ name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
+ k = $1 || ''
+ after = $' || ''
+
+ if k.empty?
+ if !v.nil? && name == "[]"
+ return Array(v)
+ else
+ return
+ end
+ end
+
+ if after == ''
+ params[k] = v
+ elsif after == "["
+ params[name] = v
+ elsif after == "[]"
+ params[k] ||= []
+ raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
+ params[k] << v
+ elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
+ child_key = $1
+ params[k] ||= []
+ raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
+ if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key)
+ normalize_params(params[k].last, child_key, v)
+ else
+ params[k] << normalize_params({}, child_key, v)
+ end
+ else
+ params[k] ||= {}
+ raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k])
+ params[k] = normalize_params(params[k], after, v, depth - 1)
+ end
+
+ params
+ end
+
+ def self.unescape(s, encoding = Encoding::UTF_8)
+ URI.decode_www_form_component(s, encoding)
end
end
end