Fork me on GitHub
#clojure-spec
<
2020-05-19
>
joefromct06:05:59

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?

ikitommi08:05:44

@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.

๐Ÿ‘ 4
mpenet09:05:36

๐Ÿ… vs ๐Ÿ…

mpenet09:05:50

I haven't tested extensively the cljs part personally, tests pass but that's it for now

jrychter12:05:18

This just bit me while writing :postconditions, 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.

Eddie21:05:30

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.

Alex Miller (Clojure team)13:05:29

all keys are checked by s/keys (even (s/keys) is a valid and useful spec)

Alex Miller (Clojure team)13:05:53

if you want to limit, you could select-keys on the data first, or validate the attributes specifically

jrychter20:05:40

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}).

jrychter20:05:10

Perhaps I'm using it wrong, but I would find the ability to check just "is this a valid ::bar ?" very useful.

seancorfield21:05:33

@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).

Alex Miller (Clojure team)21:05:00

the big idea is that spec gives named attributes global semantics

Alex Miller (Clojure team)21:05:39

if you have global semantics, it's ok (and good) to validate them when you see them

Alex Miller (Clojure team)21:05:43

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 :)