私は最近 Ruby の仕事に応募し、「"query_to_hash" という名前の Ruby 関数を作成するメソッドをコーディングするように求められました。この関数は、HTTP クエリ文字列 (例: foo=bar&abc=1%202%203
) として単一の文字列引数を取り、次のような名前と値のペアのハッシュを返します。 :
{"foo" => "bar", "abc" => "1 2 3"}
添付のコード例を提供したところ、Ruby の私のスタイルは彼らが望んでいたものではないというフィードバックがありました。
開発者が添付ファイルでどのようなスタイルの問題を目にするか知りたいので、建設的なフィードバックをいただければ幸いです。
require 'rubygems'
require 'uri'
require 'rack'
include Rack::Utils
$SAFE = 3
# HTTP Query string (from wikipedia)
#field1=value1&field2=value2&field3=value3...
# The query string is composed of a series of field-value pairs.
# Within each pair, the field name and value are separated by an equals sign. The equals sign may be omitted if the value is an empty string.
# The series of pairs is separated by the ampersand, '&' (or semicolon, ';' for URLs embedded in HTML and not generated by a <form>...</form>; see below).
# While there is no definitive standard, most web frameworks allow multiple values to be associated with a single field[3][4]:
# field1=value1&field1=value2&field1=value3...
def query_to_hash(qry, sep = '&')
# assume input string conforms to spec (no validation)
# assume only & or ; is used - not both
# return a null string if value is not defined
# return null hash if query is null string
# return array of values in hash if field has multiple values
#@qry = qry.gsub(/%20/, " ")
@qry = URI.unescape(qry)
rtn = Hash.new {|h,k| h[k]=[]}
if @qry == "" then
# return an empty hash
#
return {}
else
qry_a = @qry.split(sep)
end
qry_a.each do |fv_pair|
pair = fv_pair.split('=')
# append multiple values if needed and ensure that null values are accommodated
#
rtn[pair[0]] << pair[1] ||= ""
end
# collapse array if it contains only one item
#
rtn.each{|k,v| rtn[k] = *v if v.length == 1}
end
puts "Using 'query_to_hash' method:"
puts
test_values = %w[foo=bar&abc=1%202%203
foo&abc=1%202%203
foo=&abc=1%202%203
foo=bar&foo=boo&abc=1%202%203
]
test_values.each { |v| puts "#{sprintf("%30s",v)} is returned as #{query_to_hash(v).inspect}" }
test_values = %w[ foo=bar;foo=boo;abc=1%202%203
foo=bar;foo=boo;abc=1%0A2%203
foo=bar;foo=boo;abc=1%092%0D3
]
test_values.each { |v| puts "#{sprintf("%30s",v)} is returned as #{query_to_hash(v, ';').inspect}" }
puts "#{sprintf("%30s", "null string")} is returned as #{query_to_hash("").inspect}"
# compare with Rack::Utils::parse_query
#
puts
puts "Using 'Rack::Utils::parse_query' method:"
puts
test_values = %w[foo=bar&abc=1%202%203
foo&abc=1%202%203
foo=&abc=1%202%203
foo=bar&foo=boo&abc=1%202%203
]
test_values.each { |v| puts "#{sprintf("%30s",v)} is returned as #{parse_query(v).inspect}" }
test_values = %w[ foo=bar;foo=boo;abc=1%202%203
foo=bar;foo=boo;abc=1%0A2%203
foo=bar;foo=boo;abc=1%092%0D3
]
test_values.each { |v| puts "#{sprintf("%30s",v)} is returned as #{parse_query(v, ';').inspect}" }
puts "#{sprintf("%30s", "null string")} is returned as #{parse_query("").inspect}"