clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
joefromct 2020-05-19T06:01:59.458100Z

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?

ikitommi 2020-05-19T08:56:44.460200Z

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

πŸ‘ 1
mpenet 2020-05-19T09:26:36.460700Z

πŸ… vs πŸ…

mpenet 2020-05-19T09:28:50.461800Z

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

jrychter 2020-05-19T12:01:18.465Z

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.

alexmiller 2020-05-19T13:06:29.465800Z

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

alexmiller 2020-05-19T13:07:53.466700Z

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

jrychter 2020-05-19T20:40:40.469700Z

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

jrychter 2020-05-19T20:42:10.470700Z

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

Eddie 2020-05-19T21:06:30.471200Z

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.

seancorfield 2020-05-19T21:09:33.473600Z

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

alexmiller 2020-05-19T21:28:00.474Z

the big idea is that spec gives named attributes global semantics

alexmiller 2020-05-19T21:28:39.474500Z

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

alexmiller 2020-05-19T21:29:43.475700Z

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