This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-01-23
Channels
- # arachne (3)
- # aws (1)
- # bangalore-clj (2)
- # beginners (19)
- # boot (151)
- # cider (72)
- # cljs-dev (9)
- # cljsjs (7)
- # cljsrn (37)
- # clojure (215)
- # clojure-austin (1)
- # clojure-denmark (2)
- # clojure-dev (68)
- # clojure-india (1)
- # clojure-ireland (2)
- # clojure-italy (4)
- # clojure-mke (1)
- # clojure-nl (4)
- # clojure-russia (4)
- # clojure-serbia (1)
- # clojure-spec (29)
- # clojure-uk (23)
- # clojurescript (23)
- # cursive (24)
- # datomic (71)
- # emacs (5)
- # events (1)
- # gsoc (11)
- # hoplon (20)
- # klipse (4)
- # lambdaisland (2)
- # leiningen (3)
- # luminus (3)
- # off-topic (30)
- # om (40)
- # om-next (1)
- # onyx (15)
- # pedestal (19)
- # perun (7)
- # planck (23)
- # proton (1)
- # protorepl (2)
- # re-frame (35)
- # reagent (21)
- # ring-swagger (38)
- # rum (19)
- # spacemacs (9)
- # untangled (11)
- # vim (5)
- # yada (4)
Thanks @olivergeorge and @seancorfield . I was basing that off a comment of Timothy Baldridge on reddit that was suggesting that conformer was the way to go if one wanted to use a spec to coerce data
Well, yes, s/conformer
is the way to go -- but it's a "concern" to have a spec do data transformation.
sorry, there would also be (s/def ::myspecs (s/coll-of ::myspec :min-elements 1 :max-elements 5))
or something like that
But I can't think of a better way that doesn't have me re-implement half of spec for every branch of the tree
I'm not sure what you're asking -- and I think you're misunderstanding what we're saying...?
My actual use case is this: I have a service that 1) generates random data that conforms to a spec and spits it out as json 2) is supposed to take such a json map and check its conformance to the spec
the uuids have become strings, the enums (like the ::myspec) above as well, and so have the #inst datetimes
Here's an example of some specs etc we use that accept strings and coerce them to dates:
(defn coerce->date
"Given a string or date, produce a date, or throw an exception.
Low level utility used by spec predicates to accept either a
date or a string that can be converted to a date."
[s]
(if (instance? java.util.Date s)
s
(-> (tf/formatter t/utc "yyyy/MM/dd" "MM/dd/yyyy"
"EEE MMM dd HH:mm:ss zzz yyyy")
(tf/parse s)
(tc/to-date))))
(defn ->date
"Spec predicate: conform to Date else invalid."
[s]
(try (coerce->date s)
(catch Exception _ ::s/invalid)))
(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))))))
(s/def ::dateofbirth (api-spec ->date #(dt/format-date % "MM/dd/yyyy") inst?))
This accepts an instant or a string that will coerce to an instant. It auto-generates as well based on inst?
and converts it to a MM/dd/yyyy
string.
hey, thank you @seancorfield , that is super useful!
@brownmoose3q: Interesting… I’ve asked similar questions before, but never had any responses… I’m not sure if it’s because there isn’t an answer for it yet… I’d certainly like to know how to integrate clojure.spec with a clojure.test runner.
not sure what others do… but might be nice to have some clojure.test wrappers for tools like exercise etc...
obviously you can also use instrument
I just find out that lein test
is giving that wierdo error and refind-out for myself this issue: https://github.com/technomancy/leiningen/issues/2173
turned off monkeydispatch
and whoop - all is good.
So... seems to be a way of testing 🙂
Can anyone suggest how to simplify the following:
(s/def ::created inst?)
(s/def ::updated inst?)
(s/def ::foo* (s/keys :req-un [::created ::updated]))
(s/def ::foo
(s/with-gen ::foo*
#(gen/such-that (fn [{:keys [created updated]}]
(>= (.getTime updated) (.getTime created)))
(s/gen ::foo*))))
(s/exercise ::foo)
I would like to ditch ::foo*
, but if I reference the ::foo
generator from within s/def ::foo
, then understandably I get a SOEThere is option in s/keys
that fails/remove on unwanted keys??
(s/valid? (s/keys :req [:a/b]) {:a/b 0 :c/d 1}) ;=> false
or something like
(s/"filter????" (s/keys :req [:a/b]) {:a/b 0 :c/d 1}) ;=> {:a/b 0}
@souenzzo spec is designed to be open for extension — read the guide for more details.
If you want a spec to fail for unwanted keys, you need to explicitly s/and
a predicate that checks the set of keys in the map.
(but you probably shouldn’t do that)