From 5ef30443efd9715df9e816362b249c4103bcd924 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Tue, 20 Mar 2018 16:30:53 +0200 Subject: [PATCH] Initial take on IntoString --- modules/reitit-core/src/reitit/core.cljc | 8 ++-- modules/reitit-core/src/reitit/impl.cljc | 55 ++++++++++++++++++++++-- test/cljc/reitit/core_test.cljc | 6 +++ test/cljc/reitit/impl_test.cljc | 28 ++++++++++++ 4 files changed, 90 insertions(+), 7 deletions(-) diff --git a/modules/reitit-core/src/reitit/core.cljc b/modules/reitit-core/src/reitit/core.cljc index 535353f4..35d2c87b 100644 --- a/modules/reitit-core/src/reitit/core.cljc +++ b/modules/reitit-core/src/reitit/core.cljc @@ -175,7 +175,7 @@ (match nil))) (match-by-name [_ name path-params] (if-let [match (impl/fast-get lookup name)] - (match path-params))))))) + (match (impl/path-params path-params)))))))) (defn lookup-router "Creates a lookup-router from resolved routes and optional @@ -215,7 +215,7 @@ (match nil))) (match-by-name [_ name path-params] (if-let [match (impl/fast-get lookup name)] - (match path-params))))))) + (match (impl/path-params path-params)))))))) (defn segment-router "Creates a special prefix-tree style segment router from resolved routes and optional @@ -255,7 +255,7 @@ (match nil))) (match-by-name [_ name path-params] (if-let [match (impl/fast-get lookup name)] - (match path-params))))))) + (match (impl/path-params path-params)))))))) (defn single-static-path-router "Creates a fast router of 1 static route(s) and optional @@ -290,7 +290,7 @@ match)) (match-by-name [_ name path-params] (if (= n name) - (impl/fast-assoc match :path-params path-params))))))) + (impl/fast-assoc match :path-params (impl/path-params path-params)))))))) (defn mixed-router "Creates two routers: [[lookup-router]] or [[single-static-path-router]] for diff --git a/modules/reitit-core/src/reitit/impl.cljc b/modules/reitit-core/src/reitit/impl.cljc index 46d5a3b7..28499e75 100644 --- a/modules/reitit-core/src/reitit/impl.cljc +++ b/modules/reitit-core/src/reitit/impl.cljc @@ -13,8 +13,10 @@ (ns ^:no-doc reitit.impl (:require [clojure.string :as str] [clojure.set :as set]) - #?(:clj (:import (java.util.regex Pattern) - (java.util HashMap Map)))) + #?(:clj + (:import (java.util.regex Pattern) + (java.util HashMap Map) + (java.net URLEncoder URLDecoder)))) (defn wild? [s] (contains? #{\: \*} (first (str s)))) @@ -135,7 +137,7 @@ (defn throw-on-missing-path-params [template required path-params] (when-not (every? #(contains? path-params %) required) (let [defined (-> path-params keys set) - missing (clojure.set/difference required defined)] + missing (set/difference required defined)] (throw (ex-info (str "missing path-params for route " template " -> " missing) @@ -155,3 +157,50 @@ (defn strip-nils [m] (->> m (remove (comp nil? second)) (into {}))) + +;; +;; Path-parameters, see https://github.com/metosin/reitit/issues/75 +;; + +(defn url-encode [s] + (some-> s + #?(:clj (URLEncoder/encode "UTF-8") + :cljs (js/encodeURIComponent)) + (.replace "+" "%20"))) + +(defn url-decode [s] + #?(:clj (some-> s (URLDecoder/decode "UTF-8")) + :cljs (some-> s (js/decodeURIComponent)))) + +(defprotocol IntoString + (into-string [_])) + +(extend-protocol IntoString + #?(:clj String + :cljs string) + (into-string [this] this) + + #?(:clj clojure.lang.Keyword + :cljs cljs.core.Keyword) + (into-string [this] + (str (namespace this) + (when (namespace this) "/") + (name this))) + + #?(:clj Number + :cljs number) + (into-string [this] (str this)) + + #?(:clj Object + :cljs object) + (into-string [this] (str this))) + +(defn path-params + "shallow transform of the path-param values into strings" + [params] + (persistent! + (reduce-kv + (fn [m k v] + (assoc! m k (url-encode (into-string v)))) + (transient {}) + params))) diff --git a/test/cljc/reitit/core_test.cljc b/test/cljc/reitit/core_test.cljc index 83ef54c1..e8144e75 100644 --- a/test/cljc/reitit/core_test.cljc +++ b/test/cljc/reitit/core_test.cljc @@ -29,6 +29,12 @@ :path "/api/ipa/large" :path-params {:size "large"}}) (r/match-by-name router ::beer {:size "large"}))) + (is (= (r/map->Match + {:template "/api/ipa/:size" + :data {:name ::beer} + :path "/api/ipa/large" + :path-params {:size "large"}}) + (r/match-by-name router ::beer {:size :large}))) (is (= nil (r/match-by-name router "ILLEGAL"))) (is (= [::beer] (r/route-names router))) diff --git a/test/cljc/reitit/impl_test.cljc b/test/cljc/reitit/impl_test.cljc index 45032008..8ae5839d 100644 --- a/test/cljc/reitit/impl_test.cljc +++ b/test/cljc/reitit/impl_test.cljc @@ -10,3 +10,31 @@ (deftest strip-nils-test (is (= {:a 1, :c false} (impl/strip-nils {:a 1, :b nil, :c false})))) + +(deftest into-string-test + (is (= "1" (impl/into-string 1))) + (is (= "2.2" (impl/into-string 2.2))) + (is (= "kikka" (impl/into-string "kikka"))) + (is (= "kikka" (impl/into-string :kikka))) + (is (= "reitit.impl-test/kikka" (impl/into-string ::kikka)))) + +(deftest url-encode-and-decode-test + (is (= "reitit.impl-test%2Fkikka" (-> ::kikka + impl/into-string + impl/url-encode))) + (is (= "reitit.impl-test/kikka" (-> ::kikka + impl/into-string + impl/url-encode + impl/url-decode)))) + +(deftest path-params-test + (is (= {:n "1" + :d "2.2" + :s "kikka" + :k "kikka" + :qk "reitit.impl-test%2Fkikka"} + (impl/path-params {:n 1 + :d 2.2 + :s "kikka" + :k :kikka + :qk ::kikka}))))