This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-11-17
Channels
- # aws (3)
- # beginners (81)
- # boot (155)
- # capetown (2)
- # cider (32)
- # clara (14)
- # cljs-dev (40)
- # cljsrn (12)
- # clojure (158)
- # clojure-austin (5)
- # clojure-korea (6)
- # clojure-poland (1)
- # clojure-russia (63)
- # clojure-spec (45)
- # clojure-uk (75)
- # clojurescript (109)
- # code-reviews (1)
- # core-logic (12)
- # core-matrix (1)
- # cursive (36)
- # datomic (16)
- # defnpodcast (1)
- # devcards (2)
- # editors (3)
- # euroclojure (1)
- # events (3)
- # flambo (1)
- # hoplon (19)
- # javascript (4)
- # jobs (1)
- # lein-figwheel (4)
- # leiningen (1)
- # off-topic (1)
- # om (177)
- # onyx (121)
- # pedestal (14)
- # planck (19)
- # proton (3)
- # re-frame (36)
- # reagent (21)
- # remote-jobs (1)
- # ring (4)
- # ring-swagger (6)
- # spacemacs (1)
- # specter (2)
- # test-check (4)
- # untangled (9)
- # utah-clojurians (1)
- # yada (2)
We’re slowly creating functions that turn explain data into a series of unique failure codes which we have as a documented part of our API. Our use case is essentially
(let [conformed (s/conform spec args)]
(if (s/invalid? conformed)
(render-failure (problems->failure-codes spec args))
(render-result conformed)))
@seancorfield is it possible to share what kind of code lies in the problems->failure-codes
?
Shoud (s/form (s/spec integer?))
return (clojure.spec/spec clojure.core/integer?)
? now it returns just clojure.core/integer?
That's a valid spec
So, looks right to me
@ikitommi: it walks the problems and maps path to a code if it non-empty else it maps pred to a code (and it special-cases (contains? % key)
which you get for a missing key from req/req-un.
@ikitommi That's to be expected, s/form
returns a data structure, not a spec. The clojure.core/integer?
you're seeing is just the symbol, not the var
@ikitommi Ah, alright, makes sense 🙂
Looks like s/form
is not injective!
This is also interesting:
(s/form integer?)
; => :clojure.spec/unknown
Why does this not work?
(def not-blank? (complement clojure.string/blank?))
(s/conform not-blank? "")
IllegalStateException Attempting to call unbound fn: #'dev/not-blank? clojure.lang.Var$Unbound.throwArity (Var.java:43)
I don't know.
@dergutemoritz: that's a known bug and will be fixed
@dergutemoritz: I've done some of the work on it, just needs a bit more input from rich
is there a way to do something similar to the removed clojure.spec.test/instrument-all
before running (but after compiling) tests with lein test
?
oh I guess I can use fixtures for this
@joost-diepenmaat (instrument-all)
was replaced with (instrument)
yes that works fine
you might want to unstrument
at the end
@alexmiller: yeah i thought so too
(defn with-instrument-all [t] (let [instrumented (stest/instrument)] (t) (stest/unstrument instrumented)))
That's what I'm using as fixture right now
try
/`finally`
that was my first thought too, but in theory deftest will catch any exceptions from tests, so the only exceptions could be from fixtures, but your other fixtures should already never bubble out exceptions, because fixtures have some odd edge cases when exceptions are allowed to bubble out
e.g. an external system returns strings containing integers and i use a conformer to parse them
Channeling Alex: it’s OK to do a type conversion in a spec if you’re OK with all clients of that spec getting the built-in type conversion 🙂
(but in general avoid conformers in specs)
FWIW, we have a bunch of specs that accept strings and conform them to non-strings, for use in a REST API.
We use this macro to wrap such specs:
(defmacro api-spec
"Given a coercion function and a predicate / spec, produce a
spec that accepts strings that can be coerced to a value that
satisfies the predicate / spec, and will also generate strings
that conform to the given spec."
[coerce str-or-spec & [spec]]
(let [[to-str spec] (if spec [str-or-spec spec] [str str-or-spec])]
`(s/with-gen (s/and (s/conformer ~coerce) ~spec)
(fn [] (g/fmap ~to-str (s/gen ~spec))))))
so you can say (s/def ::age (api-spec ->long (s/int-in 18 121)))
where ->long
is a conversion that produces ::s/invalid
if the conversion fails.This also allows (s/def ::yes-no (api-spec keyword name #{:yes :no}))