如何动态生成Clojure宏的参数?

时间:2011-07-23 19:38:11

标签: macros clojure enlive

我目前正在使用精彩的Enlive作为模板引擎开发一个小型CMS。 Enlive有一个名为at的宏,它接受一个指定HTML片段的节点(一个映射)和一个任意数量的元组,每个元组由一个选择器(一个向量)和一个转换(一个闭包)组成。

(at a-node
  [:a :selector] a-transformation
  [:another :selector] another-transformation
  ...)

现在我想根据传入的数据/上下文生成元组。我尝试过很多不同的事情而没有成功。例如

(let [this (repository/u "http://example.com/ACMECorp")
      statements (repository/find-by-subject this)
      context {:depth 1}]
  `(at (snippet-for 'this 'context)
       [root] (set-attr :about (str 'this))
       ~@(loop [rules []
                st statements]
           (if-not (seq st)
             rules
             (recur (conj rules
                          `[:> (attr= :property ~(str (repository/predicate (first st))))]
                          `(content (renderit ~(repository/object (first st)) 'context)))
                    (rest st))))))

非常感谢任何帮助。

-Jochen

2 个答案:

答案 0 :(得分:1)

不确定它们是否可以互换,但请查看at *函数。在我看来,你的问题是成为一个宏。

编辑:他们不是。这样称呼:

(at* a-node
  [[:a :selector] a-transformation
   [:another :selector] another-transformation
   ...])

答案 1 :(得分:1)

Clojure是一个Lisp,因此您可以随时回退以构建您想要的代码作为列表,并在其上调用eval。我对你提供的代码并不是100%肯定,但我猜你只想在eval调用中附上你的整个语法引用。

(let [this (repository/u "http://example.com/ACMECorp")
      statements (repository/find-by-subject this)
      context {:depth 1}]
  (eval `(at (snippet-for 'this 'context)
             [root] (set-attr :about (str 'this))
             ~@(loop [rules []
                      st statements]
                 (if-not (seq st)
                   rules
                   (recur (conj rules
                                `[:> (attr= :property ~(str (repository/predicate (first st))))]
                                `(content (renderit ~(repository/object (first st)) 'context)))
                          (rest st)))))))