diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/abra/core.clj | 63 |
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*] |