Fork me on GitHub

There is this specs:

(s/def ::a integer?)
(s/def ::b string?)
(s/def ::m (s/keys :opt [::b]))
When I try
(s/valid? ::m {::b "b" ::a "b"})
I get :clojure.spec/invalid, explanation: val ["a"] fails... Is it a bug?


IMHO it should be valid, once spec just looks for what is defined, and on ::m spec's, there is no ::a


> When conformance is checked on a map, it does two things - checking that the required attributes are included, and checking that every registered key has a conforming value. We’ll see later where optional attributes can be useful. Also note that ALL attributes are checked via keys, not just those listed in the :req and :opt keys. Thus a bare (s/keys) is valid and will check all attributes of a map without checking which keys are required or optional.


@souenzzo this is actually by design


Specs registered under namespaced keys give the keys global meaning thus are checked whenever they are encountered


This is different than other systems. (I like it)


have a clojure.spec question, assume I have a number of specs defined for seq:s of chars, how would I define a string spec which uses them? i.e given:

(s/def ::my-char-sequence
  (s/cat :valid-chars (s/* (s/and char? #{\a \b}))))
=> my-char-sequence

(s/explain ::my-char-sequence [\a \b])
=> nil

(s/explain ::my-char-sequence [\a \c])
In: [1] val: \c fails spec: my-char-sequence at: [:valid-chars] predicate: #{\a \b}
=> nil
how would I write a string spec using the char seq spec:
(s/def ::my-string
  (s/and string?
             (??? <something using ::myc-char-sequence and perhaps (seq %) > ???)))


@mbjarland Inserting (s/conformer seq) after the string? predicate in the ::my-string spec should do the trick!


@dergutemoritz !! ahh...I knew there had to be away to make a transformation before handing it off to spec...that is great!! thanks


@mbjarland You're welcome! Note that when using that with s/conform it'll also return a seq of chars. Maybe you want to add something like (s/conform (partial apply str)) at the end of the chain.


seems conformer has a second unform argument function


would that fix it


Yeah but that's for use with s/unform for recovering the original value - slightly different approach with different pros and cons but works, too 🙂


Another option would be to use string regexen instead of spec regexen


yeah, I was hoping not to have to do string regex


I like the composability of specs


errr...I'm assuming "string regexen" refers to actual regular expression #" " matching?

Adam Munoz10:04:47

Hi everyone. How do you spec :args of any type? i.e. takes x that can be anything and returns for example boolean.

Adam Munoz10:04:31

Ok, any? 🙂

Adam Munoz10:04:37

thanks anyway


@adammunoz, I'm a beginner with spec but perhaps something like:

(defn some-fn [x]

(s/fdef some-fn
        :args (fn [_] true)
        :ret boolean? )
(doc some-fn)
  args: (fn [_] true)
  ret: boolean?

Adam Munoz10:04:56

@mbjarland Thanks. No I meant that predicate that I want is maybe any? .

Adam Munoz10:04:08

(any? 1) => true


: ) yes looks like it

Adam Munoz10:04:19

(any? "whatever") =>true


I figured any would be collection based, but you are right


@mbjarland Yeah that's what I meant by string regexen 🙂


Note that there are also various libraries which provide a structured representation of regexen similar to that of spec which can be composed just as well and compiled down to java.util.regex.Pattern


@dergutemoritz have any clj ones to share?


@mbjarland I seem to remember having seen multiple ones actually, but I fail to find them again!


@dergutemoritz : ) no worries (edit: was on touch screen...they suck)


I have used Scheme Regular Expressions with great pleasure in the past, though. Perhaps I'm mixing it up.


and as a side question, how do you organize specs for functions? Right after the function itself? in another namespace? somewhere else?


keeing them close feels good in a sense but also pollutes the code with a lot of "spec noise"...for good or bad


Personally, I like to put them before the function definition (if you mean fdefs) but I don't have enough confidence in it to recommend it as a good idea or anything 😉


Also, I'm not specing each and every function just for the sake of it


I got another one (starting to feel like a spambot here), do you see any immediate reason why this:

(s/def ::align-specifier
  (s/and char?
         #{\L \C \R \l \c \r}))

(s/def ::bracket-expr
  (s/cat :left-bracket #{\[}
         :align ::align-specifier
         :right-bracket #{\]}))

(s/def ::between-bracket-expr
  (s/cat :between-char
         (s/* (s/and char? (complement #{\[ \]})))))

(s/def ::layout-exprs
  (s/cat :le
         (s/* (s/alt :br ::bracket-expr :be ::between-bracket-expr))))
would result in:
(s/explain ::layout-exprs [\a \b])
StackOverflowError   clojure.core/complement/fn--6675 (core.clj:1438)


improvements to the specs also welcome, I can for example see that I could remove the (s/and char? in the first one


all of ::align-specifier, ::bracket-expr and ::between-bracket-expr work in isolation


as in I can run explain and valid? on them and they behave as I would expect


ah...complement...maybe I need to be explicit there instead...


I did feel a bit woozy writing (complement #{\[ \}}) : )


@mbjarland Looks like you're running into an infinite left recursion because ::between-bracket-expr may not consume any input


@dergutemoritz ok, I will have to marinate on that a bit. Thanks for the pointer


Or perhaps not 😄


food for marination


and yes, changing (s/* to (/s+ in :between-bracket-expr fixes the problem. It probably should have been + to begin with


and so I'm lost in the woods again...and not for the first time with spec : ) If I write standalone specs I can run explain/valid?/exercise etc on them. What if I spec a function, do I have to actually instrument the function to test my spec or is there a way to get hold of the function spec and run the normal spec-exercising-functions on it?


I guess I can do a s/def on say the args spec and then exercise that separately...


yes, you can call s/get-spec on the fully-qualified symbol to get the function spec, and the function spec supports keyword lookups for it’s parts (`:args`, etc).


@alexmiller ok, nice and data centric as usual. thank you


(s/fdef user/foo :args (s/cat :a int?))
(s/valid? (:args (s/get-spec 'user/foo)) [100])


or you can go the other way and define the args spec as a standalone spec and then assemble the fdef spec from it (I’ve done this in some cases)


that's what I ended up with, but still good to know it's not a black hole and you have access to the function spec


I find my biggest hurdle with spec so far is not understanding the language but understanding its place in the process and best practice use. Is there for example still a place for using specs as preconditions in functions? I guess it would be nice to see an example of a larger production system using spec (or a similarily reality checked code base) and what kind of usage patterns they ended up with. Any references to presentations or repos with such code base much appreciated....


Is there any way to use coll-of or every (or some other existing capability in spec short of writing custom predicates and generators) to spec non-Clojure collections, like java.util.HashSet? I feel pretty certain the answer would be "no", but just want to double-check before reinventing any wheels.


@dave.dixon Since most (all?) Java collections are seqable, you should be able to make it work by anding in a seq conformer


@dergutemoritz thanks. Looks like even every works if you specify :kind to be a custom predicate, but still doesn't generate. And just verified every-kv doesn't seem to work with :kind, and keys doesn't give any hooks for custom collections, as far as I can tell. Which seems sensible - can't support everything possible in the JVM with a single API.


@dave.dixon Oh, right, generation isn't covered by my suggestion either. Note what the doc string says about a custom :kind predicate, though: > :kind - a pred/spec that the collection type must satisfy, e.g. vector? (default nil) Note that if :kind is specified and :into is not, this pred must generate in order for every to generate.


Hm but I doubt that passing something like :into (HashSet.) will just work either 🙂


@dergutemoritz not documented, but the collection must also support the Clojure interface for supporting into.


Yeah, seems reasonable


I doubt that spec is of much use for mutable collection types


Actually, I want to use it for bifurcan collections.


covering Java colls was not really a goal of the spec coll preds


I can’t say we’ve really talked about it either way though. doesn’t seem like there’s any technical reason such a thing couldn’t exist. not sure if there are performance concerns in growing/shrinking non-persistent colls in generators.