Fork me on GitHub

@gfredericks does the maven clojure plugin do the same monkey-patching of clojure.test that lein does?,jdk=Sun%20JDK%201.6/console <— seems to be the same exception as I got testing locally


Not sure how to tell Maven’s plugin not to do the Leiningen naughtiness 🙂


com.theoryinpractise.clojure.testrunner is your culprit


I don't know about maven clojure, but it smells like something similar


this seems a lot harder to work around given the constraints


It rebinds the report function


do you get to choose an alternate version of the clojure-maven-plugin if you want?


I could override it for my project I think, yes (this is for java.jdbc)


Is there a version that is compatible with test.check’s clojure_test stuff?


alternately, any tactic you can think of that lets you require test.check.clojure-test prior to that line running will fix it


no I was just imagining forking it :)


Hahaha… ok...


so a user.clj could work if you can keep it out of the release jar


Would that run with Maven?


it runs when clojure boots up


user.clj is a pretty reliably way to slip something in before just about anything else happens


Pretty sure that doesn’t work with Boot? (more an FYI but…)


I don’t remember… but it was discussed in #boot a while back...


probably something about their magical space age classloader thing


And how do you get it to be loaded for Maven running Clojure?


@seancorfield heck for that matter adding a (:require clojure.test.check.clojure-test) to any of your namespaces should also work


putting the user.clj on the classpath means that clojure.core reads it at then end of its loading


e.g. src/test/resources/user.clj or whatever


Ah, yeah, that worked...


@seancorfield you can define/give your own test runner script to clojure-maven-plugin if you need to


Dynamically requireing that namespace when my test namespace loads seems to do the trick — and I can remove the Leiningen monkey-patch setting as well.




in the pom


I have this now in my test ns:

(def with-spec? (try
                  (require '
                  (require 'clojure.spec.test)
                  ;; require this to workaround rebinding of report multi-fn
                  (require 'clojure.test.check.clojure-test)
                  (let [syms ((resolve 'clojure.spec.test/enumerate-namespace) ']
                    ((resolve 'clojure.spec.test/instrument) syms))
                  (println "Instrumenting with clojure.spec")
                  (catch Exception _


Works with Leiningen and Maven!


Sweet - PRs welcome to improve that default test runner script as well.


I have a spec that looks like this:

(s/def ::value <???>)
(s/def ::type #{"type-date", "type-weirdo", "no-value"})
(s/def ::ent (s/keys :req-un [::type] :opt-un [::value]))
(s/def ::ents (s/coll-of ::ent))
Depending on the type, the value needs to be different, e.g., for type-date, the value should be a date. I know there are multimethods that can, and probably should, be used, but I just can't get it right. What comes at the <???>, so I can have different predicates for value depending on the value of type?

Alex Miller (Clojure team)15:09:27

have you looked at s/multi-spec?


I ran into this problem two days ago you want to make N :value specs. (e..g.`(s/def :my/value <???>)`, (s/def :other/value <???>), (s/def :one.more/value <???>) and then dispatch those :value's with a multimethod


yeah, I'm looking at it. but it seems to be somewhat different. So, I could do:

(defmulti ent-type ::type)
(defmethod ent-type "type-date" [_]
   (s/keys :req-un [::value])
(s/def ent-type (s/multi-spec ent-type ::type))
So I day value is required for "type-date". But that still doesn't solve the problem. I must be missing something...


@spinningtopsofdoom Allright, and I don't need to care about the namespaces? - I mean, the map contains just 'value', no namespaces. I'll give it a few tries.

Alex Miller (Clojure team)15:09:54

instead of using ::value, you could define many :foo1/value :foo2/value :foo3/value specs

Alex Miller (Clojure team)15:09:07

each defmethod would use a different one in :req-un


@alexmiller is there any movement on having spec/keys take a map of keywords and specs (e.g.)

(spec/def :one-map (spec/keys :req-un {:value <one spec>})
(spec/def :other-map (spec/keys :req-un {:value <other spec>})
So that you don't have to have registered specs for spec/keys

Alex Miller (Clojure team)15:09:07

well, it will never take inline specs

Alex Miller (Clojure team)15:09:16

we might possibly loosen the constraint between key name and spec name, but it’s part of the design that s/keys doesn’t use inline specs and I don’t expect that to change

Alex Miller (Clojure team)15:09:39

the idea is to encourage defining semantics for attributes


The constraint between key name and spec name is what I would like to loosen. So then my example would be

(spec/def :one-map (spec/keys :req-un {:value ::one-spec})
(spec/def :other-map (spec/keys :req-un {:value ::other-spec})

Alex Miller (Clojure team)15:09:11

yeah, something like that has been mentioned, but I do not know whether we’ll end up doing it or not


Well I'll make a Jira ticket for that if it's not already there, then. Thanks for the clarification.

Alex Miller (Clojure team)15:09:42

I do not know of a jira ticket for this


Hi everybody, very new to specs, but have already a good part implemented. Now I need a little help on something that is probably very easy, but I'm stuck. I have a def that verifies a url to be a s3 url (s/def ::s3-url #(str/starts-with? % "s3"). Using it to check a single argument works. Now I have a function with 2 arguments (from-url and to-url) of which 1 needs to conform to that spec. Can anyone hint me for the solution.


This is what I have:

(s/def ::valid-url is-valid-url?)
(s/def ::s3-url #(str/starts-with? % "s3"))

(defn sync
  "sync an s3 folder with a local folder, this works both ways"
  [from-url to-url])

(s/fdef sync
        :args (s/and (s/cat :from-url is-valid-url? :to-url is-valid-url?)
                     ??? this is where I get lost ???))

Alex Miller (Clojure team)15:09:08

(s/fdef sync
        :args (s/cat :from-url is-valid-url? :to-url is-valid-url?))

Alex Miller (Clojure team)15:09:24

I guess I’m also wondering what the difference is between is-valid-url?, ::valid-url and ::s3-url

Alex Miller (Clojure team)15:09:53

given that you have specs, I would actually use the specs in the sync fdef


Good one, I will have to clean that up

Alex Miller (Clojure team)15:09:24

(s/fdef sync :args (s/cat :from-url ::s3-url :to-url ::s3-url))


The function will be called either (sync "" "") or (sync "" "")


What I am trying to spec is that either url is an s3 url

Alex Miller (Clojure team)15:09:55

right so you could have something like:

(s/def ::file-url #(str/starts-with? % “file://“))
(s/def ::s3-url #(str/starts-with? % “s3://“))
(s/def ::aws-url (s/or :file ::file-url :s3 ::s3-url))
… then use ::aws-url in the sync fdef

Alex Miller (Clojure team)15:09:08

or whatever is appropriate

Alex Miller (Clojure team)15:09:33

oh, you want a constraint across the args!


Yes, is that beyond what spec is meant for?

Alex Miller (Clojure team)15:09:03

You can do it with s/and like you were or you can do that in the :fn spec too

Alex Miller (Clojure team)15:09:45

fn is used for constraints between args and ret or also across args

Alex Miller (Clojure team)15:09:13

Only the args spec is checked in instrumentation though so that might be what you want


Ah, been reading about it all day and understood the args / ret, but of course that works for across args as well.

Alex Miller (Clojure team)15:09:30

Yeah fn gets the conformed version of both args and ret


That might be the easiest way to accomplish it.


Also read about 10 times that stest/instrument only does :args, now I know that is true 😉


I have the :fn version working. I'm still curious about a solution in the :args part, where I got stuck to begin with. That way, if people use my sync function they can simply (stest/instrument `sync) and work from there.

Alex Miller (Clojure team)16:09:11

(s/fdef :args (s/and (s/cat :from-url ::aws-url :to-url ::aws-url)
                   (fn [{:keys [from-url to-url]}]
                     (or (s3-url? from-url) (s3-url? to-url)))))

Alex Miller (Clojure team)16:09:53

the second function in the s/and receives the conformed version of the first part of the and

Alex Miller (Clojure team)16:09:09

so that will be a map with :from-url and :to-url keys


Works like a charm and is actually simple enough


Learned a lot today, thanks for helping me get through that last part!


is it possible to use `s/multi-spec' on different specs? Something like - but this doesn't work:

(defmulti m [::type ::op])
(defmethod m ["date-type" "do"] [_]
  (s/keys ...))
(s/def .... (s/multi-spec m [::type ::op]))

Alex Miller (Clojure team)17:09:11

that defmulti definition looks wrong - it takes a dispatch function not a vector

Alex Miller (Clojure team)18:09:30

(defmulti m #(vector (::type %) (::op %))) maybe?

Alex Miller (Clojure team)18:09:59

or it’s a great opportunity to use juxt :)

Alex Miller (Clojure team)18:09:09

(defmulti m (juxt ::type ::op))


oh, cool... thx!

Alex Miller (Clojure team)18:09:39

and then the retag value is not valid either - should either be a tag or a fn of generated value and dispatch-tag


huh; are instrumentation exceptions supposed to escape clojure.test assertions?


oh, wait, never mind; only some of them are outside assertions 🙂