diff options
author | Carlo Zancanaro <carlo@clearboxsystems.com.au> | 2013-08-10 00:53:06 +1000 |
---|---|---|
committer | Carlo Zancanaro <carlo@clearboxsystems.com.au> | 2013-08-10 00:53:06 +1000 |
commit | 809dee0523d267c49b970a91a5cbe7aa119627fd (patch) | |
tree | 39f71f1d33ceaef1766141902cc22ba0d66dd7a5 /src |
Initial commit.
Diffstat (limited to 'src')
-rw-r--r-- | src/reverse_routing/core.clj | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/src/reverse_routing/core.clj b/src/reverse_routing/core.clj new file mode 100644 index 0000000..4936064 --- /dev/null +++ b/src/reverse_routing/core.clj @@ -0,0 +1,82 @@ +(ns reverse-routing.core + (:require [clojure.string :as string])) + +(defn wrap-reverse-routing [handler & {:keys [root] :or {:root ""}}] + (fn [request] + (let [route-table (->> handler meta ::routes) + request (assoc request + ::reverse-routes route-table + ::root root)] + (handler request)))) + +(defn ^:private routing [request & handlers] + (some #(% request) handlers)) + +(defn routes [& handlers] + (let [merge-first (partial merge-with (fn [x y] x))] + (apply vary-meta #(apply routing % handlers) + update-in [::routes] + merge-first (map (comp ::routes meta) handlers)))) + +(defmacro context [path args & routes] + (let [string-path (if (vector? path) (first path) path)] + `(with-meta (compojure.core/context ~path ~args ~@routes) + {::routes (let [path-keys# (:keys (clout.core/route-compile ~string-path)) + ~args [] ;; wow. could this be hackier? I doubt it. + ] + (->> (for [routes# (map (comp ::routes meta) (list ~@routes)) + [key# val#] routes#] + [key# {:uri (str ~string-path (:uri val#)) + :args (concat path-keys# (:args val#)) + :type (:type val#)}]) + (into {})))}))) + +(defmacro register-route [route-name [type path args & body :as route]] + (let [string-path (if (vector? path) (first path) path)] + `(with-meta ~route + {::routes {~route-name {:uri ~string-path + :type ~(keyword (string/lower-case (name type))) + :args (:keys (clout.core/route-compile ~string-path))}}}))) + +(defn url-for [request route & arg-values] + (let [{:keys [uri type args]} (-> request ::reverse-routes route) + root-path (::root request)] + (str root-path + (reduce (fn [string [name val]] + (clojure.string/replace string (str name) (str val))) + uri (map vector args arg-values))))) + +(comment + + (require '[compojure.core :refer [GET]]) + + (def test-routes + (-> (routes + (->> (GET "/user/:id" {{id :id} :params :as request} + (url-for request :get-something id)) + (register-route :get-user)) + (->> (GET "/person/:id" {{id :id} :params :as request} + (url-for request :get-user id)) + (register-route :get-person)) + (context "/something/:id" [id] + (GET "/nom" [] + "something, blah!") + (->> (GET "/name" {:as request} + (url-for request :get-person id)) + (register-route :get-something)) + (->> (GET ["/nam/:blah", :blah #"1\d+"] {{bloo :blah} :params :as request} + (url-for request :get-something-else id 10)) + (register-route :get-something-else)))) + wrap-reverse-routing)) + + (test-routes {:request-method :get + :scheme :http + ;;:uri "/something/15/name" + ;;:uri "/person/15" + :uri "/user/15" + ;;:uri "/something/15/nam/12" + ;;:uri "/something/10/nom" + :remote-addr "127.0.0.1" + :server-port 8080 + :server-name "something"}) + ) |