clojure.spec
Uses: validation at system boundaries, documentation, destructuring with conform, generative testing, and macro syntax checking (Clojure itself specs ns, let, defn). spec2 (alpha) is an evolving redesign.
(require '[clojure.spec.alpha :as s]
'[clojure.spec.gen.alpha :as gen]
'[clojure.spec.test.alpha :as stest])
;; Specs for values
(s/def ::name (s/and string? #(not (clojure.string/blank? %))))
(s/def ::age (s/and int? #(<= 0 % 150)))
(s/def ::email (s/and string? #(re-matches #".+@.+\..+" %)))
(s/def ::role #{:admin :editor :viewer}) ; sets are predicates
(s/def ::roles (s/coll-of ::role :kind set?))
;; Specs for maps (by key names)
(s/def ::person (s/keys :req-un [::name ::age] :opt-un [::email ::roles]))
(s/valid? ::person {:name "Ana" :age 30}) ; true
(s/valid? ::person {:name "" :age 200}) ; false
(s/explain ::person {:name "" :age 200}) ; human-readable explanation
(s/explain-data ::person {:name "Ana"}) ; machine-readable
(s/conform ::age 30) ; 30 (or :clojure.spec.alpha/invalid)
;; Sequence specs (regex ops)
(s/def ::config (s/cat :host string? :port int? :flags (s/* keyword?)))
(s/conform ::config ["localhost" 8080 :debug :verbose])
;; {:host "localhost", :port 8080, :flags [:debug :verbose]}
;; Alternatives
(s/def ::id (s/or :num int? :str string?))
(s/conform ::id
…