Fork me on GitHub
#clojure-spec
<
2018-03-20
>
bbrinck00:03:40

This feature still requires a lot of work, but soon(ish), Expound will be able to provide examples of valid clojure code https://gist.github.com/bhb/f637ef589ef3ac3d2ca5a883fafc2c12

bbrinck00:03:39

However, this adds a dependency on test.check to use expound at dev time. Would you prefer to have this be a hard dependency OR would you prefer expound to disable this feature if you don’t have test.check available?

seancorfield00:03:46

@mcama200 spec/keys is a macro so it takes literal code forms, not variables.

seancorfield00:03:55

What you can do instead is to use the literal vector in s/keys and then call s/form (I think?) on the spec itself and walk that to get the list of required keys back out of a spec definition.

camachom00:03:50

awesome, thanks for the help!

seancorfield00:03:25

@alexisvincent The short answer is: specs are currently pretty static so you have to have multiple specs -- or specify that :card/cvv is :opt in the base spec and then wrap it in another spec that uses s/and and a predicate that "requires" that key be present.

seancorfield00:03:55

(s/def :card/full-details (s/and :card/details #(contains? % :card/cvv)))
something like that (untested)

borkdude09:03:11

I guess spec could eat its own dog food?

boot.user=> (s/fdef foo (s/cat :a1 string?))

     java.lang.IllegalArgumentException: No value supplied for key: (s/cat :a1 string?)
clojure.lang.Compiler$CompilerException: java.lang.IllegalArgumentException: No value supplied for key: (s/cat :a1 string?), compiling:(null:1:1)

Alex Miller (Clojure team)13:03:22

Actually it can’t, unless you enjoy infinite recursion

mpenet10:03:31

been there done that: my personal favorite is (s/def foo any?) or (s/fdef ::foo :args (s/cat))

mpenet10:03:34

both silently fail, which makes it even better

alexisvincent10:03:54

@seancorfield Thanks for the answer, the s/and is neat, and will help reduce branching factor, but I don’t think it’s a long term behaviour. I can use functions that return specs, but loose out on spec’s repository. Do you know if dynamism will be added to named specs in the future, or if it even needs to be?

borkdude11:03:30

I have the current spec (simplified):

(s/fdef widget
        :args
        (s/cat :opts
               (s/keys
                :req-un [::title
                         ::content]
                :opt-un [
                         ::init-collapsed?
                         ::fixed?])))
How do I say init-collapsed? and fixed? are mutually exclusive?

mpenet11:03:35

but they can be both absent as well?

borkdude11:03:17

if you say the widget must be fixed, init-collapsed? can not be true, because the widget won’t be visible at all that way

borkdude11:03:23

I could just emit a warning outside of spec, but maybe there’s a nice solution

borkdude11:03:32

I also don’t want to introduce nesting in the arguments

borkdude11:03:49

I could maybe use s/conformer?

mpenet11:03:03

I guess you need a separate pred in s/and since opt-un will not accept (or ...) etc

borkdude11:03:49

yes,

(fn [m]
  (not (and (:init-collapsed? m)
        (:fixed? m))))
works with s/and thanks

mpenet11:03:00

I imagine a multispec could do it too, but that's prolly too much complexity for such as simple check

acron14:03:18

java.util.concurrent.ExecutionException: clojure.lang.ExceptionInfo: Couldn't satisfy such-that predicate after 100 tries. {}

acron14:03:23

Most depressing error ever.

Alex Miller (Clojure team)14:03:44

unfortunately, the current linkage between spec and test.check prevents good error reporting on where this is happening. there are plans to make this better, but it requires changes in both projects.

gfredericks15:03:03

@alexmiller I'm curious how what you just described relates to an earlier comment that spec can't enscricten its version requirements of test.check

danielneal15:03:44

make more scrict

danielneal15:03:36

opposite of pecmissive

misha17:03:13

@alexisvincent define all your fields’ specs, and then have several s/keys specs for different combinations of those fields. Then you might want to have the card spec, which is s/or around those s/keys

misha18:03:12

Remember, you can have keys with different namespaces in the same map/object, so don’t paint yourself into corner with unified namespace “:card” when some attributes might be better named, like :amex.card/number, because it’ll have different spec and generator.