Fork me on GitHub
#clojure-spec
<
2018-08-15
>
djtango09:08:12

I think clojure.java.jdbc has good spec coverage

Ethan16:08:29

thank you

ericnormand20:08:54

Can someone tell me what :opt is for? How is validation affected by its presence?

ericnormand20:08:22

I'm talking about :opt as an option to keys

guy20:08:28

As far as i’ve understood it, if you have say (s/keys :opt [::name]) If the key ::name is present it will check it against the spec.

guy20:08:03

So i’ve used it in the past to say, If this thing is present then it has to look like this spec. Otherwise carry on.

guy20:08:57

So if i just make up an example with some pseduo code

guy20:08:45

(s/def ::name string?)
(s/def ::type string?)

(s/def ::person (s/keys :opt [::name] :req [::type]))

(s/valid? ::person {::type "human})
=> probably true

(s/valid? ::person {::name 124 ::type "human"})
=> false because name is not a string

guy20:08:59

I’ve just written these by hand so don’t trust the code 1 for 1

guy20:08:34

This registers a ::person spec with the required keys ::first-name, ::last-name, and ::email, with optional key ::phone. The map spec never specifies the value spec for the attributes, only what attributes are required or optional.

When conformance is checked on a map, it does two things - checking that the required attributes are included, and checking that every registered key has a conforming value. We'll see later where optional attributes can be useful. Also note that ALL attributes are checked via keys, not just those listed in the :req and :opt keys. Thus a bare (s/keys) is valid and will check all attributes of a map without checking which keys are required or optional.
A rather large snippet

guy20:08:41

Hope that helps!

ericnormand22:08:31

However, if I do (s/keys), it still checks that ::name is valid.

ericnormand22:08:42

(s/def ::name string?)
(s/def ::person (s/keys))

(s/valid? ::person {}) ;=> true
(s/valid? ::person {::name "Eric"}) ;=> true
(s/valid? ::person {::name 15}) ;=> false

guy22:08:28

Yeah but what does ::person check for

guy22:08:34

:man-shrugging:

guy22:08:39

part of why i use opt is documentation

guy22:08:46

your point is valid though and its been asked before

ericnormand22:08:47

yes, documentation is good

guy22:08:49

let me find it

guy22:08:21

ah bummer the historys gone

guy22:08:31

Another person asked something similar but a different way

guy22:08:48

saying why use :opt at all when (s/keys) does the job

guy22:08:05

I think for me its documentation + being explicit about what you want to check for

ericnormand22:08:36

the spec guide on http://clojure.org hints that it'll explain later, but it never does

ericnormand22:08:43

I thought it might be more than just docs

mpenet22:08:11

Kind of important ;)

guy22:08:37

I think when it comes to speccing out ur fn as well it might be awkward depending on how u use (s/keys)

guy22:08:17

I’m unsure if you would really generate a spec like (s/def ::person (s/keys))

guy22:08:54

you might just use (s/keys) as an anonymous spec inside a (s/fdef ..)

guy22:08:03

i’ve probably got the terminology wrong

guy22:08:26

but that would also lead to harder reading when it comes to spec messages when they have failed

guy22:08:56

but yeah

guy22:08:18

i would favour :opt over (s/keys)

guy22:08:25

just from a readability factor

guy22:08:30

but im just one guy 😄

gfredericks22:08:58

is there also a difference when the spec is not defined?

gfredericks22:08:27

i.e., putting things in :opt forces you to define the specs you listed (i.e., prevents you from accidentally forgetting them)?

ericnormand23:08:13

@gfredericks a little repling shows that opts does not check if the spec exists

guy15:08:25

Can you give an example?

guy15:08:49

Like do you mean just doing something like (s/keys :opt [::fake-spec]) ?

dadair15:08:09

That fact allows me to avoid circular spec dependencies; the s/keys doesn’t validate that the spec exists

ericnormand18:08:19

@guy that's what I mean

👍 4