Share your thoughts in the 2020 Clojure Community Survey!

Welcome! Please see the About page for a little more info on how this works.

0 votes
in Spec by

When using clojure.spec for elaborate specifications and clojure.spec.gen for generative testing, developers often find themselves writing code which heavily relies on clojure.spec.gen/fmap. This is sometimes unnatural and difficult to read.

To make writing custom generators easier, this patch ports test.check/let to clojure.spec.gen. Now developers can write generators more simply.

3 Answers

0 votes
_Comment made by: xcthulhu_

For example, if a user wanted to make a generator of vectors with length between 5 and 11 or 20 to 40 elements, consisting of keywords which were either `:a` or `:b`, they would have to write something like:

(gen/fmap (fn [[n gens]] (take n gens))
          (gen/tuple (spec/gen (spec/or :short (int-in 5 11)
                                        :long (int-in 20 40)))
                     (gen/vector (gen/elements #{:a :b}) 40)))

With this patch they could write this as:

(gen/let [length (spec/or :short (int-in 5 11)
                          :long  (int-in 20 40))]
  (repeat length #{:a :b}))

0 votes

Comment made by: rickmoynihan

Ran into the lack of this useful macro recently. And spoke to @gfredricks about it on slack. He mentioned that the supplied patch looks to be a complete reimplementation of gen/let with different behaviour.

He suggested an alternative might be to have the gen/let macro make a require call, which when succeeds just expands to use the test.check let implementation. If the require fails the macro can expand into code that raises an appropriate error. Presumably indicating that test.check needs to be included as a dependency.


(defmacro let [& args] (try (require ...) `(...) (catch Exception e `(throw ...))))

0 votes
Reference: (reported by alex+import)