【问题标题】:Documentation of records in clojureclojure 中的记录文档
【发布时间】:2014-10-19 19:05:50
【问题描述】:

我之前有一个 api,其中包含许多函数,所有这些函数都需要一个非常特殊格式的地图。在记录这个 API 时,我发现在每个函数的文档字符串中我都在重复“调用这个函数的地图必须是这样那样的格式,并且地图的这个字段意味着这样那样。”

所以我认为这些函数最好记录一个记录,而我可以只记录记录。但是,似乎无法记录记录,至少以任何方式由 doc 宏或 Marginalia 解释。

here 建议的解决方案是“只需在记录的元数据中添加一个 :doc 键”。

我尝试了(defrecord ^{:doc "Here is some documentation"} MyRecord [field1 field2]),但对其进行宏扩展表明它没有任何效果。 defrecord 还返回一个 java.lang.class 的实例,它没有实现 IMeta,所以我不确定我们可以给它元数据吗?

  • 应如何记录记录?
  • 记录在这里是合适的解决方案吗?

【问题讨论】:

  • 如果您在该线程中进一步阅读,您会发现将 :doc 键添加到记录的元数据将不起作用。请注意,您可以将文档字符串添加到协议中。
  • this 堆栈溢出答案建议不要编写仅由一条记录实现的协议,这可能会发生。
  • 一个解决方案是像prismatic/schema 这样的库,它允许您指定您将接受的数据类型,还允许验证提供的参数。
  • 临时解决办法是在 defrecord 前面加上一个以两个分号开头的注释,这对 marg 有效,但在 repl 中无效

标签: clojure documentation record


【解决方案1】:

TL;DR:很遗憾你不能。

来自docs

符号和集合支持元数据

当您使用defrecord 时,您实际上是在创建一个java 类。由于类既不是符号也不是 Clojure 记录,因此您不能将文档附加到它们。

更详细的解释

以下 REPL 会话说明了为什么无法将元数据附加到记录。

user=> (defrecord A [a b])
#<Class@61f53f0e user.A>
user=> (meta A)  ;; <= A contains no metadata
nil  

这里要注意的重要一点是 A 是一个常规的 java 类。 如果你尝试为 A 设置元数据,你会得到一个有趣的错误

user=> (with-meta A {:doc "Hello"}) 

ClassCastException java.lang.Class cannot be cast to clojure.lang.IObj

显然 with-meta 需要 clojure.lang.IObj。由于java.lang.Class 是Java 领域的构造,它显然对clojure.lang.IObj 一无所知。

我们现在来看看with-meta的源代码

user=> (source with-meta)
(def
 ^{:arglists '([^clojure.lang.IObj obj m])
   :doc "Returns an object of the same type and value as obj, with
    map m as its metadata."
   :added "1.0"
   :static true}
 with-meta (fn ^:static with-meta [^clojure.lang.IObj x m]
             (. x (withMeta m))))

如您所见,此方法期望x 有一个withMeta 对象,而记录显然没有。

【讨论】:

    【解决方案2】:

    您不能将文档字符串记录在案。但如果你真的想要,那么实际上你可以。

    如果您希望阅读代码的用户了解您的意图,那么您可以在代码中添加注释。

    如果您希望创建记录实例的用户能够通过工具访问您的文档字符串,那么您可以修改创建的构造函数元数据。例如:

    (let [docstring "The string-representation *MUST* be ISO8601."
          arglists '([string-representation millis-since-epoch])
          arglists-map '([{:keys [:string-representation :millis-since-epoch]}])]
      (defrecord Timestamp [string-representation millis-since-epoch])
      (alter-meta! #'->Timestamp assoc :doc docstring)
      (alter-meta! #'->Timestamp assoc :arglists arglists)
      (alter-meta! #'map->Timestamp assoc :doc docstring)
      (alter-meta! #'map->Timestamp assoc :arglists arglists-map))
    

    对于在 Cursive 中使用 REPL 的我来说,当我询问“参数信息”时会看到 argslist 弹出窗口,而当我询问“快速文档”时会看到 docstring。

    另一种更好的方法可能是为您自己的构造函数提供标准文档字符串。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多