diff --git a/spec/std/uri/params_spec.cr b/spec/std/uri/params_spec.cr index 0acd647617c5..44fc0b3abb4c 100644 --- a/spec/std/uri/params_spec.cr +++ b/spec/std/uri/params_spec.cr @@ -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 diff --git a/spec/std/uri_spec.cr b/spec/std/uri_spec.cr index 96aea2e16989..402263742a96 100644 --- a/spec/std/uri_spec.cr +++ b/spec/std/uri_spec.cr @@ -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 diff --git a/src/uri.cr b/src/uri.cr index 06842deadf6d..dfdf26f9f419 100644 --- a/src/uri.cr +++ b/src/uri.cr @@ -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. # diff --git a/src/uri/params.cr b/src/uri/params.cr index aa4f5eb30511..70dd0f1b373a 100644 --- a/src/uri/params.cr +++ b/src/uri/params.cr @@ -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. # # ```