Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
# Helper methods to encode and parse nested query strings without a
# third-party library (e.g. ActiveSupport, Addressable, or Rack).
module NestedQuery
autoload :CGI, 'cgi'
extend self
# Dumps a hash into a nested query string.
#
# NestedQuery.encode a: [1, 3], b: { 2 => 4 }, c: 5
# # => "a%5B%5D=1&a%5B%5D=3&b%5B2%5D=4&c=5"
def encode object, key = nil
case object
when Hash
object.map { |k, v| encode v, key ? "#{key}[#{k}]" : k }.sort * '&'
when Array
object.map { |o| encode o, "#{key}[]" } * '&'
else
"#{CGI.escape key.to_s}=#{CGI.escape object.to_s}"
end
end
# Parses a nested query string into a params hash.
#
# NestedQuery.parse "a%5B%5D=1&a%5B%5D=3&b%5B2%5D=4&c=5"
# # => {"a"=>["1", "3"], "b"=>{"2"=>"4"}, "c"=>"5"}
def parse string
string.scan(/([^=&]+)=([^=&]*)/).inject({}) do |hash, pair|
key, value = pair.map(&CGI.method(:unescape))
keypath, array = key.scan(/[^\[\]]+/), key[/\[\]$/]
keypath.inject(hash) do |nest, component|
next nest[component] ||= {} unless keypath.last == component
array ? (nest[component] ||= []) << value : nest[component] = value
end
hash
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment