Skip to content

Instantly share code, notes, and snippets.

@kwatch
Created March 2, 2011 03:15
Show Gist options
  • Save kwatch/850407 to your computer and use it in GitHub Desktop.
Save kwatch/850407 to your computer and use it in GitHub Desktop.
benchmark to measure parsing both 'user[123][name]' and 'user.123.name'
###
### benchmark to measure parsing both 'user[123][name]' and 'user.123.name'
###
require 'rubygems'
require 'benchmarker'
## copied from rack/utils.rb
def unescape(s)
s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
[$1.delete('%')].pack('H*')
}
end
DEFAULT_SEP = /[&;] */n
def parse_nested_query(qs, d = nil)
params = {}
(qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
k, v = unescape(p).split('=', 2)
normalize_params(params, k, v)
end
return params
end
def normalize_params(params, name, v = nil)
name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
k = $1 || ''
after = $' || ''
return if k.empty?
if after == ""
params[k] = v
elsif after == "[]"
params[k] ||= []
raise TypeError, "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 TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key)
normalize_params(params[k].last, child_key, v)
else
params[k] << normalize_params({}, child_key, v)
end
else
params[k] ||= {}
raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash)
params[k] = normalize_params(params[k], after, v)
end
return params
end
##
def parse_dotted_query(qs, d=nil)
params = {}
rexp = d ? /[#{d}] */n : DEFAULT_SEP
(qs || '').split(rexp).each do |p|
k, v = unescape(p).split('=', 2)
normalize_dotted_params(params, k, v)
end
return params
end
def normalize_dotted_params(params, k, v)
items = k.split(/\./)
hash = params
items[0...-1].each do |item|
if hash[item].is_a?(Hash)
hash = hash[item]
else
hash = hash[item] = {}
end
end
item = items[-1]
#if item.end_with?('[]')
if item =~ /\[\]\z/
item = item[0...-2]
if hash[item].is_a?(Array)
hash[item] << v
else
hash[item] = [v]
end
else
hash[item] = v
end
end
query1 = "user[123][name]=Haruhi&user[123][mail]=haruhi@sos.org&user[123][items][]=Mikuru&user[123][items][]=Yuki"
p parse_nested_query(query1)
query2 = "user.123.name=Haruhi&user.123.mail=haruhi@sos.org&user.123.items[]=Mikuru&user.123.items[]=Yuki"
p parse_dotted_query(query2)
nloop = 10*1000
Benchmarker.new(:cycle=>5, :extra=>1) do |bm|
bm.task("parse_nested_query()") do
nloop.times { parse_nested_query(query1) }
end
bm.task("parse_dotted_query()") do
nloop.times { parse_dotted_query(query2) }
end
end
__END__
# benchmarker.rb: release 0.0.0
# RUBY_VERSION: 1.8.7
# RUBY_PATCHLEVEL: 334
# RUBY_PLATFORM: i686-darwin10.6.0
#
# ## Ranking real
# parse_dotted_query() 8.2658 (100.0%) ********************
# parse_nested_query() 12.6859 ( 65.2%) *************
# benchmarker.rb: release 0.0.0
# RUBY_VERSION: 1.9.2
# RUBY_PATCHLEVEL: 180
# RUBY_PLATFORM: x86_64-darwin10.6.0
#
# ## Ranking real
# parse_dotted_query() 7.1663 (100.0%) ********************
# parse_nested_query() 10.3392 ( 69.3%) **************
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment