在我正在研究的项目中,我们经常为不同的目的定义自定义defsomething
- 样式的宏以隐藏样板。一个例子是defhook
,它有助于为事件定义一个钩子处理程序。这是它的简化版本(实际版本有更多参数,并在defmethod
中做了一些非平凡的事情,但这与我的问题无关):
(defmulti handle-hook
"This multimethod is called when an event was fired."
(fn [event context] event))
(defmacro defhook
"Define a hook for an event."
[event docstring & more]
`(let [body# (fn ~@more)]
(defmethod handle-hook ~event [event# context#]
(body# context#))))
(defhook "EntryDeleted"
"Hook called on entry deletion."
[context]
(log-deletion (:EntryID context)))
我对此代码的主要问题是defmethod
不支持docstring,因此我不能在REPL中使用"EntryDeleted"
或自动生成文档。最后一个对于项目很重要:有defhook
和defhandler
作为外部API公开,目前我们必须单独(和手动)维护文档。
所以最简单的问题是“如何将docstring附加到defmethod
”?。
更深层的是“如何附加/生成自定义defsomething
宏的文档?”
如果某些现有的文档生成工具支持此功能,那就太棒了!然而,Marginalia,Codox或Autodoc似乎都不支持此类内容。
答案 0 :(得分:1)
如何附加/生成自定义
defsomething
宏的文档?
由于文档字符串附加到变量,因此您通常会将defsomething
个宏扩展为更原始的def
形式,例如defn
,def
。然后,您只需安排将defsomething
的文档字符串附加到基础var。
如何将docstring附加到
defmethod
?
这是一个特例 - defmethod
没有定义新的var;它在Java对象上调用Java方法。另一方面,defmulti
确实创建了一个var。一种想法是使用调度值和相关描述扩展多功能的文档字符串。例如,
(defn append-hook-doc! [event docstring]
(let [hook-doc (str event " - " docstring)]
(alter-meta! #'handle-hook
(fn [m]
(update-in m [:doc] #(str % "\n\t" hook-doc))))))
...
(doc handle-hook)
-------------------------
user/handle-hook
This multimethod is called when an event was fired.
EntryDeleted - Hook called on entry deletion.
正如!
所示,此表单有副作用:对调用此表单的定义表单进行多次评估将导致#'handle-hook
的docstring中出现重复行。您可以通过在#'handle-hook
中存储一些额外的元数据来避免这种情况,以用作是否已附加文档的标记。或者,您可以将文档字符串存储在其他地方,并在一些辅助步骤中将它们全部修补,例如通过延迟(defmulti handle-hook ...
的扩展直到你拥有所有的文档字符串(尽管,这打破了文档字符串的多方法的开放扩展)。