Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build queries containing boolean values #286

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 6 additions & 2 deletions lib/rack/utils.rb
Expand Up @@ -92,7 +92,11 @@ def normalize_params(params, name, v = nil)
return if k.empty?

if after == ""
params[k] = v
if v == "false" || v == "true"
params[k] = eval(v)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not happy with having them automatically transformed, but even more is that eval hurting my eyes :)

case v
when /false/i
  params[k] = false
when /true/i
  params[k] = true
else
  params[k] = v
end

A bit more verbose, but way faster.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see the benefits of removing the eval statement but is case insensitive matching for the whole string appropriate? I don't thnk trUe and FALse were ever intended to get boiled down to booleans.

How about:

case v
when /[F|f]alse/
  params[k] = false
 when /[T|t]rue/
  params[k] = true

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now we're getting into real opinion territory. If we want to restrict the format, then full uppercase, lowercase and camel case would seem to make sense. I'm not sure why we're invoking the regex engine here. Why don't we just use the case statement the whole way?

case v
when "true", "True", "TRUE"
  params[k] = true
when "false", "False", "FALSE"
  params[k] = false
else
  params[k] = v
end

Sadly, this probably optimizes better like so:

BOOLEAN_COERCIONS = {
  "true" => true,
  "True" => true,
  "TRUE" => true,
  "false" => false,
  "False" => false,
  "FALSE" => false
}

def coerce_param(v)
  BOOLEAN_COERCIONS[v] || v
end

Something like this could also be considered configurable, at least you don't have to alter the code to alter it's input and output sets.

else
params[k] = v
end
elsif after == "[]"
params[k] ||= []
raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
Expand Down Expand Up @@ -137,7 +141,7 @@ def build_nested_query(value, prefix = nil)
value.map { |k, v|
build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
}.join("&")
when String
when String, TrueClass, FalseClass
raise ArgumentError, "value must be a Hash" if prefix.nil?
"#{prefix}=#{escape(value)}"
else
Expand Down
9 changes: 8 additions & 1 deletion test/spec_utils.rb
Expand Up @@ -212,6 +212,12 @@ def kcodeu
should.equal "foo[]="
Rack::Utils.build_nested_query("foo" => ["bar"]).
should.equal "foo[]=bar"
Rack::Utils.build_nested_query("foo" => true).
should.equal "foo=true"
Rack::Utils.build_nested_query("foo" => false).
should.equal "foo=false"
Rack::Utils.build_nested_query("foo" => {"bar" => true}).
should.equal "foo[bar]=true"

# The ordering of the output query string is unpredictable with 1.8's
# unordered hash. Test that build_nested_query performs the inverse
Expand All @@ -232,7 +238,8 @@ def kcodeu
{"x" => {"y" => [{"v" => {"w" => "1"}}]}},
{"x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}},
{"x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}},
{"x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}}
{"x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}},
{"foo" => false}, {"foo" => {"bar" => true}}
].each { |params|
qs = Rack::Utils.build_nested_query(params)
Rack::Utils.parse_nested_query(qs).should.equal params
Expand Down