Fork me on GitHub
#clojure-spec
<
2018-05-07
>
alexandergunnarson02:05:34

So, reached what seems to me to be a bug: (gen/sample (s/gen (s/and (s/? string?) string?))) -> ([""] [""] ["4"] [""] ["Ii5"] ["fye"] ["x4oa"] ["6i"] ["2LH7cR"] ["Y"]) But it seems that this should fail just as (s/and number? nil?). [""], for instance, is not a string?.

Alex Miller (Clojure team)11:05:33

s/? matches collections but conforms to a value and s/and flows conformed values so I think this is the expected behavior

Alex Miller (Clojure team)11:05:36

Using s/? as a top level regex op often leads to confusing behavior - this is tricky. Usually it gets nested in s/cat or something

👍 4
alexandergunnarson13:05:56

Thanks! Yeah I found that it works with s/exercise so that makes sense at least

alex-dixon13:05:57

Should I expect spec validation errors to be thrown if I call a function that has a spec registered with s/fdef in CLJS?

alex-dixon13:05:41

(defn foo [a b] a)
=> #'elp.components.dialogs/foo
(s/fdef foo :args (s/cat :attributes map? 
                         :children vector?))
=> elp.components.dialogs/foo
(foo 1 2)
=> 1
I have check-asserts on…working with specs defined with s/def and {:pre (s/valid? ….

Alex Miller (Clojure team)13:05:48

have you instrumented it?

alex-dixon13:05:10

I was confused about that as well. An example I saw used s/instrument from the spec namespace….maybe it moved? Showing as undeclared var

Alex Miller (Clojure team)13:05:09

it’s in the clojure.spec.test.alpha namespace (in clojure) and parallel in cljs

Alex Miller (Clojure team)13:05:27

although I think you can just require that same ns in cljs and it will automatically load the right one

alex-dixon13:05:59

Thanks. Sorry…lazy this morning

alex-dixon13:05:01

I’m on cljs 1.9.946 (unfortunately). Tried googling and can’t discern whether spec.test.alpha is a separate library

alex-dixon13:05:52

Question after that would be how to instrument all functions there’s a fdef for

Alex Miller (Clojure team)13:05:35

clojure.spec.test.alpha is a namespace and is included in clojurescript

Alex Miller (Clojure team)13:05:51

(well the cljs equivalent)

Alex Miller (Clojure team)13:05:00

several arities - no args = instrument all registered fdefs, or with a single symbol or with a collection of symbols

Alex Miller (Clojure team)13:05:25

instrument is covered in the guide above and should work the same way in clojure and clojurescript

🎉 4
Alex Miller (Clojure team)14:05:56

oh, one caveat is that you will likely need to include org.clojure/test.check 0.9.0 as a dep

alex-dixon14:05:14

Ah hah. Thank you 🙂

Alex Miller (Clojure team)14:05:03

ClojureScript 1.10.238
cljs.user=> (defn foo [a b] a)
#'cljs.user/foo
cljs.user=> (require '[clojure.spec.test.alpha :as stest])

cljs.user=> (require '[clojure.spec.alpha :as s])

cljs.user=> (s/fdef foo :args (s/cat :attributes map?
                         :children vector?))
cljs.user/foo
cljs.user=> (stest/instrument `foo)
[cljs.user/foo]
cljs.user=> (foo 1 2)
#error {:message "Call to #'cljs.user/foo did not conform to spec:\nIn: [0] val: 1 fails at: [:args :attributes] predicate: map?\n:cljs.spec.alpha/spec  #object[cljs.spec.alpha.t_cljs$spec$alpha1385]\n:cljs.spec.alpha/value  (1 2)\n:cljs.spec.alpha/args  (1 2)\n:cljs.spec.alpha/failure  :instrument\n", :data #:cljs.spec.alpha{:problems [{:path [:args :attributes], :pred cljs.core/map?, :val 1, :via [], :in [0]}], :spec #object[cljs.spec.alpha.t_cljs$spec$alpha1385], :value (1 2), :args (1 2), :failure :instrument}}
Error: Call to #'cljs.user/foo did not conform to spec:
In: [0] val: 1 fails at: [:args :attributes] predicate: map?
:cljs.spec.alpha/spec  #object[cljs.spec.alpha.t_cljs$spec$alpha1385]
:cljs.spec.alpha/value  (1 2)
:cljs.spec.alpha/args  (1 2)
:cljs.spec.alpha/failure  :instrument

alex-dixon14:05:30

Thanks @alexmiller. Dev setup for cljs with spec is now:

(defn dev-setup []
  (when config/debug?
    (stest/instrument)
    (s/check-asserts true)
    (set! s/*explain-out* expound/printer)
    (println "dev")))

pfeodrippe14:05:14

Hi, guys, we'are having problems spec'ing protocols, we're implementing the protocols with records, so instead of wrap manually the protocol methods with functions, we're defining a defrecord* macro of the kind

defmacro defrecord*
  [name fields pname & opts+body]
  (let [[{:keys [method-parser],
          :or   {method-parser rest-symbol}}
         body]
        (parse-opts opts+body)]
    `(do (defrecord ~name
           ~fields
           ~pname
           ~@body)
         ~(-build-defns-from-protocol pname (eval method-parser)))))

pfeodrippe14:05:04

Is it a good approach for now?

Alex Miller (Clojure team)15:05:41

I think it’s a bad idea to wrap protocol functions (as you then destroy many of the benefits of protocol functions)

bronsa16:05:40

why? that's the advice I've always seen given (even before spec was a thing) : use protocol methods for polymorphism and a wrapping function for validation + varargs + else

bronsa16:05:58

unless you're talking about a different "wrapping"

Alex Miller (Clojure team)16:05:34

I wouldn’t wrap it purely to use spec

Alex Miller (Clojure team)16:05:12

there are some good reasons to wrap a call to a protocol but you don’t necessarily need one

Alex Miller (Clojure team)15:05:16

rather, I would recommend just not spec’ing protocol functions

dominicm17:05:47

@alexmiller I'm curious, why not spec protocol functions?

Alex Miller (Clojure team)18:05:04

or rather you can’t for the purposes of instrument

Alex Miller (Clojure team)18:05:50

I suppose you could spec them regardless for doc (and maybe check)? I haven’t tried it.

dominicm21:05:27

@alexmiller I thought you were suggesting it would be a bad idea even if it could be done. I wasn't missing any reason it would be a bad idea 😊