将可选的docstring添加到def *宏

时间:2014-04-05 14:18:57

标签: macros clojure

我想在我的def*宏中添加可选的文档字符串。例如:

(defmacro defhtml
  "Macro to avoid backtick unquote[splicing] in html vectors.
   TODO: Add optional docstring."
  [name args & body]
  `(defn ~name ~args (html ~@body)))

;; Working defhtml
(defhtml include-css [href]
  [:link {:href href :rel "stylesheet"}])

我想:

(defhtml include-css
  "My optional docstring here."
  [:link {:href href :rel "stylesheet"}])

我认为应该有一些常见的习惯用法。

2 个答案:

答案 0 :(得分:5)

您需要决定宏的第二个参数是否是文档字符串(您可以测试它是否为字符串)。 Clojure宏是Clojure,因此您可以对传递给您想要的宏的表单执行任何逻辑或操作。如果不完全符合您的要求,这应该接近:

(defmacro defhtml [name & args]
  (cond
    ;; doc-string?
    (string? (first args))
    (let [[doc-string args-list & body] args]
      `(defn ~name ~doc-string ~args-list (html ~@body)))

    :no-doc-string
    (let [[args-list & body] args]
      `(defn ~name ~(format "HTML Generator %s" name) ~args-list (html ~@body)))))

这应该产生你之后的宏观扩展:

(defhtml include-css [href]
  [:link {:href href :rel "stylesheet"}])

产生

(defn include-css
    "HTML Generator include-css"
  [href]
  (html [:link {:href href, :rel "stylesheet"}]))

,同时:

(defhtml include-css
  "Standard css includes fory my site"
  [href]
  [:link {:href href :rel "stylesheet"}])

产生

(defn include-css
    "Standard css includes fory my site"
  [href]
  (html [:link {:href href, :rel "stylesheet"}]))

答案 1 :(得分:2)

defndefmacro已经支持可选文档字符串,因此,如果您的def*宏扩展为对其中一个的调用,则可能不需要包含您自己的代码中的任何string?检查。这是defhtml的情况,可以这样实现:

;; also adding an optional attribute map parameter, because why not?
(defmacro defhtml [name doc? attr-map? params & body]
  `(defn ~name ~doc? ~attr-map? ~params (html ~@body)))

;; equivalent, perhaps prettier:
(defmacro defhtml [name doc? attr-map? params & body]
  `(defn ~@[name doc? attr-map? params] (html ~@body)))