Skip to content

Commit

Permalink
ref(*): general refactoring + duct.reitit.util
Browse files Browse the repository at this point in the history
  • Loading branch information
kkharji committed Dec 25, 2021
1 parent 9cec7b8 commit 625fa58
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 84 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Full configuration demo:
:duct.core/middleware-ns middleware ; default value

:foo/database {}
:foo/index-path "resources/test-index.html"
:foo/index-path "public/index.html"

:duct.module.reitit/cors ;; defaults in for dev and local environment
{:origin [#".*"]
Expand Down
131 changes: 50 additions & 81 deletions src/duct/module/reitit.clj
Original file line number Diff line number Diff line change
@@ -1,97 +1,66 @@
(ns duct.module.reitit
(:require [integrant.core :refer [init-key] :as ig]
[duct.core :as duct]
[clojure.string :as str]))
[duct.reitit.util :as util]))

(defn- qualify-key [key ns]
(if (str/includes? (str key) "/")
(str ns "." (namespace key) "/" (name key))
(str ns "/" (name key))))

(defn- try-resolve [str]
(cond (get-method init-key (keyword str))
(keyword str)
(resolve (symbol str))
(var-get (resolve (symbol str)))))
(def ^:private default-config
{:duct.core/handler-ns 'handler-ns
:duct.core/middleware-ns 'middleware-ns})

(defn- resolve-key
"if key is valid integrant keyword, then return it,
elseif the key result to a symbol, return it's value."
{:test #(let [namespaces ['foo.handler 'foo.middleware]
resolve-key (fn [k] (resolve-key k namespaces))]
(-> :ping resolve-key keyword? assert)
(-> :plus/with-body resolve-key keyword? assert)
(-> 'plus/with-query resolve-key map? assert)
(-> :plus/with-email resolve-key nil? assert))}
[key namespaces]
(let [qualify #(conj %1 (qualify-key key %2))
result (->> (reduce qualify [] namespaces)
(mapv try-resolve)
(remove nil?))]
(if (second result)
(throw
(-> "duct.reitit: Found conflict detected: "
(str (pr-str result))
(ex-info {:data result})))
(first result))))
(defn- merge-with-defaults [config]
(merge default-config config))

(defn- resolve-registry
"Given a registry"
{:test #(-> [[:index {:path (ig/ref :index-path)}]
[:ping {:message "pong"}]
[:plus/with-body]]
(resolve-registry '{:duct.core/project-ns foo
:duct.core/handler-ns handler
:duct.core/middleware-ns middleware})
(= {:index [:foo.handler/index {:path (ig/ref :index-path)}]
:plus/with-body [:foo.handler.plus/with-body {}]
:ping [:foo.handler/ping {:message "pong"}]})
(assert))}
[registry config]
(let [{:duct.core/keys [project-ns middleware-ns handler-ns]} config
to-path (fn [ns] (str project-ns "." ns))
namespaces (mapv to-path [middleware-ns handler-ns])
collect (fn [f] (reduce f {} registry))]
(collect
{:test #(let [namespaces ["foo.handler" "foo.middleware"]
assert-eql (fn [a b] (assert (= (resolve-registry namespaces a) b)))]
(assert-eql
[[:index {:path (ig/ref :index-path)}]
[:ping {:message "pong"}]
[:plus/with-body]]
{:index [:foo.handler/index {:path (ig/ref :index-path)}]
:plus/with-body [:foo.handler.plus/with-body {}]
:ping [:foo.handler/ping {:message "pong"}]}))}
[namespaces registry]
(letfn [(process [f] (reduce f {} registry))
(resolve [k] (util/resolve-key namespaces k))]
(process
(fn [acc [k v]]
(when-let [res (resolve-key k namespaces)]
(when-let [res (resolve k)]
(assoc acc k [res (or v {})]))))))

(comment
(test #'resolve-key)
(test #'resolve-registry))

(def ^:private default-config
{:duct.core/handler-ns 'handler-ns
:duct.core/middleware-ns 'middleware-ns})
(defn- registry->config [registry]
(letfn [(process [f] (reduce-kv f {} registry))]
(process
(fn [m _ v]
(assoc m (first v) (second v))))))

(defn- merge-with-defaults [config]
(merge default-config config))
(defn- registry->key [registry]
(letfn [(process [f] (reduce-kv f {} registry))]
(process
(fn [m k v]
(assoc m k (ig/ref (first v)))))))

(defn- registry->duct-config [registry]
(reduce-kv
(fn [m _ v]
(assoc m (first v) (second v)))
{}
registry))

(defn- registry->duct-registry [registry]
(reduce-kv
(fn [m k v]
(assoc m k (ig/ref (first v))))
{}
registry))
(defn- get-namespaces [config]
(->> [:duct.core/handler-ns :duct.core/middleware-ns]
(select-keys config)
(vals)
(util/get-namespaces (config :duct.core/project-ns))))

(defmethod init-key :duct.module/reitit [_ {:keys [routes registry]}]
(fn [config]
(let [config (merge-with-defaults config)
registry (resolve-registry registry config)
extra (registry->duct-config registry)
merge #(duct/merge-configs config (merge extra %))
router {:routes routes
:cors (ig/ref ::cors)
:registry (ig/ref ::registry)
:opts (ig/ref ::opts)}]
(merge
{::registry (registry->duct-registry registry)
:duct.router/reitit router}))))
(let [config (merge-with-defaults config)
namespaces (get-namespaces config)
registry (resolve-registry namespaces registry)
extras {:duct.router/reitit
{:routes routes
:cors (ig/ref ::cors)
:registry (ig/ref ::registry)
:opts (ig/ref ::opts)}
::registry (registry->key registry)}]
(->> (registry->config registry)
(merge extras)
(duct/merge-configs config)))))

(comment
(test #'resolve-registry))
73 changes: 73 additions & 0 deletions src/duct/reitit/util.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
(ns duct.reitit.util
(:require [clojure.string :as str]
[integrant.core :refer [init-key]]))

(defn- qualify-key [key ns]
(if (str/includes? (str key) "/")
(str ns "." (namespace key) "/" (name key))
(str ns "/" (name key))))

(defn- resolve-key* [str]
(cond (get-method init-key (keyword str))
(keyword str)
(resolve (symbol str))
(var-get (resolve (symbol str)))))

(defn resolve-key
"if key is valid integrant keyword, then return it,
elseif the key result to a symbol, return it's value."
{:test
#(let [namespaces ['foo.handler 'foo.middleware]
resolve-key (partial resolve-key namespaces)
check (fn [k t] (assert (t (resolve-key k))))]
(check :ping keyword?)
(check :plus/with-body keyword?)
(check 'plus/with-query map?)
(check :plus/with-email nil?))}
[namespaces key]
(let [qualify #(conj %1 (qualify-key key %2))
result (->> (reduce qualify [] namespaces)
(mapv resolve-key*)
(remove nil?))]
(if (second result)
(throw
(-> "duct.reitit: Confliction detected: "
(str (pr-str result))
(ex-info {:data result})))
(first result))))

(defn get-namespaces
{:test
#(assert (= ["foo.handler" "foo.middleware"]
(get-namespaces 'foo ['handler 'middleware])))}
[root nss]
(mapv (partial str root ".") nss))

(defn compact
"Remove nils from a given coll (map, list, vector)"
{:test
#(do (assert (= [1 2] (compact [1 nil 2])))
(assert (= {:y "1"} (compact {:x nil :y "1"})))
(assert (= [1] (compact '(nil nil nil 1)))))}
[coll]
(cond (or (list? coll) (vector? coll))
(into [] (filter (complement nil?) coll))
(map? coll)
(into {} (filter (comp not nil? second) coll))))

(defn member?
"same as contains?, but check if v is part of coll."
{:test
#(do (assert (true? (member? [1 2 3] 1)))
(assert (false? (member? [1 2 3] 6)))
(assert (true? (member? ["a"] "a"))))}
[coll v]
(true? (some (fn [x] (= x v)) coll)))

(comment
(test #'resolve-key)
(test #'get-namespaces)
(test #'compact)
(test #'member?))


2 changes: 1 addition & 1 deletion test/duct/module/reitit_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
:duct.core/middleware-ns middleware ; default value

:foo/database {}
:foo/index-path "resources/test-index.html"
:foo/index-path "resources/index.html"

:duct.module.reitit/cors ;; defaults in for dev and local environment
{:origin [#".*"]
Expand Down
2 changes: 1 addition & 1 deletion test/foo/handler.clj
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
(defmethod init-key ::index [_ {:keys [path]}]
(constantly
{:status 200
:body (->> path io/resource slurp)}))
:body (some->> path io/resource slurp)}))

(defmethod init-key ::ping [_ {:keys [message]}]
(constantly
Expand Down

0 comments on commit 625fa58

Please sign in to comment.