Fork me on GitHub
#clojure-spec
<
2019-03-28
>
borkdude19:03:37

@ikitommi If you want to always validate, also in prod, why not use s/valid? for this?

borkdude19:03:06

(s/valid? (:args (s/get-spec `my-fn)) args)
something like that

borkdude19:03:34

or if you don’t like using s/get-spec you can write the args spec separately and use that in fdef, you’ll still get the docstring

drone19:03:31

we use s/valid? in asserts for things that should never happen and both s/valid? and s/conform in control flow (`if`, condp, match, etc). not advocating to do that, but sharing a related need we felt and what we’re trying out to address it

borkdude19:03:48

user=> (s/fdef foo :args (s/cat :i int?))
user/foo
user=> (def args-spec (:args (s/get-spec `foo)))
#'user/args-spec
user=> (defn foo [i] (if (s/valid? args-spec [i]) i (throw (ex-info "n00" (s/explain-data args-spec [i])))))
#'user/foo
user=> (foo 1)
1
user=> (foo "1")
Execution error - invalid arguments to user/foo at (REPL:1).
"1" - failed: int? at: [:i]

borkdude19:03:38

s/assert also works, but we have assertions turned off in prod

borkdude19:03:49

so s/valid? always works

borkdude19:03:25

and I bet you can wrap this in a macro like (def-checking-fn name & body)

ikitommi20:03:25

@borkdude thanks! looks just right. In my case, it's a framework calling the specced functions at runtime, so I can use apply & args to make a generic functional proxy.

ikitommi20:03:17

... or just extract the function spec if that exist and validate by the framework. indeed.

ikitommi20:03:46

that said, tempted to add an s/defn with identical syntax as Schema somewhere. There are several ones (all bit different) out there already. The Lisp Curse?

drone20:03:03

I think the only public one that’s maintained is orchestra’s defn-spec

Alex Miller (Clojure team)21:03:58

fwiw, I think we’re probably going to add something with spec 2 (or maybe Clojure 1.11)

👍 20
metametadata21:03:31

I like https://github.com/Provisdom/defn-spec syntax as it's friendly out-of-the-box to Cursive IDE (specs are defined inside defn metadata). but maybe orchestra's macro is also supported by Cursive

butterguns21:03:58

The other day, I asked a question about speccing Java object fields https://clojurians.slack.com/archives/C1B1BB2Q3/p1553612761304000 I thought I'd check back in, and say that I got intimate with s/conformer! My solution is to use a conformer to convert the Java object into a clojure map of {<fieldname-keyword> <field-value>}, and then just use s/keys

(s/def ::device (s/and (s/conformer (conform-java-fields ::summary #(.getSummary %)
                                                         ::report #(.getReport %)))
                       (s/keys :req [::summary ::report])))
I learnt something! 🙂

Alex Miller (Clojure team)21:03:32

note that this spec won't work backwards with unform though

Alex Miller (Clojure team)22:03:35

in general, this kind of thing is frowned upon as it bakes transformation into the spec and doesn't give registry consumers the option of whether to do the transformation. I would probably recommend to instead actually convert the objects to Clojure data, then use simple data specs on it.

butterguns22:03:49

So, doing the transformation in code, instead of within a spec?

Alex Miller (Clojure team)22:03:53

conformer was really imagined primarily as a tool for spec op creators, not for api users

butterguns22:03:18

OK, that makes sense. Thanks for the advice. I'm making progress

borkdude21:03:48

re: https://clojurians.slack.com/archives/C1B1BB2Q3/p1553807158018600 it would be nice if spec offered a bit more integration between fdef args and defn args somehow

Alex Miller (Clojure team)22:03:05

well the big thing likely here is to integrate the requires/provides semantics via select, and also to introduce a way to talk about returns in terms of args more descriptively. the :ret/:fn as it stands now is likely to change