Fork me on GitHub

hi guys, how do we use variable inside s/keys like this

(def a [::first-name])
(s/def ::user (s/keys :req a))


@nxqd: I don't think we can because s/keys is a macro. Though I'm not sure if this is worth it for keys, as it doesn't capture predicates, I would expect it to be a function. As far as I can tell the only thing macro'ey it does is look at forms like (or ::foo ::bar).

Alex Miller (Clojure team)17:06:25

At the moment you can't do this except via eval or something

Alex Miller (Clojure team)17:06:52

But there has been talk of adding a fn entry point that would allow it


With check-fn and check-var, is there a way to get a "nice" explanation of the failures, like explain produces?


I'm trying to see how the changes in Alpha 6 affect the testing workflow.


@nxqd: (somewhat belatedly) you can replace the var with the function that populates it (it can cache its results, if it's an expensive call), if it's a var that it makes sense to populate at macro eval time.


Unrelated: test.check has a fn (`fmap`) that lets you call an arbitrary fn on the results of a generator. But is there any way to create a generator that just calls an arbitrary fn? I haven't found one.


The only solution I've found so far is to do (fmap (fn [_] do-what-I-want) some-arbitrary-gen), but it's pretty ugly to put in a generator and then ignore what it generates.


Folks, is it a good idea to define fdef function/macro specs next to the actual function/macro definition or would you rather define them in separate my-project.specs kind of namespace?


I'd like to associate most of my functions with specs for automatted random function testing but at the same time I don't want to clutter my code base with specs too much.


I guess there are no best practices established yet?


I've been debating that myself, haven't come to any particular conclusion.


Currently defining them on their own because it's still fairly experimental for us...but as we fully integrate them, I'll definitely consider moving them to live next to what they're speccing.


I think we’ll have data specs in separate namespaces. Not sure yet about function specs. Part of me would like them above function definitions — that seemed natural for when we used Schema and core.typed.


We went back and forth between core.typed and Schema several times before we abandoned them. With spec being in core, I think we’re more likely to stick with it.


Yeah. It also means you don't have to require the function namespaces and the function spec namespaces when you want to test functions.


There the function specs are in a separate namespace, below the data specs.


But that was mostly to ensure pre-1.9 code can still use the library


Here's my first attempt at writing function specs alongside the actual functions:


It would feel a little more natural to define the function spec like`:pre` and :post, e.g.`(defn my-fun [arg1 arg2] {:spec {:args ... :ret ... :fn ...}} <body>)` or something like it, although there are good reasons to keep them separate.


@jannis: What do you think about putting the fdefs before the function? IMHO, that's a little clearer. I like having the function specs near the functions since that provides documentation when reading the function. Not sure about data specs, though.


or rather, put each fdef before its associated fn


what have I messed up here...?

Clojure 1.9.0-alpha7
Java HotSpot(TM) 64-Bit Server VM 1.8.0_65-b17
        Exit: Control+D or (exit) or (quit)
    Commands: (user/help)
        Docs: (doc function-name-here)
              (find-doc "part-of-name-here")
Find by Name: (find-name "part-of-name-here")
      Source: (source function-name-here)
     Javadoc: (javadoc java-object-or-class-here)
    Examples from : [clojuredocs or cdoc]
              (user/clojuredocs name-here)
              (user/clojuredocs "ns-here" "name-here")
boot.user=> (require '[clojure.spec :as s])
boot.user=> (require '[clojure.spec.test :as t])
boot.user=> (defn foo [x] (inc x))
boot.user=> (s/fdef foo :args (s/cat :x integer?) :ret integer?)
boot.user=> (t/check-var foo)

java.lang.IllegalArgumentException: No :args spec for [email protected]


boot.user=> (s/fn-spec foo)
boot.user=> (doc foo)
  args: (cat :x integer?)
  ret: integer?
boot.user=> (s/fn-spec 'foo)