2016-07-22 22 views
3

Wenn ich den folgenden Datensatz definiert:Clojure spec und Plattenbauer

(defrecord Person [name id]) 

und die folgende:

(s/def ::name string?) 
(s/def ::id int?) 
(s/def ::person (s/keys :req-un [::name ::id])) 

Wie kann ich sicherstellen, dass Sie nicht eine Person erstellen können, die den Anforderungen nicht entspricht zur :: person spec? Mit anderen Worten, sollte die folgende Ausnahme aus:

(->Person "Fred" "3") 

Ich habe versucht:

(s/fdef ->Person :ret ::person) 

aber ruft:

(->Person "Fred" "3") 

keine Ausnahme ausgelöst.

jedoch:

(s/conform ::person (->Person "Fred" "3")) 

hat ergeben die erwartete:

:clojure.spec/invalid 

Dank

Antwort

5

fdef: ret und: fn-Spezifikationen werden nur während clojure.spec.test/check Tests geprüft, aber man konnte eine FdEF verwenden : args spec, um die Eingaben für die Konstruktorfunktion bei der Instrumentierung zu überprüfen.

(s/fdef ->Person 
    :args (s/cat :name ::name :id ::id) 
    :ret ::person) 

(require '[clojure.spec.test :as stest]) 
(stest/instrument `->Person) 

(->Person "Fred" "3") 

=> CompilerException clojure.lang.ExceptionInfo: Call to #'spec.examples.guide/->Person did not conform to spec: 
In: [1] val: "3" fails spec: :spec.examples.guide/id at: [:args :id] predicate: int? 
:clojure.spec/args ("Fred" "3") 
:clojure.spec/failure :instrument 
:clojure.spec.test/caller {:file "guide.clj", :line 709, :var-scope spec.examples.guide/eval3771} 

Es wäre nicht allzu schwer zu Makro sein die Kombination von defrecord und FdEF des Konstrukteurs der passenden Spezifikationen verwenden.