将deftemplate中的局部变量绑定为enlive

时间:2012-08-11 01:02:17

标签: clojure enlive

我是clojure和Web开发堆栈的新手。我正在尝试使用enlive在HTML模板中设置值:

(en/deftemplate project-main-page
  (en/xml-resource "project-main.html")
  [id]
  [:#project-name] (en/content (str "Name: " ((get-project id) :name)))
  [:#project-desc] (en/content (str "Desc: " ((get-project id) :desc))))

这适用于设置我的两个HTML元素,但它涉及重复调用我的函数get-project。目前这只是从本地地图读取,但最终它将涉及一些外部存储访问,所以我更喜欢在此功能中执行一次。

我在考虑使用let

(en/deftemplate project-main-page
  (en/xml-resource "project-main.html")
  [id]
  (let [project (get-project id)]
    [:#project-name] (en/content (str "Name: " (project :name)))
    [:#project-desc] (en/content (str "Desc: " (project :desc)))))

但这仅影响description元素并忽略名称形式。

deftemplate中绑定局部变量的最佳方法是什么?

2 个答案:

答案 0 :(得分:2)

如果我理解你想要实现的目标;您也可以尝试使用enlive提供的转换宏。

(defn main-page [{:keys [name desc] :as project}]
 (en/transformation
   [:#project-name] (en/content (str "Name: " name)
   [:#project-desc] (en/content (str "Desc: " desc))))


(en/deftemplate project-main-page
  (en/xml-resource "project-main.html")
  [id]
   (main-page (get-project id)))

代码未经测试,但我希望它以不同的方式传达你需要的东西

答案 1 :(得分:1)

Enlive的deftemplate宏需要args向量之后的一系列标记/内容对(示例中的args向量为[id])。你不能只在那里粘贴一个let,因为宏不期望一个let形式,所以当它拼接时,一切都搞砸了,导致你上面描述的行为。

您可以解决此问题的一种方法是编写自己的deftemplate宏,该宏允许使用args向量中的标识符进行绑定定义。例如:

(alt/deftemplate project-main-page
  (en/xml-resource "project-main.html")
  [id]
  [project (get-project id)]
  [:#project-name] (en/content (str "Name: " (project :name)))
  [:#project-desc] (en/content (str "Desc: " (project :desc))))

deftemplate宏是template的简单包装,它使用snippet*,这可能是您需要插入更改的地方:

(defmacro snippet* [nodes args & forms]
  `(let [nodes# (map annotate ~nodes)]
     (fn ~args
       ; You could add let bindings here since args are in scope
       (doall (flatmap (transformation ~@forms) nodes#)))))

另一个选项 - 可能更简单,因为你不必在库代码中捣乱 - 将为你的get-project函数添加一个间接级别来缓存结果。您可以尝试使用core.cache库。