summaryrefslogtreecommitdiff
path: root/src/reverse_routing
diff options
context:
space:
mode:
Diffstat (limited to 'src/reverse_routing')
-rw-r--r--src/reverse_routing/core.clj107
1 files changed, 44 insertions, 63 deletions
diff --git a/src/reverse_routing/core.clj b/src/reverse_routing/core.clj
index 4936064..cab8f33 100644
--- a/src/reverse_routing/core.clj
+++ b/src/reverse_routing/core.clj
@@ -1,82 +1,63 @@
(ns reverse-routing.core
- (:require [clojure.string :as string]))
+ (:require clout.core
+ compojure.core
+ [clojure.string :as string]))
+
+(def ^:private ^:dynamic *reverse-routes* nil)
+(def ^:private ^:dynamic *root* nil)
(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)]
+ (binding [*reverse-routes* (->> handler meta ::routes)
+ *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 routes [& handlers]
+ (let [routes-map (->> handlers
+ (map (comp ::routes meta macroexpand))
+ (into {}))]
+ (vary-meta `(vary-meta (fn [request#]
+ (#'routing request# ~@handlers))
+ assoc ::routes ~routes-map)
+ assoc ::routes routes-map)))
+
+(defmacro defroutes [name & handlers]
+ `(def ~name (routes ~@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 {})))})))
+ (let [string-path (if (vector? path) (first path) path)
+ routes-map (let [path-keys (:keys (clout.core/route-compile string-path))
+ keylen (count path-keys)]
+ (->> (for [route (map (comp ::routes meta macroexpand) routes)
+ [[path num] {:keys [uri args type]}] route]
+ [[path (+ num keylen)] {:uri (str string-path uri)
+ :args (vec (concat path-keys args))
+ :type type}])
+ (into {})))]
+ (vary-meta `(vary-meta (compojure.core/context ~path ~args ~@routes)
+ assoc ::routes ~routes-map)
+ assoc ::routes routes-map)))
(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)]
+ (let [string-path (if (vector? path) (first path) path)
+ route-args (:keys (clout.core/route-compile string-path))
+ route-id [route-name (count route-args)]
+ routes-map {route-id {:uri string-path
+ :type (keyword (string/lower-case (name type)))
+ :args (vec route-args)}}]
+ (vary-meta `(vary-meta ~route assoc ::routes ~routes-map)
+ assoc ::routes routes-map)))
+
+(defn url-for [route & arg-values]
+ (let [{:keys [uri type args]} (get *reverse-routes* [route (count arg-values)])
+ root-path *root*]
+ (assert uri)
(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"})
- )