summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Johansson <drenmi@gmail.com>2019-08-01 19:50:12 +0800
committerTed Johansson <drenmi@gmail.com>2019-08-03 10:09:50 +0800
commitcb2ab0baf6d5bec8fcdb1a45c215d521ff0f471c (patch)
tree13f1bb0bf0e23df8a03cadf0b8e38d75ceb72a05
parentbbd2a93f422508c615ae23d007c34b8bfb405b91 (diff)
downloadrack-cb2ab0baf6d5bec8fcdb1a45c215d521ff0f471c.tar.gz
Refactor QueryParser::Params#to_params_hash for readability and performance
-rw-r--r--lib/rack/query_parser.rb50
1 files changed, 35 insertions, 15 deletions
diff --git a/lib/rack/query_parser.rb b/lib/rack/query_parser.rb
index fce1ce91..2a4eb244 100644
--- a/lib/rack/query_parser.rb
+++ b/lib/rack/query_parser.rb
@@ -55,7 +55,7 @@ module Rack
end
end
- return params.to_params_hash
+ return params.to_h
end
# parse_nested_query expands a query string into structural types. Supported
@@ -73,7 +73,7 @@ module Rack
normalize_params(params, k, v, param_depth_limit)
end
- return params.to_params_hash
+ return params.to_h
rescue ArgumentError => e
raise InvalidParameterError, e.message
end
@@ -177,22 +177,42 @@ module Rack
@params.key?(key)
end
- def to_params_hash
- hash = @params
- hash.keys.each do |key|
- value = hash[key]
- if value.kind_of?(self.class)
- if value.object_id == self.object_id
- hash[key] = hash
- else
- hash[key] = value.to_params_hash
- end
- elsif value.kind_of?(Array)
- value.map! {|x| x.kind_of?(self.class) ? x.to_params_hash : x}
+ # Recursively unwraps nested `Params` objects and constructs an object
+ # of the same shape, but using the objects' internal representations
+ # (Ruby hashes) in place of the objects. The result is a hash consisting
+ # purely of Ruby primitives.
+ #
+ # Mutation warning!
+ #
+ # 1. This method mutates the internal representation of the `Params`
+ # objects in order to save object allocations.
+ #
+ # 2. The value you get back is a reference to the internal hash
+ # representation, not a copy.
+ #
+ # 3. Because the `Params` object's internal representation is mutable
+ # through the `#[]=` method, it is not thread safe. The result of
+ # getting the hash representation while another thread is adding a
+ # key to it is non-deterministic.
+ #
+ def to_h
+ @params.each do |key, value|
+ case value
+ when self
+ # Handle circular references gracefully.
+ @params[key] = @params
+ when Params
+ @params[key] = value.to_h
+ when Array
+ value.map! { |v| v.kind_of?(Params) ? v.to_h : v }
+ else
+ # Ignore anything that is not a `Params` object or
+ # a collection that can contain one.
end
end
- hash
+ @params
end
+ alias_method :to_params_hash, :to_h
end
end
end