简体   繁体   中英

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM