Документация записей в clojure

Ранее у меня был api, в котором было множество функций, все из которых ожидали карту в очень конкретном формате. Когда дело дошло до документирования этого API, я обнаружил, что в docstrings каждой из этих функций я повторял "Карта, с которой эта функция вызывается, должна иметь такой и такой формат, и это поле карты означает такое-то."

Итак, я подумал, что для этих функций будет лучше взять запись, и я мог бы просто документировать запись. Однако, как представляется, невозможно документировать записи, по крайней мере, интерпретироваться либо макросом doc, либо маргинальным.

Предлагаемое решение здесь означает "просто добавьте ключ: doc в метаданные записи".

Я попробовал (defrecord ^{:doc "Here is some documentation"} MyRecord [field1 field2]), но макрорасширение это говорит о том, что это не имеет никакого эффекта. Также defrecord возвращает экземпляр java.lang.class, который не реализует IMeta, поэтому я не уверен, что мы можем дать ему метаданные?

  • Как документировать документы?
  • Здесь записано подходящее решение?
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 
</class@61f53f0e>

Важным признаком здесь является то, что A является обычным java-классом. Если вы попытаетесь установить метаданные для A, вы получите интересную ошибку.

user=> (with-meta A {:doc "Hello"}) 
ClassCastException java.lang.Class cannot be cast to clojure.lang.IObj

Очевидно, что с-meta ожидает a clojure.lang.IObj. Поскольку java.lang.Class является конструкцией Джаваланда, он ничего не знает о 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, записи которого явно отсутствуют.

licensed under cc by-sa 3.0 with attribution.