Fork me on GitHub

what is the idiomatic way to write specs? in a spec directory? how do you run them? is there a lein spec like lein test? how do you guys do that? i guess specs are not just to be run in a repl while developing..

Alex Miller (Clojure team)12:10:59

Specs are code. You can either put them inline with your other code or in a separate namespace.

Alex Miller (Clojure team)12:10:16

You can use them in a variety of ways

Alex Miller (Clojure team)12:10:13

If you want to use them in your production code you can call s/conform or s/valid?

Alex Miller (Clojure team)12:10:50

If you want to be able to toggle them on or off you can use s/assert

Alex Miller (Clojure team)12:10:11

If you want to use them during testing you can use stest/instrument (to check calls to a function) and stest/check to generatively test a spec'ed function


I think I may have run into a bug in conform:


(s/def ::mapping-offset
  (s/cat :offset nat-int? :length nat-int?))

(s/def ::mapping-offsets
  (s/map-of ::mapping-offset ::mapping-offset))


(s/conform ::mapping-offsets {[0 3] [4 3]}) => {[0 3] {:offset 4, :length 3}}


Easy enough to work around using s/tuple instead of s/cat, but figured I’d mention it here. Should I file a bug report?

Alex Miller (Clojure team)18:10:50

no, that’s expected behavior

Alex Miller (Clojure team)18:10:09

you can pass :conform-keys true as additional map-of options to get both conformed

Alex Miller (Clojure team)18:10:52

default is false (as often you don’t need it, and there’s a perf cost, and there’s the possibility of conformed keys overlapping and losing data in the conformed map)

Alex Miller (Clojure team)18:10:23

this is in the docstring for map-of too

Alex Miller (Clojure team)18:10:03

I’m assuming that you were objecting to the vals being conformed but not the keys

Alex Miller (Clojure team)18:10:45

if you actually want neither conformed, you can do that with a conformer on the val spec

Alex Miller (Clojure team)18:10:29

or change it to use tuple as you suggested

Oliver George22:10:50

Hey @alexmiller, I think there's a bug in (s/form (s/every pred ...)). (s/form (s/coll-of (s/keys :req-un [:PROJ_CONTACT/NAME]))) returns a pred of s/keys instead of clojure.spec/keys.

Alex Miller (Clojure team)22:10:48

yes, there’s a ticket and a patch waiting for Rich already on that

Alex Miller (Clojure team)22:10:20

that patch was super annoying with all the macrology - it’s hard to tell but I put a lot of work into making that as small a change as it is

Oliver George22:10:58

That code is quite tricky.

Oliver George22:10:39

While you're about. I'm interested in finding a good approach for walking through specs to transform. In my case I'd like to use specs to produce a simple version of a datomic pull query.

Oliver George22:10:05

I suspect there's a slightly more artful approach. Any chance you can point me at an example.

Alex Miller (Clojure team)22:10:12

so one thing that is coming (and is behind all my spec form fixes) is specs for s/form’s return, basically specs for spec forms, which is the path you’re on there


Has anyone tried using test.check cljs.spec and core.async together?

Alex Miller (Clojure team)22:10:02

@olivergeorge so I think using spec to conform spec forms is imo a good approach


I am having some trouble getting a test that uses promises wired up to be the body of a property. (the example i am extending is here and here

Oliver George22:10:13

@alexmiller Thanks. The spec form specs (!) sound useful. Perhaps those could be the basis for post-walk wrapper or zipper. I'm thinking that might make walking/transforming the spec tree less quirky.

Oliver George22:10:28

Nice to know i'm on the right track. Much appreciated.


Thanks, alexmiller, I should have checked the docstring first.


is (s/keys) the best way to express s/map-of-style varargs?


assuming my key-spec is keyword? of course


@gfredericks s/keys* is for varargs


assuming you meant what I thought you did by that


in particular I mean (s/keys*) with no args

Alex Miller (Clojure team)23:10:41

I mean, that's fine but opt-un is useful on the gen side