(require '[clojure.spec :as s])
consider the following data:
(def data {:names [["Anna" :lucky]
["Peter"]
["Jon" :lucky]
["Andre" :lucky]]})
It's a hash-map of with one key :names having a value of a vector of vectors. The inner vectors must contain a string as the first element and can optionally contain a the keyword :lucky as the second element.
The previous two sentences should be described with clojure.spec- Let's start with the items in the vector:
(s/def ::item (s/cat :name string? :lucky (s/? #(= :lucky %))))
(s/conform ::item ["Tom"])
;; {:name "Tom"}
(s/conform ::item ["Tom" :lucky])
;; {:name "Tom", :lucky :lucky}
(s/conform ::item ["Tom" :sad])
;; :clojure.spec/invalid
This works. However, if there is only one option. Wouldn't a parsed result look be better like this:
`{:name "Tom", :lucky true}` or `{:name "Tom", :lucky false}`
Can this be done in clojure.spec?
With this, one can carry on:
(s/def ::items (s/coll-of ::item '()))
(s/conform ::items [["Tom" :lucky] ["Tim"]])
[["Tom" :lucky] ["Tim"]]
However, it looks like it passes the test but why the items are not parsed anymore?
Edit: This could be solved by switching from alpha7 to alpha10 release, where coll-of only takes one argument
Finally my spec looks like, having the previously described caveats:
(s/def ::my-spec (s/keys req-un [::items]))
#(= :lucky %)is better spec'ed as#{:lucky}. - Alex Miller