hi, quick question, given a spec ::my-map
based on req
and opt
how could i get a list of the keys that this spec pertains to?
Should i be parsing s/form
or is there an easier way?
@marques.goncalves.fel havenβt seen that. please write an issue to spec-tools and you could check also spec-coerce or coax - many libs doing mostly/exactly the same.
π vs π
I haven't tested extensively the cljs part personally, tests pass but that's it for now
This just bit me while writing :post
conditions, where I wanted to assert that the return value was (among other things) a "status", but did not want to assert anything else: this is at an edge API where data has been transformed into external representations (timestamps to ISO8601 date strings, for example):
(s/def ::a string?)
(s/def ::b string?)
(s/def ::foo (s/keys :req [::a ::b]))
;; Let's define ::bar, which is not concerned with ::b at all:
(s/def ::bar (s/keys :req [::a]))
;; This is expected:
(s/valid? ::foo {::a "a" ::b "b"}) => true
(s/valid? ::foo {::a "a" ::b 1}) => false
;; But even though ::bar is not concerned with ::b, validation fails. I was hoping to only check if something
;; is a valid ::bar, without asserting anything about keys that are not in :req or :opt in ::bar.
(s/valid? ::bar {::a "a" ::b 1}) => false
I expected the last form to return true
, to this day I did not realize that spec is eagerly checking all keys, not just those listed by s/keys
.all keys are checked by s/keys (even (s/keys)
is a valid and useful spec)
if you want to limit, you could select-keys on the data first, or validate the attributes specifically
That was unexpected, I somehow got used to reading s/valid?
as "tell me if this thing is a valid ::bar". Especially since it takes a parameter β (s/validate {:data :foo})
is intuitively different from (s/valid? ::foo {:data :foo})
.
Perhaps I'm using it wrong, but I would find the ability to check just "is this a valid ::bar
?" very useful.
Good to know! Thanks for mentioning it.
It seems odd to me that we would associate a value that is not a valid ::b
with the very specific qualified keyword of ::b
in a map. Perhaps this indicates that in the :bar
maps should be using a different key, like :b
.
@jrychter That makes sense for unqualified keys but part of the idea behind Spec for qualified keys is that they are globally unique (within your program) and therefore if :foo/bar
is present in a hash map, it should conform to the Spec for :foo/bar
if any. s/keys
is more about required/optional anyway (and that's emphasized in Spec 2 via schema
and select
).
the big idea is that spec gives named attributes global semantics
if you have global semantics, it's ok (and good) to validate them when you see them
if that's bad then either the spec is bad (b/c it doesn't fully encompass what that attribute can mean), or your data is bad (b/c it doesn't conform to the global semantics) or your version of "valid" does not match spec's semantics :)