clojure.spec cheatsheet
clojure.spec cheat sheet
Specs
Require
(ns my.ns
  (:require [clojure.spec.alpha :as s]))Register
(s/def ::even even?)
(s/valid? ::even 4)Use a registered spec from another namespace
(require '[my.namespace :as mn])
(s/valid? ::mn/even 4)Validate
(s/conform even? 4) ; returns the value or :clojure.spec.alpha/invalid
(s/valid? even? 4) ; returns true or falseGet validation errors
(s/explain-data even? 4) ; => nil
(s/explain-data even? 5) 
; => #:clojure.spec.alpha{:problems [{:path [], :pred clojure.core/even?, :val 5, :via [], :in []}],
;                         :spec #function[clojure.core/even?],
;                         :value 5}Compose
(s/def ::even-and-above-10 (s/and even? #(> % 10)))
(s/valid? ::even-and-above-10 12) ; => true
(s/valid? ::even-and-above-10 8) ; => falseEntity maps
(s/def ::name string?)
(s/def ::nickname string?)
(s/def ::age int?)
(s/def ::person (s/keys :req-un [::name ::age] :opt-un [::nickname]))
(s/explain-data ::person {:name "Pesho" :age 30 :nickname "10"}) ; => nil
(s/explain-data ::person {:name "Pesho" :age 30 :nickname 10})
; #:clojure.spec.alpha{:problems
;                      ({:path [:nickname],
;                        :pred clojure.core/string?,
;                        :val 10,
;                        :via [:user/person :user/nickname],
;                        :in [:nickname]}),
;                      :spec :user/person,
;                      :value {:name "Pesho", :age 30, :nickname 10}}Generators
Require
(require '[clojure.spec.gen.alpha :as gen])Generator
(s/gen pos-int?)Compound generator
(s/gen (s/and pos-int? even?))Generate a value
(gen/generate (s/gen pos-int?)) ; => 14Custom generators
from spec
This works by clojure.spec generating values from the base spec (in this case string?) and then applying the subsequent predicates as filters. Since it only generates 100 initial values, this will probably not work for complex specs.
(def uuid-regex #"(?i)^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$")
(s/def ::uuid-string (s/and string? #(some? (re-matches uuid-regex %))))
(s/valid? ::uuid-string "c278820c-9734-4ac2-99f6-23dd959ee73c") ; => true
(gen/generate (s/gen ::uuid-string))
; => 
; Error:
; Execution error (ExceptionInfo) at clojure.test.check.generators/fn (generators.cljc:435).
; Couldn't satisfy such-that predicate after 100 tries.with-gen
Takes a spec and a function, returning a generator, and returns a spec, which uses the generator to generate values.
(s/def ::my-even (s/with-gen 
                   (s/and pos-int? even?)
                   #(s/gen #{2 100 980})))
(gen/generate (s/gen ::my-even)) ; => one of 2, 100 or 980fmap
Takes a function and a generator and returns a generator, whose values are transformed by the function
(gen/generate (s/gen uuid?)) ; => #uuid "a06baf1e-3d77-49b4-8279-bceb5cd74ecd"
(gen/generate (gen/fmap str (s/gen uuid?))) ; => "a06baf1e-3d77-49b4-8279-bceb5cd74ecd"Spec with custom generator
(def uuid-regex #"(?i)^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$")
(s/def ::uuid-string
  (s/with-gen (s/and string? #(some? (re-matches uuid-regex %)))
    #(gen/fmap str (s/gen ::uuid))))
(gen/generate (s/gen ::uuid-string)) ; => "a06baf1e-3d77-49b4-8279-bceb5cd74ecd"Written by Alex Popov
Related protips
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
 #Clojure 
Authors
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#

 
 
 
 
