This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-04-07
Channels
- # announcements (5)
- # asami (17)
- # aws (11)
- # babashka (67)
- # beginners (90)
- # calva (13)
- # cider (17)
- # circleci (6)
- # clj-kondo (3)
- # clojure (53)
- # clojure-europe (12)
- # clojure-france (8)
- # clojure-germany (3)
- # clojure-losangeles (1)
- # clojure-nl (4)
- # clojure-norway (4)
- # clojure-spec (15)
- # clojure-uk (8)
- # clojurescript (41)
- # cursive (7)
- # data-science (6)
- # datomic (8)
- # emacs (10)
- # exercism (1)
- # figwheel-main (2)
- # fulcro (5)
- # graalvm-mobile (97)
- # graphql (1)
- # hyperfiddle (7)
- # inf-clojure (6)
- # interop (4)
- # introduce-yourself (5)
- # jobs (3)
- # kaocha (3)
- # malli (8)
- # meander (8)
- # music (3)
- # nrepl (7)
- # observability (1)
- # off-topic (45)
- # overtone (2)
- # polylith (63)
- # portal (2)
- # re-frame (26)
- # reveal (8)
- # ring (3)
- # shadow-cljs (56)
- # tools-build (5)
- # vim (11)
- # xtdb (8)
I find I often have this scenario:
{:type :foo
:bar 1
:baz 2}
Where I want my spec to say that the keys are :type
, :bar
and :baz
, but also that the value of :type
must be :foo
. What's the most straightforward way to write that spec?
Bonus point where the generator for it properly constructs a map where :type
is always :foo
.have you looked at multi-spec?
seems like it would be a great match here
Multi-spec is actually where I have this problem, because the generator doesn't generate the correct :type
Like if we take the spec guide example: https://clojure.org/guides/spec#_multi_spec
Assume that instead of:
(s/def :event/type keyword?)
we have
(s/def :event/type #{:event/search :event/error})
If you try to generate an :event/event
, they won't be valid to any of the type of events most of the time, because the generator doesn't know which of the :event/type to pick for the different multi-specs
I'd like to write a spec for a clojure.data.xml data structure and use said spec for generation as well. For example, say I have something like this:
{:tag :foo
:content [{:tag :bar
:content ["..."]}]}
I'm not sure what the best way to do that would be, though. That is, how do I write (spec/def ::foo ,,,)
that specifies that :tag
needs to be :foo
and :content
must conform to the ::bar
spec, etc.
Is some combination of spec/keys
and spec/and
the way to go?It's been a while since I've used spec so this might be horribly wrong, but it might also solve both your problems 😃 🧵
Thank you! I'll give that a go. I tried flailing about with multi-spec
a bit, but I didn't think of the merge into a base element spec, that's clever. :thumbsup:
I tested this for at least two seconds, so caveat emptor 🙂
Actually, it's probably easier to write a spec for the Hiccup syntax using tuples and/or regexp ops.
(spec/def ::messageId
(spec/tuple #{:messageId} string?))
(spec/def ::from
(spec/tuple #{:from} string?))
(spec/def ::soap/Header
(spec/tuple #{::soap/Header}
::messageId
::from
;; etc
))
(spec/def ::soap/Envelope
(spec/tuple #{::soap/Envelope}
::soap/Header))
(->
(spec/gen ::soap/Envelope)
(gen/generate)
(xml/sexp-as-element)
(xml/emit-str)
(pretty-print-xml-string)
(println))
;;=>
<a:Envelope xmlns:a=" ">
<a:Header>
<messageId>I67NC7</messageId>
<from>733R0T1MGsY9cnx943</from>
</a:Header>
</a:Envelope>
@U0K064KQV the example I gave above might offer one way to use generators with multi-specs. but as I said, I'm no expert in this stuff so there may be better ways to do it