Clojure中的宏,评估和引用

时间:2015-02-02 18:56:30

标签: macros clojure lisp compojure

我正在尝试编写一个宏来仅在某些环境中有条件地将compojure处理程序包装在中间件中。我似乎在评估顺序中迷失了,我应该引用什么/如何引用。我目前的尝试如下:

(defn empty-middleware [handler]
  (fn [request] (handler request)))

(defmacro prod [handler middleware]
  (if (= "production" (System/getenv "APP_ENV"))
    (middleware handler)
    (empty-middleware handler)))

所需用法是:

(in/prod (fn [handler]  (airbrake/wrap-airbrake handler config/airbrake-api-key)))

---编辑---

更多信息: in / prod应该在线程宏中使用,它包含许多中间件中的路由,如:

(-> handler
    middleware1
    middleware2
    (in/prod (middleware3 middleware-3-param1))

middleware3和in / prod都需要handler作为参数。在括号中包装中间件3进行评估,但不可能将处理程序作为参数传递。因此我认为需要一个宏。我研究了如何使用/ prod函数传递中间件3和中间件参数作为参数:

(defn prod [handler middleware & middleware-params]
  (if (= "production" (System/getenv "APP_ENV"))
    (apply middleware handler middleware-params)
    handler))

虽然它改变了语法。电话看起来像:

(-> handler
    middleware1
    middleware2
    (in/prod middleware3 middleware-3-param1)

我如何能够使用如下语法:

(in/prod (middleware3 middleware-3-param1)

1 个答案:

答案 0 :(得分:1)

如果您要应用的中间件也是宏,那么您可能需要将其作为宏。因此您正遭受宏观传染。在那里你只需要一个宏,它返回两个可能的s-expressins之一,以包含在结果代码中。一个是直接调用处理程序的,另一个是在给定的中间件中包装的。

(defmacro prod [handler middleware]
  (if (= "production" (System/getenv "APP_ENV"))
    `(~middleware ~handler) ;; or (list middleware handler)
     handler))

如果您目前没有遭受宏传染而无法通过在其他位置删除宏来解决这个问题,那么您不需要使用这样的宏,并且示例中的代码可以简单地用作函数而不是一个宏。在任何一种情况下都不需要empty-middlware位。