(require '[clojure.spec.alpha :as s])
(s/def ::not-in-map-spec pos-int?)
(s/def ::in-map-spec string?)
(s/def ::the-map
(s/keys :req [::in-map-spec]))
(def m
{::in-map-spec "yes"
::not-in-map-spec -13})
(s/valid? ::the-map m) ; => false
(s/explain ::the-map m) ; => -13 - failed: pos-int? in: [:user/not-in-map-spec]
This surprises me, that a key that’s not in my spec, makes the spec invalid?
This is covered in the docstring for s/keys - all keys are checked
Hmm. That’s a conundrum in my usage, which I assume questions my usage: I have a big-map. I want to grab a part of it and save it away. Then use the rest to flow along. I can’t grab a part of it, because the rest is invalid. Do I explicitly select-keys to save it away?
You could also use add-on libraries like spec-tools: https://cljdoc.org/d/metosin/spec-tools/0.10.5/doc/spec-driven-transformations#transforming-map-specs
Yes, you can do that
(s/def :demo/m1 (s/keys :req-un [::a ::b ::c ::d ::e]))
(s/def :demo/m2 (s/keys :req-un [::a ::b ::c]))
Does spec provide a way to go from m1 to m2 programmatically?
(I suppose I'm looking for the inverse of s/merge)spec is not a transformation engine, it's a validation/verification library
or are you asking about spec transformation
assuming so, not really, it really encourages building up by composition, not by taking away
I meant spec transformation, yes.
I'm writing generative tests based on some s/keys specs and I'll have to dissoc some of the keys after the generation anyway, so I wondered if I could skip that step. Definitely not a deal-breaker and the justification behind the design decision is sound, as always. Thanks. 🙂