summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/abra/core.clj63
1 files changed, 52 insertions, 11 deletions
diff --git a/src/abra/core.clj b/src/abra/core.clj
index 3d373eb..e6bc3fc 100644
--- a/src/abra/core.clj
+++ b/src/abra/core.clj
@@ -11,10 +11,19 @@
(deref arg)
arg))
-(defn wrap-reverse-routing [handler & {:keys [root] :or {:root ""}}]
+(defn wrap-reverse-routing
+ "Install the `abra` reverse-routing middleware.
+
+ This middleware sets up a dynamic scope in which `abra.core/url-for`
+ can be used to lookup routes.
+
+ The optional second argument, root, provides a prefix to be placed
+ before the url upon generation (for when the routes do not begin at
+ the root path)."
+ [handler & [root]]
(fn [request]
(binding [*lookup-route* (->> handler deref-if-var meta ::lookup)
- *root* root]
+ *root* (or root "")]
(handler request))))
(defn ^:private lookup-route [route & handlers]
@@ -25,20 +34,40 @@
(defn ^:private routing [request & handlers]
(some #(% request) handlers))
-(defn routes [& handlers]
+(defn routes
+ "Create a Ring handler by combining several handlers into one while
+ maintaining `abra` metadata."
+ [& handlers]
(vary-meta #(apply routing % handlers)
assoc ::lookup #(apply lookup-route % handlers)))
-(defmacro let-routes [bindings & handlers]
+(defmacro let-routes
+ "Equivalent to (let [...] (routes ...))"
+ [bindings & handlers]
`(let ~bindings (routes ~@handlers)))
-(defmacro when-routes [cond & handlers]
+(defmacro when-routes
+ "Equivalent to (when ... (routes ...))"
+ [cond & handlers]
`(if ~cond (routes ~@handlers) (routes)))
-(defmacro defroutes [name & handlers]
+(defmacro defroutes
+ "Equivalent to (def ... (routes ...))"
+ [name & handlers]
`(def ~name (routes ~@handlers)))
-(defmacro context [path args & routes]
+(defmacro context
+ "Give all routes in the form a common path prefix and set of bindings.
+
+ The following example demonstrates defining two routes with a common
+ path prefix ('/user/:id') and a common binding ('id'):
+
+ (context \"/user/:id\" [id]
+ (GET \"/profile\" [] ...)
+ (GET \"/settings\" [] ...))
+
+ Additionally maintains `abra` metadata."
+ [path args & routes]
(let [string-path (if (vector? path) (first path) path)
path-keys (vec (:keys (clout.core/route-compile string-path)))
keylen (count path-keys)
@@ -57,7 +86,10 @@
(routes ~@routes))
assoc ::lookup ~lookup-fn)))
-(defmacro register-route [route-name [type path args & body :as route]]
+(defmacro register-route
+ "Provide a name for a given route by which it can be looked up using
+ `abra.core/url-for`"
+ [route-name [type path args & body :as route]]
(let [string-path (if (vector? path) (first path) path)
route-args (:keys (clout.core/route-compile string-path))
routes-map {:uri string-path
@@ -69,7 +101,9 @@
(= (count args#) (count ~(vec route-args))))
~routes-map)))))
-(defn add-middleware [handler middleware & args]
+(defn add-middleware
+ "Add middleware to a Ring stack while maintaining `abra` metadata."
+ [handler middleware & args]
(let [result (apply middleware handler args)]
(vary-meta result
assoc ::lookup (fn [[name args]]
@@ -78,12 +112,19 @@
::lookup)]
(lookup-fn [name args]))))))
-(defmacro with-url-fn [f & body]
+(defmacro with-url-fn
+ "Test helper: run body using `f` as a url lookup in
+ `core.abra/url-for`."
+ [f & body]
`(binding [*lookup-route* (fn [x#] (apply ~f x#))
*root* ""]
~@body))
-(defn url-for [route & arg-values]
+(defn url-for
+ "Lookup the url for a given route. Only valid within the dynamic
+ context set up by `abra.core/wrap-reverse-routing` or
+ `abra.core/with-url-fn`."
+ [route & arg-values]
(let [spec (*lookup-route* [route arg-values])
{:keys [uri type args]} spec
root-path *root*]