Fork me on GitHub
#clojure-spec
<
2020-09-02
>
johanatan04:09:33

does anyone see why the following wouldn't work? I'm getting an error: sym not defined on the stest/check line.

(defn filtered-check [sym opts]
  (let [filter (or (.get (js/URLSearchParams. js/window.location.search) "filter") "")
        matches? (fn [s] (or (= filter "all")
                             (clojure.string/includes? (name s) filter)))]
    (when (matches? sym)
      (stest/check sym opts))))

johanatan04:09:02

this is the exact error:

Unable to resolve symbol: sym in this context

  114  (defn filtered-check [sym opts]
  115    (let [filter (or (.get (js/URLSearchParams. js/window.location.search) "filter") "")
  116          matches? (fn [s] (or (= filter "all")
  117                               (clojure.string/includes? (name s) filter)))]
  118      (when (matches? sym)
  119        (stest/check sym opts))))
                          ^---

johanatan04:09:45

it seems that stest/check may be a macro (I got "can't take value of macro" previously) but in the spec.alpha code it is defined as a function: https://github.com/clojure/spec.alpha/blob/master/src/main/clojure/clojure/spec/test/alpha.clj#L373

seancorfield04:09:07

Perhaps it is a macro in ClojureScript?

seancorfield04:09:47

Yup: http://cljs.github.io/api/cljs.spec.test.alpha/check it's a function in Clojure and a macro in ClojureScript.

seancorfield04:09:15

@johanatan You might have to ask in #clojurescript -- that seems an unfortunate and gratuitous difference in the implementations.

borkdude12:09:20

I've also ran into this a couple of times

borkdude13:09:50

I think the root of this lies in dynaload which is a macro in CLJS because requires are only possible at compile time (when not using a REPL). This implies that library code around check yields another macro. E.g. https://github.com/borkdude/respeced/blob/f5ff67aa78f588e7bad2a1b86dd1a646d3fdab3d/src/respeced/test.cljc#L81 and https://github.com/borkdude/respeced/blob/f5ff67aa78f588e7bad2a1b86dd1a646d3fdab3d/src/respeced/impl.cljc#L71.

johanatan16:09:05

I suppose my best course of action is to succumb to macro contagiousness and make this a macro ?

borkdude17:09:31

macros beget macros yeah

johanatan21:09:44

this is what i ended up coming up with (for anyone following along):

(defmacro filtered-check [sym opts]
  `(let [fltr# (or (.get (js/URLSearchParams. js/window.location.search) "filter") "")
         check# (fn [res#]
                    (cljs.test/is (= true (-> res# :clojure.spec.test.check/ret :result))
                        (goog.string/format "spec check failure:\r\n%s" (with-out-str (cljs.pprint/pprint res#)))))]
     (when (or (= fltr# "all") (clojure.string/includes? (name ~sym) fltr#))
       (let [check-res# (clojure.spec.test.alpha/check ~sym ~opts)]
         (clojure.spec.test.alpha/summarize-results check-res#)
         (if (nil? check-res#)
           (cljs.test/is false "stest/check result was nil. did you pass it any valid symbols?")
           (doall (map check# check-res#)))))))
you can use it with figwheel main to filter your stest/check calls:
location/figwheel-extra-main/auto-testing?filter=the_filter
and with your calls to the macro such as:
(macros/filtered-check ns/sym {:clojure.spec.test.check/opts {:num-tests N})

johanatan21:09:24

[massive time saver once you start to accumulate many of these]