Fork me on GitHub
#clojure-spec
<
2018-03-26
>
borkdude11:03:46

is it possible to instrument an anonymous function?

borkdude11:03:45

how? say I have a re-frame event:

(reg-event-fx ::foo
  (fn [...] ...))

borkdude11:03:00

I could pull the fn out and name it, but that gets tedious

mpenet11:03:02

I think the approach would be to spec reg-event-fx and have the second arg speced via fspec

mpenet11:03:39

otherwise you can/need to add s/asserts if you want to have it "contained" at the anonymous function level

borkdude11:03:07

you can’t do that because the function reg-event-fx receives is a different one every time. I want to be specific about the concrete function, not the function argument of reg-event-fx

borkdude11:03:14

I think for now it’s easiest to name it then

borkdude12:03:42

hmm:

cljs.user=> (def param-keys [:query/query
       #_=>                  :query/source
       #_=>                  :vocab/filter
       #_=>                  :dict/guid
       #_=>                  :dict/labels?])
#'cljs.user/param-keys
cljs.user=> (s/def ::params
       #_=>   (s/keys :opt
       #_=>           param-keys))
              ^
param-keys is not ISeqable at line 2

borkdude12:03:30

it only expects me to pass in literals? that’s disappointing

mpenet12:03:33

you need to use eval to pass params-keys, s/keys is a macro

mpenet12:03:18

Hopefully it something improved in the next spec iteration, it's a common problem

mpenet12:03:12

s/merge (or s/and) can sometimes help in these case too

mpenet12:03:31

to compose multiple sets of s/keys

mpenet12:03:02

hence the "sometimes" it does not always work

borkdude12:03:00

Is this a valid way of saying I want either :dict/guid or :query/query + these optional keys?

(s/def ::params
  (s/merge (s/or :guid (s/keys :req [:dict/guid])
                 :query (s/keys :req [:query/query]))
           (s/keys :opt
                   [:query/source
                    :vocab/filter
                    :dict/labels?])))

Alex Miller (Clojure team)12:03:35

(s/def ::params
  (s/keys
    :req [(or :dict/guid :query/query)] 
    :opt [:query/source :vocab/filter :dict/labels?]))

borkdude12:03:18

regular or?

borkdude12:03:52

btw it seems to work

borkdude12:03:12

thanks. is there also a way to get exclusive or?

borkdude12:03:38

and is this usage of or undocumented?

borkdude12:03:12

I could also handle this via an extra s/and + predicate

borkdude12:03:31

(s/def ::params
  (s/and
   (s/keys
    :req [(or :dict/guid :query/query)] 
    :opt [:query/source :vocab/filter :dict/labels?])
   (fn [m]
     (not (and (:dict/guid m)
               (:query/query m))))))

Alex Miller (Clojure team)12:03:12

if you implement xor as a function and use there, it will work. but I make no guarantees that that will continue to work in the future.

borkdude12:03:52

this is undocumented right

Alex Miller (Clojure team)12:03:22

yes and not guaranteed to work in the future

borkdude14:03:12

Are there parts that we can rely on, since spec is still in alpha?

borkdude14:03:07

Don’t mind breakage btw if it’s for the better

Alex Miller (Clojure team)14:03:58

generally, it’s better to rely on the documented usage than the undocumented usage

borkdude14:03:53

I’m emitting a warning in a s/and conformer function.

(fn [{:keys [opts]}]
           (if-let
               [unexpected
                (seq
                 (apply dissoc opts expected-keys))]
             (do (warn "Unexpected options" unexpected "in widget" (or (:id opts)
                                                                       (:title opts)))
                 false)
             true))
I see this message twice. Is this because spec does something like “if not valid run it again for the explanation”?

borkdude14:03:12

The error that spec returns itself is a bit unsatisfying here, that’s why I want to print extra info

Alex Miller (Clojure team)14:03:38

there are no guarantees on the number of times a conformer function might be run (in a regex with branches, it may be run many times). I’m not sure why it’s run more than once in this particular case, but it’s possible that your explanation is correct.

borkdude14:03:53

ok no problem at all, just wanted to know

borkdude14:03:11

maybe I could write this spec a little better, so spec provides what keys are unexpected though

borkdude14:03:31

but this goes against the default of spec where extra keys are just allowed

borkdude14:03:45

(clojure.test/is (empty? [1 2 3]))
FAIL in () (NO_SOURCE_FILE:37)
expected: (empty? [1 2 3])
  actual: (not (empty? [1 2 3]))