Macros in Clojure, evaluation and quoting
I'm trying to write a macro to conditionally wrap compojure
handler in a middleware only in certain environments. I seem to be lost in the evaluation order and what/how should I quote. My current attempt is as follows:
(defn empty-middleware [handler]
(fn [request] (handler request)))
(defmacro prod [handler middleware]
(if (= "production" (System/getenv "APP_ENV"))
(middleware handler)
(empty-middleware handler)))
Desired usage is:
(in/prod (fn [handler] (airbrake/wrap-airbrake handler config/airbrake-api-key)))
--- EDIT ---
Some more information: in/prod is supposed to be used inside threading macro that wraps routes in a number of middlewares like:
(-> handler
middleware1
middleware2
(in/prod (middleware3 middleware-3-param1))
both middleware3 and in/prod need handler as parameter. Wrapping middleware3 in parenthesis evaluates without possibility to pass handler as a parameter. Hence I thought a macro is needed. I worked out how to make in/prod a function passing middleware3 and middleware params as parameters:
(defn prod [handler middleware & middleware-params]
(if (= "production" (System/getenv "APP_ENV"))
(apply middleware handler middleware-params)
handler))
It changes the syntax a bit though. The call looks like:
(-> handler
middleware1
middleware2
(in/prod middleware3 middleware-3-param1)
How would I go around to being able to use syntax like:
(in/prod (middleware3 middleware-3-param1)
You could need this to be a macro iff the middleware you wish to apply is also a macro and thus you are suffering from macro-contagion. In that you would simply want a macro that returns one of two possible s-expressins to be included in the resulting code. One where handler is called directly and one where it is wrapped in the given middleware.
(defmacro prod [handler middleware]
(if (= "production" (System/getenv "APP_ENV"))
`(~middleware ~handler) ;; or (list middleware handler)
handler))
If you are not currently suffering from macro-contagion while unable to fix that by removing the macro elsewhere, then you do not need to use such a macro and the code in your example can simply be used as a function rather than as a macro. The empty-middlware bit is not required in either case.
链接地址: http://www.djcxy.com/p/65766.html上一篇: 在Clojure宏中取消引用列表
下一篇: Clojure中的宏,评估和引用