Skip to content

Commit

Permalink
Add URI::Params#merge, #merge! and URI#update_query_params (#13415
Browse files Browse the repository at this point in the history
)

Co-authored-by: Quinton Miller <[email protected]>
  • Loading branch information
skinnyjames and HertzDevil authored May 17, 2023
1 parent 0135d69 commit 0410331
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 0 deletions.
58 changes: 58 additions & 0 deletions spec/std/uri/params_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,64 @@ class URI
end
end

describe "#merge!" do
it "modifies the reciever" do
params = Params.parse("foo=bar&foo=baz&qux=zoo")
other_params = Params.parse("foo=buzz&foo=extra")

params.merge!(other_params, replace: false)

params.to_s.should eq("foo=bar&foo=baz&foo=buzz&foo=extra&qux=zoo")
end

describe "does not modify the other params" do
it "with replace: true" do
params = Params.parse("foo=bar")
other_params = Params.parse("foo=buzz&foo=extra")

params.merge!(other_params, replace: true)
params.add("foo", "another")

other_params.to_s.should eq("foo=buzz&foo=extra")
end

it "with replace: false" do
params = Params.parse("foo=bar")
other_params = Params.parse("foo=buzz&foo=extra")

params.merge!(other_params, replace: false)
params.add("foo", "another")

other_params.to_s.should eq("foo=buzz&foo=extra")
end
end
end

describe "#merge" do
it "replaces all values with the same key by default" do
params = Params.parse("foo=bar&foo=baz&qux=zoo")
other_params = Params.parse("foo=buzz&foo=extra")

params.merge(other_params).to_s.should eq("foo=buzz&foo=extra&qux=zoo")
end

it "appends values with the same key with replace: false" do
params = Params.parse("foo=bar&foo=baz&qux=zoo")
other_params = Params.parse("foo=buzz&foo=extra")

params.merge(other_params, replace: false).to_s.should eq("foo=bar&foo=baz&foo=buzz&foo=extra&qux=zoo")
end

it "does not modify the reciever" do
params = Params.parse("foo=bar&foo=baz&qux=zoo")
other_params = Params.parse("foo=buzz&foo=extra")

params.merge(other_params)

params.to_s.should eq("foo=bar&foo=baz&qux=zoo")
end
end

describe "#empty?" do
it "test empty?" do
Params.parse("foo=bar&foo=baz&baz=qux").empty?.should be_false
Expand Down
17 changes: 17 additions & 0 deletions spec/std/uri_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,23 @@ describe "URI" do
end
end

describe "#update_query_params" do
it "returns self" do
expected_params = URI::Params{"id" => "30"}

uri = URI.parse("http://foo.com?id=30&limit=5#time=1305298413")
uri.update_query_params { |params| params.delete("limit") }.should be(uri)
uri.query_params.should eq(expected_params)
end

it "commits changes to the URI::Object" do
uri = URI.parse("http://foo.com?id=30&limit=5#time=1305298413")
uri.update_query_params { |params| params.delete("limit") }

uri.to_s.should eq("http://foo.com?id=30#time=1305298413")
end
end

describe "#==" do
it { URI.parse("http://example.com").should eq(URI.parse("http://example.com")) }
end
Expand Down
20 changes: 20 additions & 0 deletions src/uri.cr
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,26 @@ class URI
self.query = params.to_s
end

# Yields the value of `#query_params` commits any modifications of the `URI::Params` instance to self.
# Returns the modified `URI::Params`
#
# ```
# require "uri"
# uri = URI.parse("http://foo.com?id=30&limit=5#time=1305298413")
# uri.update_query_params { |params| params.delete_all("limit") } # => URI::Params{"id" => ["30"]}
#
# puts uri.to_s # => "http://foo.com?id=30#time=1305298413"
# ```
def update_query_params(& : URI::Params -> _) : URI
params = query_params

yield params

self.query_params = params

self
end

# Returns the authority component of this URI.
# It is formatted as `user:pass@host:port` with missing parts being omitted.
#
Expand Down
38 changes: 38 additions & 0 deletions src/uri/params.cr
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,44 @@ class URI
raw_params.delete(name)
end

# Merges *params* into self.
#
# ```
# params = URI::Params.parse("foo=bar&foo=baz&qux=zoo")
# other_params = URI::Params.parse("foo=buzz&foo=extra")
# params.merge!(other_params).to_s # => "foo=buzz&foo=extra&qux=zoo"
# params.fetch_all("foo") # => ["buzz", "extra"]
# ```
#
# See `#merge` for a non-mutating alternative
def merge!(params : URI::Params, *, replace : Bool = true) : URI::Params
if replace
@raw_params.merge!(params.raw_params) { |_, _first, second| second.dup }
else
@raw_params.merge!(params.raw_params) do |_, first, second|
first + second
end
end

self
end

# Merges *params* and self into a new instance.
# If *replace* is `false` values with the same key are concatenated.
# Otherwise the value in *params* overrides the one in self.
#
# ```
# params = URI::Params.parse("foo=bar&foo=baz&qux=zoo")
# other_params = URI::Params.parse("foo=buzz&foo=extra")
# params.merge(other_params).to_s # => "foo=buzz&foo=extra&qux=zoo"
# params.merge(other_params, replace: false).to_s # => "foo=bar&foo=baz&foo=buzz&foo=extra&qux=zoo"
# ```
#
# See `#merge!` for a mutating alternative
def merge(params : URI::Params, *, replace : Bool = true) : URI::Params
dup.merge!(params, replace: replace)
end

# Serializes to string representation as http url-encoded form.
#
# ```
Expand Down

0 comments on commit 0410331

Please sign in to comment.