farlee2121
farlee2121

Reputation: 3337

Clojure.Spec derive or alias another spec

I'd like to use clojure spec to build up a set of type constraints that can be aliased or further constrained by other specs.

For example, I might have many fields that all need to be valid sanitized markdown.

The following example works for validation (s/valid?) but not for generation (gen/generate)

(s/def ::sanitized-markdown string?)
(s/def ::instruction-list #(s/valid? ::sanitized-markdown %)) ;; works

(gen/generate (s/gen ::instruction-list)) ;; fails

However (gen/generate (s/gen ::sanitized-markdown)) does work.

Is there a way to extend ::instruction-list from ::sanitized-markdown so that it preserves all behavior?

Upvotes: 0

Views: 264

Answers (2)

Lee
Lee

Reputation: 144126

You can alias another spec by providing it directly to s/def:

(s/def ::instruction-list ::sanitized-markdown)

Upvotes: 2

Stanislas Nanchen
Stanislas Nanchen

Reputation: 111

You can use s/merge when merging map specs and s/and in other cases.

(s/def ::sanitized-markdown string?)
(s/def ::instruction-list (s/and ::sanitized-markdown #(> (count %) 10)))

(s/valid? ::instruction-list "abcd")
;; false
(s/valid? ::instruction-list "abcdefghijkl")
;; true

(gen/generate (s/gen ::instruction-list)) 
;; "178wzJW3W3zx2G0GJ1931eEeO"

An example with maps

(s/def ::a string?)
(s/def ::b string?)
(s/def ::c string?)
(s/def ::d string?)
(s/def ::first-map (s/keys :opt [::a ::b]))
(s/def ::second-map (s/keys :opt [::c ::d]))
(s/def ::third-map (s/merge ::first-map ::second-map))

(s/valid? ::third-map {:a "1" :d "2"})
;; true
(gen/generate (s/gen ::third-map))
;; {::b "gvQ7DI1kQ9DxG7C4poeWhk553", ::d "9KIp77974TEqs9HCq", ::c "qeSZA8NcYr7UVpJDsA17K"}

Upvotes: 2

Related Questions