Fork me on GitHub
#clojure-spec
<
2022-06-24
>
joost-diepenmaat16:06:38

Hope I’m not spamming people, but I would love to get some feedback on a tool we made to help with creating spec generators: https://git.sr.ht/~jomco/proof-specs proof-specs can be run as a leiningen alias or from the repl and will exercise all data specs (keyword specs) in a set of namespaces and report on any errors. We’re using it ourselves as part of our test suite to ensure we always write generating specs and to make it easier to find out which part of complex specs are broken. Thanks for any feedback :-)

joost-diepenmaat16:06:27

Main reason we wrote the thing is that sometimes spec generators just error out with very little context making it hard to figure out which specs even work. proof-specs will at very least give you a list of every spec that won’t generate which helps a lot in figuring out what’s going on.

genRaiy22:06:39

This might be a silly question but is there a s-exp spec that can be applied recursively?

Alex Miller (Clojure team)22:06:08

No, and I think you can quickly come up with many reasons why

genRaiy23:06:06

Sure. Like I said, was a silly question. I just wanted to make sure I hadn't missed anything before moving on other options.

reefersleep09:06:11

But I guess you’re free to make a function that does recursive stuff and use it in a spec? 🙂

genRaiy09:06:09

yes, also specs can be applied recursively even if it's silly 👺

borkdude11:06:23

@U04V5V0V4 What are you looking for? Something like tree-seq + spec? This is what grasp basically does: https://github.com/borkdude/grasp

genRaiy12:06:16

ok - thanks, I remember talking about it with you but I've never looked at the code 👀

genRaiy12:06:13

to be more straightforward: I'm looking to conform all of Clojure. That's what I'm really looking to do.

genRaiy18:06:50

@U04V15CAJ one small thing I noticed in your reify spec is that you use (s/cat :reify #{'reify} ... why do you use a set rather than just the symbol 'reify? Cos that's what I do and it works but maybe set gets you something else that I'm missing?

borkdude19:06:53

Because of how spec works?

user=> (require '[clojure.spec.alpha :as s])
nil
user=> (s/valid? 'foo 'foo)
Execution error at user/eval154 (REPL:1).
Unable to resolve spec: foo
user=> (s/valid? (s/cat :foo 'foo) ['foo])
Execution error at user/eval156 (REPL:1).
Unable to resolve spec: foo
user=> (s/valid? #{'foo} 'foo)
true
user=> (s/valid? (s/cat :foo #{'foo}) ['foo])
true

borkdude19:06:01

I.e. I want to match the literal symbol 'reify

genRaiy19:06:24

yes ... actually it's neater than #(= 'reify %)which is the ugly thing I have 🙇:skin-tone-3:

reefersleep19:06:27

I use sets for comparison all the time. it's great!

genRaiy19:06:58

yeah, seems a ton more elegant and more transparent than a function

👌 1
Alex Miller (Clojure team)20:06:51

oh but it is a function ;)

1
reefersleep07:06:16

Sometimes it can make sense to make it a var as well. Like

(def valid-foo? #{:x :y :z})
(valid-foo? :x) ;=> :x

😍 2
genRaiy22:06:25

Eg (s/cat symbol? s/+ any?) but recurring

souenzzo17:06:10

You can give it a name, then recur to this name:

(s/def ::foo
  (s/cat :k keyword?
    :v map?
    :others (s/? ::foo)))
=> :user/foo
(s/valid? ::foo
  [:a {} :b {} :c {}])
=> true
(s/valid? ::foo
  [:a {} :b {} :c])
=> false
(s/valid? ::foo
  [:a {} :b {} :c []])
=> false

genRaiy18:06:41

ha, yes - actually that's what we ended up doing! 🙂

genRaiy22:06:05

[on the phone so syntax ain't great]