This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-04-25
Channels
- # aleph (6)
- # beginners (6)
- # boot (94)
- # cider (34)
- # cljs-dev (36)
- # cljsrn (12)
- # clojure (124)
- # clojure-dev (41)
- # clojure-dusseldorf (6)
- # clojure-italy (3)
- # clojure-norway (1)
- # clojure-russia (161)
- # clojure-sg (7)
- # clojure-spec (71)
- # clojure-uk (95)
- # clojurescript (38)
- # core-async (16)
- # cursive (14)
- # data-science (1)
- # datascript (12)
- # datomic (15)
- # emacs (22)
- # funcool (2)
- # hoplon (15)
- # jobs-rus (2)
- # juxt (9)
- # liberator (7)
- # lumo (1)
- # off-topic (136)
- # onyx (24)
- # pedestal (39)
- # perun (2)
- # planck (20)
- # re-frame (23)
- # spacemacs (31)
- # unrepl (5)
- # untangled (1)
- # vim (1)
- # yada (29)
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. https://clojure.org/guides/spec
Specs registered under namespaced keys give the keys global meaning thus are checked whenever they are encountered
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])
Success!
=> 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.
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
errr...I'm assuming "string regexen" refers to actual regular expression #" "
matching?
Hi everyone. How do you spec :args of any type? i.e. takes x that can be anything and returns for example boolean.
Ok, any?
🙂
thanks anyway
@adammunoz, I'm a beginner with spec but perhaps something like:
(defn some-fn [x]
true)
(s/fdef some-fn
:args (fn [_] true)
:ret boolean? )
->
(doc some-fn)
-------------------------
string-layout.core/some-fn
([x])
Spec
args: (fn [_] true)
ret: boolean?
@mbjarland Thanks. No I meant that predicate that I want is maybe any?
.
(any? 1) => true
(any? "whatever") =>true
@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 fdef
s) 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
@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
@mbjarland https://en.wikipedia.org/wiki/Left_recursion#Removing_left_recursion might help
Or perhaps not 😄
Bon appétit!
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?
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 and
ing 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.