Fork me on GitHub
#clojure-spec
<
2016-09-13
>
jmglov06:09:13

@bahulneel I'm working on upgrading a production project to Clojure 1.9 and spec right now, so I'll keep this channel informed of any new stuff I figure out with the clojure.test integration.

jmglov06:09:05

Given that clojure.spec.test/check takes a quoted symbol, I shouldn't even need a macro to accomplish what I want. A plain 'ol function should do the trick. 🙂

bahulneel10:09:26

@jmglov thanks, I'll keep my ear to the ground

jmglov11:09:49

I'm having trouble getting clojure.spec.test/check to run a non-default number of tests. From reading the docs and the code, it looks like I should be able to do this:

(stest/check 'kpcs.event.processor/schema-version {:num-tests 1})
But it always runs 1000 tests:
({:spec #object[clojure.spec$fspec_impl$reify__14244 0x7b0d682d "clojure.spec$fspec_impl$reify__14244@7b0d682d"],
  :clojure.spec.test.check/ret {:result true, :num-tests 1000, :seed 1473765191336},
  :sym kpcs.event.processor/schema-version})

jmglov11:09:57

What am I missing?

jmglov11:09:15

Hrm... I realise that I'm dealing with a namespaced key. This doesn't work, either:

(stest/check 'kpcs.event.processor/schema-version {:clojure.test.check.stc/opts {:num-tests 1}})

jmglov11:09:01

OK, finally figured it out:

(stest/check 'kpcs.event.processor/schema-version {:clojure.spec.test.check/opts {:num-tests 1}})
({:spec #object[clojure.spec$fspec_impl$reify__14244 0x7b0d682d "clojure.spec$fspec_impl$reify__14244@7b0d682d"],
  :clojure.spec.test.check/ret {:result true, :num-tests 1, :seed 1473765827766},
  :sym kpcs.event.processor/schema-version})

jmglov11:09:46

I've never seen the ::foo/bar-style keywords before, only ::bar.

jmglov11:09:52

Why does ::stc/opts in the clojure.spec.test namespace expand into :clojure.spec.test.check/opts?

Alex Miller (Clojure team)11:09:56

clojure.spec.test sets up an alias of ‘stc to ‘clojure.spec.test.check

Alex Miller (Clojure team)11:09:28

the ::stc/opts just says to create a fully-qualified keyword using the local alias stc so that expands

jmglov12:09:34

@alexmiller Thanks for the explanation!

uwo17:09:11

could someone point me to the reasoning behind fspec requiring :ret and fdef not?

Alex Miller (Clojure team)17:09:06

I think they both used to and fdef was relaxed

Alex Miller (Clojure team)17:09:10

fspec prob should be too

Alex Miller (Clojure team)17:09:23

if you file a jira enhancement we’ll look at it

Alex Miller (Clojure team)17:09:41

(in other words, I think no reason :)

uwo17:09:50

🙂 thanks

esp117:09:38

fyi :ret is apparently required for fspec in alpha12

esp117:09:02

(s/explain (s/fspec :args empty?) (fn [] nil))
Success!
=> nil
(s/valid? (s/fspec :args empty?) (fn [] nil))
=> false

Alex Miller (Clojure team)18:09:44

just to be sure, that’s the same thing @uwo said above right?

Alex Miller (Clojure team)18:09:09

ok, I’m agreeing that’s wrong if it wasn’t clear :)

esp118:09:44

yup just pointing out that it’s required now. in previous alphas :ret was actually not required on fspec, but in alpha12 that restriction is enforced

jannis18:09:52

Is there a way to refer to a spec that is defined later in the same file? E.g. (s/def ::foo (s/with-gen ::bar ...)) ... (s/def ::bar ...) ?

jannis18:09:00

I may be getting an unspecified behavior, where sometimes the spec is found and sometimes it isn't, resulting in conform returning a tagged, conformed value and sometimes returning the untagged original value.

jannis18:09:17

Granted, the second spec is more complex than in this example but the first is pretty much that.

jannis18:09:58

(describe ::foo) says :clojure.spec/unknown.

darwin18:09:48

clojurescript related question, I’m working on a library which uses clojure.spec to describe a data structure using s/*, the data structure can be used statically during compilation in macros, or during runtime in cljs. all is nice and shiny on clj side[1], but on cljs side, I want native js arrays to be treated as collections for the purpose of speccing, but unfortunatly s/* does not treat them such. Ended up writing custom predicates for native array case[2], just wondering if there is a better way to teach s/* to walk native js arrays the same way as cljs vectors. [1] https://github.com/binaryage/cljs-oops/blob/master/src/lib/oops/sdefs.clj [2] https://github.com/binaryage/cljs-oops/blob/master/src/lib/oops/sdefs.cljs

jannis18:09:26

Funny. (s/def ::foo (s/with-gen (s/and ::bar) ..)) makes it work at all times.

Alex Miller (Clojure team)18:09:07

@jannis I don’t know of any issue with that. however, one of the perf changes in alpha12 means that one spec gets compiled into another’s definition (via delay) so when you change (re s/def) a spec at the repl, downstream specs need to be re-s/def’ed as well

Alex Miller (Clojure team)18:09:17

is there any chance you are seeing this behavior at the repl?

Alex Miller (Clojure team)18:09:51

maybe when you made it “work” you just caused a new s/def that was needed

Alex Miller (Clojure team)18:09:40

@esp1 I don’t know of any change that would have altered this behavior in alpha12, but that’s possible (or that it changed at some point during the alphas)

esp118:09:37

actually previously i was using tonsky’s future-spec port of spec to 1.8, so possibly it was something specific to that, not sure

jannis18:09:34

@alexmiller: If I load the namespace that these specs are in I get it in the REPL. If I reload the same namespace, it disappears. And I get it when running tests outside the REPL (using boot test).

jannis18:09:48

This is alpha11 though. I can't use alpha12 at the moment because it fails requiring DataScript due to an invalid ns expression in it.

Alex Miller (Clojure team)18:09:36

I can’t even run the first line of that with a bare alpha12 repl, not sure about earlier

Alex Miller (Clojure team)18:09:35

I realize this is slimmed down, but I don’t think you should expect to with-gen over a spec that doesn’t exist yet

jannis18:09:54

These specs are for a language that is recursive (think: Om Next query expressions). How would I include the recursive nature in the spec other than refering to the top-level spec in a part of it?

jannis18:09:25

The top-level spec needs the sub-spec, the sub-spec needs the top-level spec. Hmm...

Alex Miller (Clojure team)19:09:35

I’m talking about with-gen in particular

Alex Miller (Clojure team)19:09:11

you can provide gen overrides separately too of course. gen with recursion is generally hard.

jannis19:09:37

How do I do it separately?

Alex Miller (Clojure team)19:09:00

fns like instrument take an override map

Alex Miller (Clojure team)19:09:09

from name (or path) to generator

jannis19:09:01

Ah, yes. So that would also work with clojure.spec.test/check. I'd prefer to have all generators defined along with the actual spec so it's as reusable as possible (e.g. in combination with fdef args in functions other people may write). I'll see what the best solution is. Thanks!

bhagany19:09:59

I'm trying to understand why nested calls s/cat don't operate the way I expect - to illustrate:

cljs.user> (s/explain (s/cat :x number? :y number? :z number?) [0 0 0])
Success!
nil
cljs.user> (s/explain (s/cat :coords (s/cat :x number? :y number? :z number?)) [[0 0 0]])
In: [0] val: [0 0 0] fails at: [:coords :x] predicate: number?

nil
In my actual situation, I'm trying to reuse the inner s/cat as both the return value of a fn, and an argument to another fn. Also, it does work the way I expect if I use (s/tuple number? number? number?), but I'd like to be able to conform it and get a map. Am I missing something?

seancorfield19:09:44

(s/explain (s/cat :coords (s/spec (s/cat :x number? :y number? :z number?))) [[0 0 0]]) => Success!

bfabry19:09:48

@bhagany the regex operators assume concatenation by default, you need to wrap nested calls in s/spec

bfabry19:09:34

covered towards the bottom of this section http://clojure.org/guides/spec#_sequences

bhagany19:09:12

I'd read it, but I think I have not yet internalized that cat is a regex operator. thanks again

Alex Miller (Clojure team)20:09:45

any set of nested regex ops (`cat`, alt, ?, +, *, &, keys*) describes the structure of a single sequential context

Alex Miller (Clojure team)20:09:49

which is just like regex on a string

Alex Miller (Clojure team)20:09:15

strings are different in that a single character in a string can’t also be a string (but that is true of elements in a Clojure sequential collection)

hiredman20:09:57

the video of dnolen's talk on parsing with derivatives / spec is up https://www.youtube.com/watch?v=FKiEsJiTMtI

gfredericks22:09:54

@alexmiller: test.check already supports collections distinct by custom key-fns

gfredericks22:09:28

E.g. gen/vector-distinct-by

gfredericks22:09:14

@jmglov: http://github.com/gfredericks/schpec exists in case you don't want to bother managing a whole library for that function

wilkes23:09:22

Are there any conventions around where to put specs? In the namespace, in a special whatever.spec namespace, etc..

seancorfield23:09:26

@wilkes "it depends" is the answer to that.

seancorfield23:09:22

At World Singles, our specs are very data centric so they mostly live in their own namespace and we pull them into other namespaces as needed, and then our tests pull them in to instrument / check the code.

seancorfield23:09:11

In clojure.java.jdbc all the fdef’s are in a separate namespace so the code still works with pre-1.9.0 versions of Clojure.

seancorfield23:09:17

But if you know you’re only going to use 1.9.0 onward and you’re mostly spec’ing functions, rather than data, I’d imagine it would be convenient to put fdef’s next to their defn’s in the same namespace.

wilkes23:09:08

@seancorfield Thanks, that helps. I was expecting this to be at least in flux until people have spent some time with specs in their projects.

Alex Miller (Clojure team)23:09:48

Clojure itself is putting specs in clojure.core.specs