This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2016-10-13
Channels
- # beginners (14)
- # boot (108)
- # carry (6)
- # cider (28)
- # cljs-dev (107)
- # cljsrn (32)
- # clojars (4)
- # clojure (62)
- # clojure-austin (15)
- # clojure-berlin (1)
- # clojure-brasil (3)
- # clojure-chicago (1)
- # clojure-dev (9)
- # clojure-greece (2)
- # clojure-italy (4)
- # clojure-nl (1)
- # clojure-poland (2)
- # clojure-portugal (1)
- # clojure-russia (24)
- # clojure-spec (63)
- # clojure-uk (30)
- # clojurescript (123)
- # cursive (13)
- # data-science (1)
- # datascript (1)
- # datomic (27)
- # devcards (11)
- # dirac (1)
- # emacs (5)
- # events (4)
- # hoplon (27)
- # jobs (3)
- # juxt (3)
- # leiningen (11)
- # off-topic (18)
- # om (46)
- # om-next (7)
- # onyx (50)
- # pedestal (6)
- # portland-or (8)
- # proton (16)
- # re-frame (38)
- # reagent (21)
- # ring-swagger (14)
- # specter (46)
- # untangled (116)
- # vim (46)
- # yada (22)
@doglooksgood asserts aren't enabled by default. Try (s/check-asserts true)
.
https://clojure.github.io/clojure/branch-master/clojure.spec-api.html#clojure.spec/check-asserts
Is this a bug?
(def my-keys [:my.ns/some-key])
(s/def :my.ns/ok (s/keys :req-un ~my-keys))
;=> :my.ns/ok
(s/def :my.ns/not-ok (s/keys :opt-un ~my-keys))
; CompilerException java.lang.AssertionError: Assert failed: all keys must be namespace-qualified keywords
some specific behaviour for :opt-un
, I’ll try to dig further
After looking a bit further I fell into a macro trap. I guess at most it is inconsistent behaviour
This terrible hack does what I want
(defmacro dynamic-keys [& opts]
(let [args (mapcat (fn [[k v]]
[k v])
(partition 2 opts))]
`(eval (list `s/keys ~@args))))
Is there a better way?
what is the preferred convention for fdef specs, should they come before or after the function they spec?
@jeroenvandijk you could write a macro which emits my-keys
but your solution is fine, under given circumstances, I think it leads to more-readable code
instead of eval
you could use ns-resolve
and var-get
, if you expected just a symbol as arg, I think
@jeroenvandijk You don’t necessarily need macros. I’ve been using these to create specs dynamically:
ah yeah could just use eval, slightly better
Are there any examples of how to instrument with a :spec override? For example:
(defn foo [x] (inc x))
(s/def ::x clojure.future/pos-int?)
(s/fdef foo :args (s/cat :x ::x))
; Attempt #1
(stest/instrument `foo {:spec {`foo {:args (s/cat :x zero?)}}})
(foo 1)
=> 2
; Attempt #2
(stest/instrument `foo {:spec {::x zero?}})
(foo 1)
=> 2
I want to say that my function returns a vector of 1 or more jobs (a map) is this correct?
30 │ (s/def ::job (s/keys :req [::type ::meta]
31 │ :opt [::payload]))
32 │
33 │ (s/fdef sample-jobs
34 │ :args int?
35 │ :ret (s/+ ::job))
@clojuregeek I think you need to use (s/coll-of ...)
for :ret
hmm .. i would expect a better doc string?
kraken-consumer.job/sample-jobs
([] [x])
Spec
args: int?
ret: (every :kraken-consumer.job/job :clojure.spec/cpred #function[kraken-consumer.job/fn--12178] \
:clojure.spec/kind-form nil :clojure.spec/conform-all true)
Found the answer to my instrument with :spec
question above. Should be done like this:
(defn foo [x] (inc x))
(s/def ::x clojure.future/pos-int?)
(s/fdef foo :args (s/cat :x ::x))
(stest/instrument `foo {:spec {`foo (s/fspec :args (s/cat :x zero?))}})
(foo 1)
=>
ExceptionInfo Call to #'user/foo did not conform to spec:
In: [0] val: 1 fails at: [:args :x] predicate: zero?
:clojure.spec/args (1)
:clojure.spec/failure :instrument
:clojure.spec.test/caller {:file "form-init5306699344209214826.clj", :line 5, :var-scope user/eval24489}
clojure.core/ex-info (core.clj:4617)
using + has a decent doc string
175 │ kraken-consumer.job/sample-jobs
176 │ ([] [x])
177 │ Spec
178 │ args: int?
179 │ ret: (+ :kraken-consumer.job/job)
Is there a way to spec a sequential collection? s/coll-of
throws a massive error if you pass a map to it, as it tries to check each mapentry against a spec and displays a failure for each mapentry
I want my spec to be a sequence of values, each conforming to a spec
If I pass a map, then each mapentry gets evaluated against that spec instead
s/cat
is a good way of speccing sequences, but you’re probably already familiar with it so i hesitate to mention it
I thought about s/cat
but didn't think it was for this use case? I could be wrong though
if i’m reading this right, you’re passing in {a-map}, and not [{a-map}] - could that be the issue?
I know what the issue is, I'm saying that the spec error message telling me that wasn't very useful when I used s/coll-of
, so I was wondering if there was something else?
coll-of seems like what you want although I'm not entirely positive I understand what you're doing
I want my spec to be a sequential?
collection of ::request-maps
. I define ::request-map
, then create (s/def ::request-maps (s/coll-of ::request-map))
. If I pass "abc"
and check it against my spec, I get
{:cljs.spec/problems
[{:path [],
:pred coll?,
:val "abc",
:via [:day8.re-frame.http-fx/request-maps],
:in []}]}
as it fails on the coll?
predicate. This is a pretty easy to understand problem.
However if I check a single map against this spec, I get a very large error, because the map is treated as a sequence, and each MapEntry in the map is checked against (and fails) my spec ::request-map
.I can change my spec to (s/and sequential? (s/coll-of ::request-map))
but this seems like a fairly common use case, and wondered if there was another way to spec this more precisely?
That's a bit better, thanks. It short circuits earlier, but the error message is still not very illuminating:
{:cljs.spec/problems
[{:path [],
:pred map?,
:val [:method :post],
:via
[:day8.re-frame.http-fx/request-maps
:day8.re-frame.http-fx/request-maps
:day8.re-frame.http-fx/request-map
:day8.re-frame.http-fx/request-map],
:in [0]}]}
It still treats a map as a sequence of map entries
I think coll-of is the best match for what you are trying to say
Using s/* by itself without other regex ops is less good
As it conveys a sequential with more interesting internal structure
Does it make sense to include maps as valid coll-of
's?
They are a collection of tuples
And that's very useful
Is there scope to add a sequential-of?
or something similar?
No, you could use :kind though
:kind sequential?
That's wha I was after
You may also want :into []
Can't remember how it will conform without that
That might already be the default
I think so
That's used by gen too if you care about that so might double check that too
docs seem to suggest an :into is needed as well here, as I don't know if sequential?
can generate?