You can spec collections in a number of ways. coll-of allows you to spec collections and provide some additional constraints. Here's a simple example:
(clojure.spec/valid? (clojure.spec/coll-of int?) [1 2 3])
;; => true
(clojure.spec/valid? (clojure.spec/coll-of int?) '(1 2 3))
;; => true
Constraint options follow the main spec/predicate for the collection. You can constrain the collection type with :kind
like this:
(clojure.spec/valid? (clojure.spec/coll-of int? :kind vector?) [1 2 3])
;; => true
(clojure.spec/valid? (clojure.spec/coll-of int? :kind vector?) '(1 2 3))
;; => false
The above is false because the collection passed in is not a vector.
(clojure.spec/valid? (clojure.spec/coll-of int? :kind list?) '(1 2 3))
;; => true
(clojure.spec/valid? (clojure.spec/coll-of int? :kind set?) #{1 2 3})
;; => true
(clojure.spec/valid? (clojure.spec/coll-of int? :kind set?) #{1 "2" 3})
;; => false
The above is false because not all elements in the set are ints.
You can also constrain the size of the collection in a few ways:
(clojure.spec/valid? (clojure.spec/coll-of int? :kind vector? :count 3) [1 2 3])
;; => true
(clojure.spec/valid? (clojure.spec/coll-of int? :kind vector? :count 3) [1 2])
;; => false
(clojure.spec/valid? (clojure.spec/coll-of int? :min-count 3 :max-count 5) [1 2 3])
;; => true
(clojure.spec/valid? (clojure.spec/coll-of int? :min-count 3 :max-count 5) [1 2])
;; => false
You can also enforce uniqueness of the elements in the collection with :distinct
:
(clojure.spec/valid? (clojure.spec/coll-of int? :distinct true) [1 2])
;; => true
(clojure.spec/valid? (clojure.spec/coll-of int? :distinct true) [2 2])
;; => false
coll-of
ensures all elements in a sequence are checked. For large collections, this can be very inefficient. every
behaves just like coll-of
, except it only samples a relatively small number of the sequences' elements from for conformance. This works well for large collections. Here's an example:
(clojure.spec/valid? (clojure.spec/every int? :distinct true) [1 2 3 4 5])
;; => true
map-of
is similar to coll-of
, but for maps. Since maps have both keys and values, you must supply both a spec for the key and a spec for the value:
(clojure.spec/valid? (clojure.spec/map-of keyword? string?) {:red "red" :green "green"})
;; => true
Like coll-of
, map-of
checks conformance of all map key/values. For large maps this will be inefficient. Like coll-of
, map-of
supplies every-kv
for efficiently sampling a relatively small number of values from a large map:
(clojure.spec/valid? (clojure.spec/every-kv keyword? string?) {:red "red" :green "green"})
;; => true