From cecd6cf52630e48ac53118e64d0bf25750c2f9f2 Mon Sep 17 00:00:00 2001 From: Tommi Reiman Date: Sun, 3 Feb 2019 18:09:38 +0200 Subject: [PATCH] Start working on cljs trie --- modules/reitit-core/java-src/reitit/Trie.java | 4 -- modules/reitit-core/src/reitit/core.cljc | 4 +- modules/reitit-core/src/reitit/impl.cljc | 5 +- modules/reitit-core/src/reitit/trie.cljc | 36 ++++++++++---- .../reitit-swagger/src/reitit/swagger.cljc | 5 +- test/cljc/reitit/impl_test.cljc | 11 ----- test/cljc/reitit/trie_test.cljc | 49 ++++++++++++------- 7 files changed, 63 insertions(+), 51 deletions(-) diff --git a/modules/reitit-core/java-src/reitit/Trie.java b/modules/reitit-core/java-src/reitit/Trie.java index 78272b4a..656999a3 100644 --- a/modules/reitit-core/java-src/reitit/Trie.java +++ b/modules/reitit-core/java-src/reitit/Trie.java @@ -258,10 +258,6 @@ public class Trie { return matcher.match(0, path.length(), path.toCharArray(), new Match()); } - public static Matcher scanner(List matchers) { - return new LinearMatcher(matchers); - } - public static void main(String[] args) { Matcher matcher = linearMatcher( diff --git a/modules/reitit-core/src/reitit/core.cljc b/modules/reitit-core/src/reitit/core.cljc index 7c2c8919..15d6eca7 100644 --- a/modules/reitit-core/src/reitit/core.cljc +++ b/modules/reitit-core/src/reitit/core.cljc @@ -115,7 +115,7 @@ [[] {}] compiled-routes) lookup (impl/fast-map nl) - scanner (trie/scanner pl) + matcher (trie/linear-matcher pl) routes (impl/uncompile-routes compiled-routes)] ^{:type ::router} (reify @@ -131,7 +131,7 @@ (route-names [_] names) (match-by-path [_ path] - (if-let [match (trie/lookup scanner path)] + (if-let [match (trie/lookup matcher path)] (-> (:data match) (assoc :path-params (:path-params match)) (assoc :path path)))) diff --git a/modules/reitit-core/src/reitit/impl.cljc b/modules/reitit-core/src/reitit/impl.cljc index aa33e705..38727802 100644 --- a/modules/reitit-core/src/reitit/impl.cljc +++ b/modules/reitit-core/src/reitit/impl.cljc @@ -9,13 +9,10 @@ (java.util HashMap Map) (java.net URLEncoder URLDecoder)))) -(defn normalize [s] - (-> s (trie/split-path) (trie/join-path))) - (defrecord Route [path path-parts path-params]) (defn parse [path] - (let [path #?(:clj (.intern ^String (normalize path)) :cljs (normalize path)) + (let [path #?(:clj (.intern ^String (trie/normalize path)) :cljs (trie/normalize path)) path-parts (trie/split-path path) path-params (->> path-parts (remove string?) (map :value) set)] (map->Route {:path-params path-params diff --git a/modules/reitit-core/src/reitit/trie.cljc b/modules/reitit-core/src/reitit/trie.cljc index 46b0a3a6..0a7954a5 100644 --- a/modules/reitit-core/src/reitit/trie.cljc +++ b/modules/reitit-core/src/reitit/trie.cljc @@ -11,6 +11,9 @@ (defn wild? [x] (instance? Wild x)) (defn catch-all? [x] (instance? CatchAll x)) +(defprotocol Matcher + (match [this i max path match])) + ;; https://stackoverflow.com/questions/8033655/find-longest-common-prefix (defn common-prefix [s1 s2] (let [max (min (count s1) (count s2))] @@ -58,6 +61,9 @@ (instance? CatchAll x) (str "{*" (-> x :value str (subs 1)) "}")))) "" xs)) +(defn normalize [s] + (-> s (split-path) (join-path))) + (defn- -node [m] (map->Node (merge {:children {}, :wilds {}, :catch-all {}} m))) @@ -103,6 +109,21 @@ (update :children dissoc "")) node'))) +(defn data-matcher [data] + #?(:clj (Trie/dataMatcher data))) + +(defn static-matcher [path matcher] + #?(:clj (Trie/staticMatcher path matcher))) + +(defn wild-matcher [path matcher] + #?(:clj (Trie/wildMatcher path matcher))) + +(defn catch-all-matcher [path data] + #?(:clj (Trie/catchAllMatcher path data))) + +(defn linear-matcher [matchers] + #?(:clj (Trie/linearMatcher matchers))) + ;; ;; public api ;; @@ -118,14 +139,14 @@ ([node path data] (-insert (or node (-node {})) (split-path path) data))) -(defn ^Trie$Matcher compile [{:keys [data children wilds catch-all]}] +(defn compile [{:keys [data children wilds catch-all]}] (let [matchers (cond-> [] - data (conj (Trie/dataMatcher data)) - children (into (for [[p c] children] (Trie/staticMatcher p (compile c)))) - wilds (into (for [[p c] wilds] (Trie/wildMatcher p (compile c)))) - catch-all (into (for [[p c] catch-all] (Trie/catchAllMatcher p (:data c)))))] + data (conj (data-matcher data)) + children (into (for [[p c] children] (static-matcher p (compile c)))) + wilds (into (for [[p c] wilds] (wild-matcher p (compile c)))) + catch-all (into (for [[p c] catch-all] (catch-all-matcher p (:data c)))))] (if (rest matchers) - (Trie/linearMatcher matchers) + (linear-matcher matchers) (first matchers)))) (defn pretty [matcher] @@ -135,9 +156,6 @@ (if-let [match ^Trie$Match (Trie/lookup matcher ^String path)] (->Match (.data match) (.parameters match)))) -(defn scanner [compiled-tries] - (Trie/scanner compiled-tries)) - ;; ;; spike ;; diff --git a/modules/reitit-swagger/src/reitit/swagger.cljc b/modules/reitit-swagger/src/reitit/swagger.cljc index acd70fd7..b5c58fc5 100644 --- a/modules/reitit-swagger/src/reitit/swagger.cljc +++ b/modules/reitit-swagger/src/reitit/swagger.cljc @@ -5,7 +5,8 @@ [clojure.spec.alpha :as s] [clojure.set :as set] [clojure.string :as str] - [reitit.coercion :as coercion])) + [reitit.coercion :as coercion] + [reitit.trie :as trie])) (s/def ::id (s/or :keyword keyword? :set (s/coll-of keyword? :into #{}))) (s/def ::no-doc boolean?) @@ -65,7 +66,7 @@ :spec ::spec}) (defn- swagger-path [path] - (-> path impl/normalize (str/replace #"\{\*" "{"))) + (-> path trie/normalize (str/replace #"\{\*" "{"))) (defn create-swagger-handler [] "Create a ring handler to emit swagger spec. Collects all routes from router which have diff --git a/test/cljc/reitit/impl_test.cljc b/test/cljc/reitit/impl_test.cljc index 5ad83786..3c72ab23 100644 --- a/test/cljc/reitit/impl_test.cljc +++ b/test/cljc/reitit/impl_test.cljc @@ -2,17 +2,6 @@ (:require [clojure.test :refer [deftest testing is are]] [reitit.impl :as impl])) -(deftest normalize-test - (are [path expected] - (is (= expected (impl/normalize path))) - - "/olipa/:kerran/avaruus", "/olipa/{kerran}/avaruus" - "/olipa/{kerran}/avaruus", "/olipa/{kerran}/avaruus" - "/olipa/{a.b/c}/avaruus", "/olipa/{a.b/c}/avaruus" - "/olipa/kerran/*avaruus", "/olipa/kerran/{*avaruus}" - "/olipa/kerran/{*avaruus}", "/olipa/kerran/{*avaruus}" - "/olipa/kerran/{*valvavan.suuri/avaruus}", "/olipa/kerran/{*valvavan.suuri/avaruus}")) - (deftest conflicting-route-test (are [c? p1 p2] (is (= c? (impl/conflicting-routes? [p1] [p2]))) diff --git a/test/cljc/reitit/trie_test.cljc b/test/cljc/reitit/trie_test.cljc index 570c45c5..b56981dd 100644 --- a/test/cljc/reitit/trie_test.cljc +++ b/test/cljc/reitit/trie_test.cljc @@ -1,26 +1,37 @@ (ns reitit.trie-test (:require [clojure.test :refer [deftest testing is are]] - [reitit.trie :as rt])) + [reitit.trie :as trie])) + +(deftest normalize-test + (are [path expected] + (is (= expected (trie/normalize path))) + + "/olipa/:kerran/avaruus", "/olipa/{kerran}/avaruus" + "/olipa/{kerran}/avaruus", "/olipa/{kerran}/avaruus" + "/olipa/{a.b/c}/avaruus", "/olipa/{a.b/c}/avaruus" + "/olipa/kerran/*avaruus", "/olipa/kerran/{*avaruus}" + "/olipa/kerran/{*avaruus}", "/olipa/kerran/{*avaruus}" + "/olipa/kerran/{*valvavan.suuri/avaruus}", "/olipa/kerran/{*valvavan.suuri/avaruus}")) (deftest tests - (is (= (rt/->Match {:a 1} {}) - (-> (rt/insert nil "/foo" {:a 1}) - (rt/compile) - (rt/lookup "/foo")))) + (is (= (trie/->Match {:a 1} {}) + (-> (trie/insert nil "/foo" {:a 1}) + (trie/compile) + (trie/lookup "/foo")))) - (is (= (rt/->Match {:a 1} {}) - (-> (rt/insert nil "/foo" {:a 1}) - (rt/insert "/foo/*bar" {:b 1}) - (rt/compile) - (rt/lookup "/foo")))) + (is (= (trie/->Match {:a 1} {}) + (-> (trie/insert nil "/foo" {:a 1}) + (trie/insert "/foo/*bar" {:b 1}) + (trie/compile) + (trie/lookup "/foo")))) - (is (= (rt/->Match {:b 1} {:bar "bar"}) - (-> (rt/insert nil "/foo" {:a 1}) - (rt/insert "/foo/*bar" {:b 1}) - (rt/compile) - (rt/lookup "/foo/bar")))) + (is (= (trie/->Match {:b 1} {:bar "bar"}) + (-> (trie/insert nil "/foo" {:a 1}) + (trie/insert "/foo/*bar" {:b 1}) + (trie/compile) + (trie/lookup "/foo/bar")))) - (is (= (rt/->Match {:a 1} {}) - (-> (rt/insert nil "" {:a 1}) - (rt/compile) - (rt/lookup ""))))) + (is (= (trie/->Match {:a 1} {}) + (-> (trie/insert nil "" {:a 1}) + (trie/compile) + (trie/lookup "")))))