2014-10-19 5 views
10

In precedenza avevo un'API che aveva un numero di funzioni al suo interno, ognuna delle quali prevedeva una mappa in un formato molto particolare. Quando ho iniziato a documentare questa API, ho trovato che nelle docstring di ognuna di queste funzioni stavo ripetendo "La mappa con cui viene chiamata questa funzione deve essere di tale e tale formato, e questo campo della mappa significa tale e così ".Documentazione di record in clojure

Quindi ho pensato che sarebbe stato meglio per quelle funzioni registrare un record e che avrei potuto semplicemente documentare il record. Tuttavia non sembra possibile documentare i record, almeno in alcun modo interpretati dalla macro doc o Marginalia.

Una soluzione suggerita here è "basta aggiungere una: chiave doc nella meta del record".

Ho provato (defrecord ^{:doc "Here is some documentation"} MyRecord [field1 field2]) ma la macroespansione suggerisce che non ha alcun effetto. Anche defrecord restituisce un'istanza di java.lang.class che non implementa IMeta quindi non sono sicuro che possiamo fornirle i metadati?

  • Come devono essere documentati i record?
  • I record sono una soluzione appropriata qui?
+0

Se leggi più in basso in quel thread, vedrai che l'aggiunta di un: doc key ai metadati del record non funzionerà. Si noti che è possibile aggiungere una stringa doc a un protocollo. – user100464

+0

ma [questo] (http: // StackOverflow.com/questions/6627020/combining-clojure-defprotocol-and-defrecord) La risposta di overflow dello stack raccomanda di non scrivere protocolli che vengono implementati solo da un record, il che probabilmente è ciò che accadrebbe. –

+0

Una soluzione è una libreria come ['prismatic/schema'] (https://github.com/Prismatic/schema), che consente di specificare il tipo di dati che accetterete, consentendo anche la verifica degli argomenti forniti. – noisesmith

risposta

2

TL; DR: Purtroppo non è possibile.

Dal docs:

Simboli e collezioni supporto dei metadati

Quando si utilizza defrecord in realtà si sta creando una classe Java. Poiché le classi non sono né simboli né Clojure, non è possibile aggiungere loro la documentazione.

spiegazione più dettagliata

La seguente sessione REPL mostra perché la sua non è possibile accodare i metadati ai record.

user=> (defrecord A [a b]) 
#<[email protected] user.A> 
user=> (meta A) ;; <= A contains no metadata 
nil 

Il bit importante da notare qui è che A è una normale classe java. Se si tenta di impostare i metadati per A si otterrà un errore interessante

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

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

A quanto pare con-meta si aspetta un clojure.lang.IObj. Poiché java.lang.Class è un costrutto Javaland, non sa chiaramente nulla di clojure.lang.IObj.

Diamo uno sguardo ora al codice sorgente per 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)))) 

Come si può vedere, questo metodo si aspetta x di avere un oggetto withMeta, che registra chiaramente non hanno.