From c94c6c46affaf293d5c232a334b4a2c40e3cd01d Mon Sep 17 00:00:00 2001 From: iku000888 Date: Thu, 19 Jan 2017 15:09:42 +0900 Subject: [PATCH 1/3] Add an escape hatch for non utf-8 encodings --- src/cemerick/url.cljx | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/cemerick/url.cljx b/src/cemerick/url.cljx index 75ff53d..60b4113 100644 --- a/src/cemerick/url.cljx +++ b/src/cemerick/url.cljx @@ -27,16 +27,18 @@ (some-> string str (js/decodeURIComponent))) (defn map->query - [m] - (some->> (seq m) - sort ; sorting makes testing a lot easier :-) - (map (fn [[k v]] - [(url-encode (name k)) - "=" - (url-encode (str v))])) - (interpose "&") - flatten - (apply str))) + [{:as m :keys [override-encoder-fn]}] + (let [encoder-fn (or override-encoder-fn url-encode) + m (dissoc m :override-encoder-fn)] + (some->> (seq m) + sort ; sorting makes testing a lot easier :-) + (map (fn [[k v]] + [(encoder-fn (name k)) + "=" + (encoder-fn (str v))])) + (interpose "&") + flatten + (apply str)))) (defn split-param [param] (-> From 27290486f331a9b33ee42363d722f4e73d89c4e9 Mon Sep 17 00:00:00 2001 From: iku000888 Date: Thu, 19 Jan 2017 15:13:42 +0900 Subject: [PATCH 2/3] Add test for the override capability --- test/cemerick/test_url.cljx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/cemerick/test_url.cljx b/test/cemerick/test_url.cljx index fe2e6d1..88c76e9 100644 --- a/test/cemerick/test_url.cljx +++ b/test/cemerick/test_url.cljx @@ -13,7 +13,8 @@ "a=1&b=2&c=3" {:a 1 :b 2 :c 3} "a=1&b=2&c=3" {:a "1" :b "2" :c "3"} "a=1&b=2" {"a" "1" "b" "2"} - "a=" {"a" ""})) + "a=" {"a" ""} + "overridden=overridden" {:foo "bar" :override-encoder-fn (constantly "overridden")})) (deftest url-roundtripping (let [aurl (url "https://username:password@some.host.com/database?query=string")] From eca3c9b20eb0fcbd164911d5b375e626e5ab3533 Mon Sep 17 00:00:00 2001 From: iku000888 Date: Sun, 22 Jan 2017 00:26:40 +0900 Subject: [PATCH 3/3] Switch to an approach using multimethods --- src/cemerick/url.cljx | 35 +++++++++++++++++++---------------- test/cemerick/test_url.cljx | 11 +++++++++-- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/cemerick/url.cljx b/src/cemerick/url.cljx index 60b4113..3a4915a 100644 --- a/src/cemerick/url.cljx +++ b/src/cemerick/url.cljx @@ -5,14 +5,17 @@ [clojure.string :as string] #+cljs [goog.Uri :as uri])) +(defmulti url-encode + (fn ([_ encoding] encoding))) + #+clj -(defn url-encode - [string] +(defmethod url-encode :default + [string _] (some-> string str (URLEncoder/encode "UTF-8") (.replace "+" "%20"))) #+cljs -(defn url-encode - [string] +(defmethod url-encode :default + [string _] (some-> string str (js/encodeURIComponent) (.replace "+" "%20"))) #+clj @@ -27,18 +30,18 @@ (some-> string str (js/decodeURIComponent))) (defn map->query - [{:as m :keys [override-encoder-fn]}] - (let [encoder-fn (or override-encoder-fn url-encode) - m (dissoc m :override-encoder-fn)] - (some->> (seq m) - sort ; sorting makes testing a lot easier :-) - (map (fn [[k v]] - [(encoder-fn (name k)) - "=" - (encoder-fn (str v))])) - (interpose "&") - flatten - (apply str)))) + ([m] + (map->query m nil)) + ([m encoding] + (some->> (seq m) + sort; sorting makes testing a lot easier :-) + (map (fn [[k v]] + [(url-encode (name k) encoding) + "=" + (url-encode (str v) encoding)])) + (interpose "&") + flatten + (apply str)))) (defn split-param [param] (-> diff --git a/test/cemerick/test_url.cljx b/test/cemerick/test_url.cljx index 88c76e9..07a5c00 100644 --- a/test/cemerick/test_url.cljx +++ b/test/cemerick/test_url.cljx @@ -13,8 +13,15 @@ "a=1&b=2&c=3" {:a 1 :b 2 :c 3} "a=1&b=2&c=3" {:a "1" :b "2" :c "3"} "a=1&b=2" {"a" "1" "b" "2"} - "a=" {"a" ""} - "overridden=overridden" {:foo "bar" :override-encoder-fn (constantly "overridden")})) + "a=" {"a" ""})) + +(defmethod url-encode :append-foobar + [string _] + (str string "foobar")) + +(deftest test-map-to-query-str-extention + (is (= "afoobar=custom-encodingfoobar" + (map->query {:a "custom-encoding"} :append-foobar)))) (deftest url-roundtripping (let [aurl (url "https://username:password@some.host.com/database?query=string")]