This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-10-17
Channels
- # 100-days-of-code (5)
- # announcements (13)
- # beginners (98)
- # boot (19)
- # cider (10)
- # cljdoc (32)
- # clojure (142)
- # clojure-dev (37)
- # clojure-italy (3)
- # clojure-nl (2)
- # clojure-spec (30)
- # clojure-uk (18)
- # clojurescript (28)
- # cursive (8)
- # datomic (25)
- # duct (18)
- # editors (5)
- # emacs (39)
- # events (4)
- # figwheel (7)
- # figwheel-main (5)
- # fulcro (38)
- # graphql (19)
- # jobs-discuss (1)
- # jobs-rus (7)
- # keechma (1)
- # lumo (47)
- # off-topic (28)
- # om-next (3)
- # parinfer (3)
- # re-frame (18)
- # reagent (37)
- # reitit (8)
- # shadow-cljs (101)
- # specter (7)
- # tools-deps (8)
- # vim (1)
Hi, Is there a way to make s/cat
to generate vector instead of list (other than using s/with-gen
) ?
No, and that is a known issue
Is there any way I can define a generator for a spec like this?
(s/def ::hello #(isa? % :im/base))
(it has to pick from the descendants at the point when the generator is called, not at the point where the spec/generator is defined)
Hi - I’m pretty new to clojure, I’m playing around with spec and ran into some trouble:
I’m trying to spec a Person that has a last-contacted
key and I’m using clj-time
, such that I expect the field last-contacted
to be a DateTimeZone. I’m running into problems though and I’m not sure how I’m supposed to be using the spec from their library (or generally the best way to proceed.
### Thought 1:
I’d like to access the ::date-time
spec defined in clj-time.spec
since my understanding is specs are “registered globally”
Unfortunately, it appears I can’t access it. Trying to (s/exercise ::date-time)
yields and “Unable to resolve spec” error and qualifying it like (s/exercise clj-time.spec/::date-time)
gives a parse error
Question: How do I use specs defined in libraries?
### Thought 2:
If the above did work, how could I even use it with spec/keys
. From what I can tell, the name of the spec has to match the name of the key. eg:
(s/def ::person (s/keys :req [::name, ::date-time]))
Question: Is there syntax for doing something like the following invented code:
(s/def ::person (s/keys :req [::name, [:last-contacted ::date-time]]))
where a key with a different name gets a spec run on it?
So if you see the use of ::key in some library’s namespace “com.foo”, you need to use :com.foo/key. You will also need to require com.foo so that the ns is evaluated and the specs are registered
re: #1 you just need a slightly different syntax: :clj-time.spec/date-time
, or if you've aliased clj-time.spec e.g. [clj-time.spec :as ts]
then you could do ::ts/date-time
re: #2 yes the name of the spec must match the name of the key, however you can alias the original spec to whatever name you like e.g. (s/def ::my-date-time :clj-time.spec/date-time)
where would be the best place to expand a bit on a question from yesterday? i have a somewhat longer scenario id like to get some input on, but dont want to spam the channel. is there an active mailing list for spec?
I wouldn't worry about spamming the channel :man-shrugging: There's clojureverse, stack overflow (code review section?), there's a google group/mailing list for Clojure but not sure if there's a spec-specific one
This seems like an easy one: how do I specify the :args
for this fn when I do s/fdef
?
(defn demo [opts & [label]]
{:opts opts
:label label})
I’ve got this:
(s/def :key/a string?)
(s/def :key/b boolean?)
(s/def :key/c vector?)
(s/def :demo/label string?)
(s/fdef demo
:args (s/cat :opts (s/keys :req [:key/a]
:opt [:key/b :key/c])
:label (s/? :demo/label))
:ret map?)
which seems to pass:
(s/explain (s/get-spec 'demo) '(demo {:key/a "foo"}))
;; ==> Success!
but when I instrument it and try to run it, it blows up.
(demo {:key/a "foo"})
;; #error {:message "Call to #'cljs.user/demo did not conform to spec:\nIn: [0] val: ([:key/a \"foo\"]) fails at: [:args] predicate: (cat :opts (? :demo/opts) :label (? :demo/label)), Extra input\n:cljs.spec.alpha/spec #object[cljs.spec.alpha.t_cljs$spec$alpha38378]\n:cljs.spec.alpha/value {:key/a \"foo\"}\n:cljs.spec.alpha/args {:key/a \"foo\"}\n:cljs.spec.alpha/failure :instrument\n", :data {:cljs.spec.alpha/problems [{:path [:args], :reason "Extra input", :pred (cljs.spec.alpha/cat :opts (cljs.spec.alpha/? :demo/opts) :label (cljs.spec.alpha/? :demo/label)), :val ([:key/a "foo"]), :via [], :in [0]}], :cljs.spec.alpha/spec #object[cljs.spec.alpha.t_cljs$spec$alpha38378], :cljs.spec.alpha/value {:key/a "foo"}, :cljs.spec.alpha/args {:key/a "foo"}, :cljs.spec.alpha/failure :instrument}}
;; Error: Call to #'cljs.user/demo did not conform to spec:
;; In: [0] val: ([:key/a "foo"]) fails at: [:args] predicate: (cat :opts (? :demo/opts) :label (? :demo/label)), Extra input
;; :cljs.spec.alpha/spec #object[cljs.spec.alpha.t_cljs$spec$alpha38378]
;; :cljs.spec.alpha/value {:key/a "foo"}
;; :cljs.spec.alpha/args {:key/a "foo"}
;; :cljs.spec.alpha/failure :instrument
here's another take:
(s/fdef demo
:args (s/cat :opts (s/keys :req [:key/a]
:opt [:key/b :key/c])
:rest (s/? (s/cat :label :demo/label)))
:ret map?)
Ok, I get
app:cljs.user=> (demo {:key/a "foo"})
#error {:message "Call to #'cljs.user/demo did not conform to spec:\nIn: [0] val: [:key/a \"foo\"] fails at: [:args :opts] predicate: map?\n:cljs.spec.alpha/spec #object[cljs.spec.alpha.t_cljs$spec$alpha38378]\n:cljs.spec.alpha/value {:key/a \"foo\"}\n:cljs.spec.alpha/args {:key/a \"foo\"}\n:cljs.spec.alpha/failure :instrument\n", :data {:cljs.spec.alpha/problems [{:path [:args :opts], :pred map?, :val [:key/a "foo"], :via [], :in [0]}], :cljs.spec.alpha/spec #object[cljs.spec.alpha.t_cljs$spec$alpha38378], :cljs.spec.alpha/value {:key/a "foo"}, :cljs.spec.alpha/args {:key/a "foo"}, :cljs.spec.alpha/failure :instrument}}
Error: Call to #'cljs.user/demo did not conform to spec:
In: [0] val: [:key/a "foo"] fails at: [:args :opts] predicate: map?
:cljs.spec.alpha/spec #object[cljs.spec.alpha.t_cljs$spec$alpha38378]
:cljs.spec.alpha/value {:key/a "foo"}
:cljs.spec.alpha/args {:key/a "foo"}
:cljs.spec.alpha/failure :instrument
wait, for some reason you just made me think of the caveat about nested specs, I wonder if that’s it…
Nope, no joy in Specville
I should mention this is CLJS-specific — seems to work ok in CLJ
hmm yeah I tested in CLJ and it works, and I feel like I've seen a JIRA ticket for this issue or similar for CLJS
finally got around to posting a longer question on SO. hopefully it makes sense, but let me know how it could be improved for clarity and whatnot, or if im just missing basic concepts here. in any case its been a fun (s/)exercise https://stackoverflow.com/questions/52862471/using-clojure-spec-to-decompose-a-map
@taylor epic response! really appreciate it. i had played with using a separate s/def
for the keys, but i kept going down a path where i was trying to use multi-specs there, too, to no avail. i think ill ultimately use something like the get-spec-keys
way. the eval isn’t something i had thought about but thats a cool one too. thanks again man!
pretty amped about how this turned out. ended up dispatching using s/or
, and it will work with arbitrarily merged multi-specs (as long as the s/keys
are defined by the convention you suggested, which im ok with, since this is sort of a hack anyway). but its pretty sweet. it works pretty much just like select-keys
i.e.
(select-keys-spec m ::many-level-merged-spec)