Fork me on GitHub
#clojure-spec
<
2019-02-20
>
jsa-aerial01:02:03

I have question that more experienced people here will likely think obvious. Say I have a map with some keys, two of which need to have the same value. For example m, {::id v1 ::nm v2 ...}, and I want to enforce (= (m ::id) (m ::nm)). I haven't seen this sort of example, but presumably it is covered by spec?? Thanks in advance for any insight!

jsa-aerial01:02:17

Hmmmm, this doesn't give errors, but it doesn't work either:

jsa-aerial01:02:18

Hmmmm, looks like id-eq-nm? needs to use (m :sid) and (m :snm)

PB15:02:10

Hey all. I'm writing specs for a few controller functions. They take in request maps and hand off those maps to have work done. The issue I'm experiencing is that a collection inside of that (`body-params`) can vary by quite a bit depending on which endpoint is called and I don't like the idea of writing a really loose spec that can work with all of the say, user endpoints. As such: (s/def ::body-params (s/keys :opt [::username ::email ::....])) and would prefer to have specs setup for each call: (s/def ::body-params (s/keys :req [::email] :opt [:...])). Without putting each endpoint into a new file. How do I go about handling this?

johanatan17:02:27

Isn’t it possible to have more than one ns form per file?

borkdude15:02:48

I think this is a problem which spec2 solves

borkdude15:02:16

you can watch the latest Rich Hickey talk on youtube if you want to know more

borkdude15:02:47

not that this is solving your problem right now… sorry 🙂

PB15:02:06

Yeah, I saw the talk. I was just kinda hoping that there was something I could do naow

butterguns16:02:01

Could a multi-spec be used for this?

butterguns16:02:52

(s/def ::email string?)
(s/def ::username number?)
(s/def ::request-type #{:change-email :show-username})

(s/def ::change-email-request (s/keys :req [::email] :opt [::username]))
(s/def ::show-username-request (s/keys :req [::username] :opt [::email]))


(defmulti request-type ::request-type)
(defmethod request-type :change-email [_] ::change-email-request)
(defmethod request-type :show-username [_] ::show-username-request)

(s/def ::body-params (s/multi-spec request-type ::request-type))

(s/valid? ::body-params {::request-type :change-email ::email "boop"})
=> true
(s/valid? ::body-params {::request-type :change-email ::username 1234})
=> false
(s/valid? ::body-params {::request-type :show-username ::email "boop"})
=> false
(s/valid? ::body-params {::request-type :show-username ::username 1234})
=> true

butterguns16:02:58

You'll have to do a step first that assigns the request-type key to the map, depending on the controller that was callled

guy20:02:05

Might be the wrong place to ask, But with https://github.com/jeaye/orchestra are you still supposed to use, https://clojure.github.io/spec.alpha/clojure.spec.test.alpha-api.html#clojure.spec.test.alpha/check To check the instrumented fdef’s?

borkdude21:02:24

@guy as far as I know orchestra only changes instrumentation (it includes ret + fn checks). you still define specs with normal spec, so everything should still work. orchestra uses different namespaces, so it doesn’t patch/replace spec itself (I think)

👍 5
borkdude21:02:33

@jeaye might be able to confirm or correct this

guy21:02:49

Also i’m a little confused about how to use :fn

guy21:02:58

as part of an fdef

guy21:02:49

Am i supposed to try and link the :args and :ret using :fn ? As in when a certain input is something, then the return should be something, using fn to validate that?

jeaye21:02:22

Yep, you still use spec for everything. Just use orchestra to enable instrumentation and consider using defn-spec to clean up your fns.

guy21:02:19

ok thanks 🙂

borkdude21:02:43

@guy with fn you can do additional checking on arg + ret and dependencies between them

jeaye21:02:40

:fn is optional, so you'll likely know when you need it.

borkdude21:02:44

@guy e.g. in the group-by spec I linked I did an additional check that group-by should not produce more elements than the input collection had

guy21:02:51

:thinking_face:

guy21:02:01

I guess it might be an issue with my understanding. Lets say you have a function that takes some args and returns true or false. Would you ever want to use :fn to sort of specify that when the args are nil, you return false

guy21:02:29

I’m not sure if thats a bad example, but when i check an instrumented function, i want the args and return to make sense

guy21:02:00

or maybe i’m thinking about it the wrong way 🤷

borkdude21:02:56

I think in the case of simple predicates fn specs might not be the most helpful. The clojure spec guide might provide you with more helpful ones.

5
guy21:02:24

I’ll read the guide again and check that speculative lib too. Thanks 🙂

drone22:02:32

❤️ defn-spec

drone22:02:47

we’ve rolled our own for defrecord, but would like to see standard spec-enhanced forms be a thing. but I have a feeling they’re most useful for those of us using spec as a poor man’s type system, which is probably something Hickey wants to discourage

Alex Miller (Clojure team)23:02:19

can you explain what you're talking about?

Alex Miller (Clojure team)23:02:07

what is "spec-enhanced forms"?