I need to spec map-entry-like vectors whose keys are themselves spec-ed. Each vector looks like this:
[:my.spec-ed.key/foo 42]
The specific keys used vary, and I am hoping to write a predicate that would dynamically spec any map-entry-like vector based on its key the way maps are spec-ed entry by entry via (s/keys).
In this case let's say the key is spec-ed like this:
(s/def :my.spec-ed.key/foo int?)
The best I can come up with to spec the map-entry-like vector is this:
(s/def :my.spec-ed.key/pair (s/and vector? #(s/valid? (first %) (second %))))
This works, but I don't like it because (s/explain) is not as good when something goes wrong. For example, (s/explain :my.spec-ed.key/foo "foo")
is informative:
"foo" - failed: int? spec: :my.spec-ed.key/foo
Conversely, (s/explain :my.spec-ed.key/pair [:my.spec-ed.key/foo "bar"])
doesn't end up explaining what really went wrong (that I passed a string instead of an int), I have to go look up the original spec to find that out:
[:my.spec-ed.key/foo "bar"] - failed: (valid? (first %) (second %)) spec: :my.spec-ed.key/pair
Does anyone have any ideas for a better way to spec my map-entry-like vectors? For what it's worth, these vectors don't actually come from maps, and are not actually going to maps, so I can't use any of the spec functions designed to work on maps specifically.