Fork me on GitHub
Jakub Holý (HolyJak)10:06:09

Hello, how do I spec protocol methods? Just (s/fdef protocol-method :args (s/cat :this any? ...)) ?


You'll have to wrap the protocol method into a spec-able function. E.g. using defn-spec:

(defprotocol Protocol
  (-foo [_ x]))

(ds/defn-spec foo
  {::s/args (sp/pos any? ::specs/x)
   ::s/ret  ::specs/y}
  [this x]
  (-foo this x))

👍 4
😢 4

what is (sp/pos ...) ?


@U0HJD63RN ah, it's a local helper to reduce verbosity:

   (defmacro -cat
     [& body]
     (if (-cljs-env? &env)
       `(cljs.spec.alpha/cat [email protected])
       `(clojure.spec.alpha/cat [email protected]))))

   (defmacro pos
     "Shorthand for s/cat but without specifying key for every position.
     Name means \"positional\".
     Keys are generated automatically: :pos1, :pos2, etc.
     Convenient in ::s/args so that you don't have to keep s/cat keys in sync with function argument names.
     Why not just use s/tuple instead? Because it doesn't support regex ops (e.g. s/?)."
     [& pred-forms]
     (let [keys-pred-forms (apply concat
                                  (for [[i pred-form] (map-indexed vector pred-forms)]
                                    [(keyword (str "pos" (inc i))) pred-form]))]
       `(-cat [email protected]))))


ah nice - I had a feeling that was how it worked, just got my hopes up it might be something in spec-2 😞

🙂 8

Is there a way to control the recursion depth for spec generators?


My use case is a recursive tree-like spec that I’m generating using (gen/generate (s/gen ::my-spec))

Alex Miller (Clojure team)17:06:43

there are some dynamic var knobs in the spec.alpha namespace

Alex Miller (Clojure team)17:06:51

also, if you have any collection specs, I usually use :gen-max 3 to limit nested collections from going out of control

Alex Miller (Clojure team)18:06:19

even given those, I think there are some known issues where the recursion is not well controlled


Awesome, :gen-max 3 is working for me, thanks!


so for a string? bool in a macro, I get

{:path [:define-fx-params :orc-string],
                          :pred clojure.core/string?,
                           "\ngkTransPose init 1\ngkTransRand init 0.1"),
                          :via [:panaeolus.csound.macros/orc-string],
                          :in [:orc-string]}
So it's obviously a string, but it's a macro, so I understand it sees a list at this point, any good tip to make this string check?


(s/def ::orc-string #(string? (eval %))) works actually

Alex Miller (Clojure team)23:06:53

That’s not a good pattern

👍 4
Alex Miller (Clojure team)23:06:50

By eval‘ing here you’re basically ruining the lazy evaluation of macros and could even cause issues

Alex Miller (Clojure team)23:06:36

In general macro specs are often tricky to write unless you’re trying to enforce positional constraints

Alex Miller (Clojure team)23:06:56

For something like this I would probably not spec it at all

Alex Miller (Clojure team)23:06:18

But would spec that arg as any? if I was