Fork me on GitHub
#clojure-spec
<
2018-04-30
>
jimmy06:04:32

hi guys, how can I instrument spec in another namespace?

gnl08:04:57

(st/instrument `namespace.something/function)

jimmy09:04:49

@clojurians.net thanks for you help. I have tried it and it returns empty []. If I have the fdef in the same ns, and I run (st/instrument) it works

gnl09:04:08

Just tested it to make sure I'm not missing something, but it works for me. Have you made sure that the external namespace the fdef is in is :required?

jimmy09:04:51

yes it does. I feel like there is something missing as well, but I haven’t figured it out yet, it should work like your said.

gnl09:04:55

@nxqd Can you post the head of your fdef, as in (s/fdef <name> ...)?

guy09:04:11

I found if your fdef doesn’t work correctly you can’t instrument it

guy09:04:36

if it gives that error saying it cant be satisfied after 100 tries or something, it won’t be able to be instrumented

jimmy09:04:16

@guy if I put this spec in the same ns, it works.

guy09:04:26

interesting

jimmy09:04:45

my purpose is to reuse the same fdef button ns for different functions

guy09:04:57

are you doing it across clj/cljs?

jimmy09:04:20

yes, but for now, I test in in clj repl, so it’s only java for now.

gnl09:04:39

Am I being blind here or is there no (defn button ....)?

guy09:04:53

i think he had ;;button fn

jimmy09:04:54

@clojurians.net it’s defined in another namespace.

guy09:04:02

dont you have to import it?

guy09:04:07

some-ns/button

gnl09:04:17

well then you have to (s/fdef some-ns/button)

guy09:04:18

(s/fdef some-ns/button
        :args (s/cat :opts (s/keys :opt-un [:button/type :button/state :button/size
                                            ::class])))

guy09:04:24

what gnl said 🙂

jimmy09:04:54

thanks 🙂

👍 4
guy09:04:10

Did that fix it?

jimmy09:04:28

it does. Thanks guys

guy09:04:32

excellent!

guy09:04:42

it was all gnl really :thumbsup:

guy09:04:51

Also thats a super common mistake to make so don’t worry about it

guy09:04:00

I had the same issue before

guy09:04:12

and spent an hour or two being confused

jimmy09:04:21

yeah, most of the time I just define it in the same ns 😄 so I didn’t notice this.

jimmy09:04:35

thanks a lot guys

👍 12
deansher15:04:05

This is a question about clojure.spec.alpha as an example code base, rather than about using it. In the following code, it seems to me as though alpha.clj is working very hard to avoid multimethods. Does anyone have insight into why?

(defprotocol Specize
  (specize* [_] [_ form]))

(extend-protocol Specize
  clojure.lang.Keyword
  (specize* ([k] (specize* (reg-resolve! k)))
            ([k _] (specize* (reg-resolve! k))))

  clojure.lang.Symbol
  (specize* ([s] (specize* (reg-resolve! s)))
            ([s _] (specize* (reg-resolve! s))))

  Object
  (specize* ([o] (spec-impl ::unknown o nil nil))
            ([o form] (spec-impl form o nil nil))))

(defn- specize
  ([s] (c/or (spec? s) (specize* s)))
  ([s form] (c/or (spec? s) (specize* s form))))

alexmiller15:04:16

protocols are faster

deansher15:04:12

Thanks, Alex. I wondered if it was as simple as that.

ghadi16:04:35

it's not just performance.

alexmiller16:04:05

in this particular case, the protocol has one method, so that’s not a concern

deansher17:04:13

Hmm, I’m thinking of it quite differently. The Specize protocol is allowing keywords, symbols, and (to a degree) objects to participate in the multiple-method Spec protocol, instead of using multi-methods. For example:

(defn conform
  "Given a spec and a value, returns :clojure.spec.alpha/invalid 
	if value does not match spec, else the (possibly destructured) value."
  [spec x]
  (conform* (specize spec) x))

(defn unform
  "Given a spec and a value created by or compliant with a call to
  'conform' with the same spec, returns a value with all conform
  destructuring undone."
  [spec x]
  (unform* (specize spec) x))

jimbob16:04:19

is there a good spec function that will return the req-un’ed keys for a spec defined map?

jimbob16:04:12

example. i have a record blah

{:a a :c c :e e }
and a spec def
(s/def ::blah-fact
  (s/keys ::req-un [::a ::e]) 
whats the best way to call a function to get back
#{:a :e}
?

ghadi16:04:12

@ben.borders Here's one way:

user=> (s/def ::mymap (s/keys :req-un [::boo ::bar]))
:user/mymap
user=> (-> (apply hash-map (-> ::mymap s/form rest)) :req-un)
[:user/boo :user/bar]

ghadi16:04:45

(s/form ::mymap) == '(clojure.spec.alpha/keys :req-un [:user/boo :user/bar])

eoliphant16:04:44

Hi, I’m working on a system of clojure based services, that passes messages based on clojure maps around. So Im thinking I can just create a common module of specs (or at least a common as they need to be), but I have one other potential wrinkle. We basically need to support ‘tenants’. So I might have the same attribute, that means the same thing throughout the system (s/def :account/number ; like "A123") so far so good. But for another tenant maybe :account/numbers should start with “B”.. Is a good way to handle this ?

alexmiller16:04:45

note that that won’t work if :req-un contains and or or @ghadi @ben.borders

jimbob16:04:23

cool that works. thanks!

ghadi21:04:41

Has anyone experienced... "Overspeccing"?

seancorfield21:04:00

@ghadi You mean, someone trying to spec "everything"? I've seen some folks (new to spec) go down that path...

ghadi21:04:21

Maybe not as an intent, but definitely as an effect

ghadi21:04:43

e.g. spec the wire boundary, spec post-transformation, spec the output (of whatever)

ghadi21:04:54

then you end up with hundreds of specs

alexmiller21:04:48

it’s useful to spec core data structures, boundaries, functions amenable to property testing

alexmiller21:04:31

but it’s totally ok to not spec stuff, or use any? or ifn? etc to under-spec things that are still in process or too annoying to spec