Maybe we can do a little more:
(defmacro limit-keys
[& {:keys [req req-un opt opt-un only] :as args}]
(if only
`(s/merge (s/keys ~@(apply concat (vec args)))
(s/map-of ~(set (concat req
(map (comp keyword name) req-un)
Whoops, that should be:
(defmacro only-keys
[& {:keys [req req-un opt opt-un] :as args}]
`(s/merge (s/keys ~@(apply concat (vec args)))
(s/map-of ~(set (concat req
(map (comp keyword name) req-un)
opt
Yeah, my team and I were initially surprised at the lack of a built-in
option for this to s/keys, but TBH it's been an unusual use case so far,
and Alex / Beau's solutions don't seem particularly onerous despite the
repetition.
I suppose if you're using it all over the place you could write a m
Nice, thanks. I had not thought to use map-of for this. And, s/merge
certainly helps too.
The only remaining issue for me is that this requires supplying the list of
keys twice.
AI think this case is general enough that it is worth extending the s/keys
macro to support: (s/keys :req [::a ::b] :
For stuff like this s/merge is probably preferable to s/and (when combining
map specs) - the difference being that merge does not flow conformed
results, will combine all failures, and that gen can work better in some
cases.
(s/def ::a int?)
(s/def ::b string?) ;; changed for this example
(s/e
boot.user=> (s/def ::my-map (s/and (s/keys :req [::a ::b]) (s/map-of #{::a
::b} any?)))
boot.user=> (s/explain ::my-map {::a 1 ::b 2 ::BAD 3})
In: [:boot.user/BAD 0] val: :boot.user/BAD fails spec: :boot.user/my-map
at: [0] predicate: #{:boot.user/a :boot.user/b}
Seems better
On Tuesday, Septe
In clojure.spec, how can I declare a map that accepts only certain keys?
*{::a 1 ::b 2 ::BAD 3}* does conform to *(s/keys :req :req [::a ::b])*, but
I want a spec that will be bothered by ::BAD or any other undeclared key.
My use case: I am introducing spec to some legacy code, and I want to b