This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-11-14
Channels
- # beginners (33)
- # boot (38)
- # clara (21)
- # cljs-dev (1)
- # cljsjs (2)
- # cljsrn (12)
- # clojure (230)
- # clojure-argentina (1)
- # clojure-brasil (3)
- # clojure-dusseldorf (4)
- # clojure-france (9)
- # clojure-italy (1)
- # clojure-russia (123)
- # clojure-spec (46)
- # clojure-turkiye (1)
- # clojure-uk (60)
- # clojurescript (83)
- # core-async (6)
- # cursive (10)
- # datascript (19)
- # datomic (28)
- # defnpodcast (1)
- # emacs (7)
- # figwheel (7)
- # fulcro (29)
- # leiningen (29)
- # lumo (9)
- # off-topic (14)
- # om (1)
- # onyx (25)
- # pedestal (1)
- # protorepl (3)
- # re-frame (10)
- # reagent (41)
- # ring-swagger (11)
- # shadow-cljs (10)
- # testing (5)
- # unrepl (3)
- # vim (3)
(defn tag-is [t]
(fn [x]
(= (:tag x) t)))
;; ** vec2
(s/def ::x number?)
(s/def ::y number?)
(s/def ::vec2 (s/and (s/keys :req [::x ::y])
(tag-is ::vec2)))
;; ** bbox
(s/def ::x0 number?)
(s/def ::x1 number?)
(s/def ::y0 number?)
(s/def ::y1 number?)
(s/def ::bbox (s/and (s/keys :req [::x0 ::x1 ::y0 ::y1])
(tag-is ::bbox)))
(defn vec2-new [{:keys [x y]}]
{:tag ::vec2
::x x
::y y})
(defn bbox-new [{:keys [x0 x1 y0 y1]}]
{:tag ::bbox
::x0 x0
::x1 x1
::y0 y0
::y1 y1})
Am I using spec right nere? the vec2-new and bbox-new seem very UN-clojurish 'every is data' approach.
However, given that I'm using ::x ::y ::x0 ::y0 ... I don't know how else to nicely create vec2/bbox objectsmulti-spec
seems like it might better fit that use case https://clojure.org/guides/spec#_multi_spec
that would obviate the tag-is
thing. the *-new
fns at the bottom seem like they’re just converting map keys from unnamespaced to the current namespace, why not use the namespaced keys upstream?
@qqq In the upstream code, do you already have maps with unqualified keys? If so, where did they come from?
If you don't want the keys namespaced, change :req
to :req-un
(then bbox-new
becomes just (assoc data :tag ::bbox)
)
@seancorfield: all code is code I have written (and can change -- am rewriting with spec -- and trying to figure out best practices)
I actually think qualified makes more sense than unqialified, since a word may mean different things n different namesapces
@hiredman I did not know that, thanks!. Was it always the case that s/keys
checks other keys too? Where is this documented?
Meanwhile, I realized that another part of the solution for me is to use s/merge
. That way, the central spec needs to only about the existence of each module, not its behavior.
@deg It's documented here https://clojure.org/guides/spec#_entity_maps
Question: In general, do you find it’s better to define specs in the namespaces that use them? Or in a separate “appname.specs” namespace?
I think that the advantage of defining them in the namespaces where they are used is one of brevity.
For example, with nested data structures
#:longappname.specs{:a 1 :b 2}
this is less verbose than {:longappname.specs/a 1 :longappname.specs/b 2}
But the #:
syntax only applies to the top level of the map
So, I’m loading a config file that looks like this
and I’m trying to spec it
I know I can use (spec/keys :req-un …)
But I’d like to use namespaces
Anyway, all of the pieces of this config are currently in my appname.specs
namespace
When I load it and try to validate it, it fails, because all of my specs are namespaced
But I’d rather not have to put #:appname.specs
in front of each map in the config
So if I use the alias strategy like taylor said, I’d need to choose an arbitrary alias ahead of time that I would use in the config file, and that would need to match up with an alias that I would create in the namespace where I’m actually using and validating this config data.
Or, if I def
ed the specs in the namespace where the data will be loaded and used,
then I can just put a ::
in front of each of the keys and everything will work as intended
But am I going to get burned down the road if I have all of my spec definitions scattered throughout a bunch of namespaces instead of keeping them all in one location?
I guess I’d ask myself what problem am I solving by namespacing all the keywords in my config map
Okay, that’s a fair question taylor. I guess at this point it’s me still trying to learn the idiomatic way of doing spec as it was intended by its creators. And they seem to think that namespaced keywords are a beautiful thing. I’m still trying to figure out how they’re beautiful. 🙂
best practices
so I’m wondering if “best practices” here are, like you said, creating more problems
or if I’m just doing it wrong.
I use specs for maps with unnamespaced keywords all the time, personally. I don’t think there’s anything necessarily wrong with it
Anyway, the config is stored in edn format in a hand-edited file, loaded with edn/read-string
during app initialization
but then again most of the maps I work with are deserialized from some format that doesn’t support namespaces
and FWIW you could use any “made up” namespace for your config keywords, it doesn’t necessarily have to match a real namespace in your project
that’s an interesting idea
thanks for the discussion, taylor
I’ll probably just end up using :req-un
the hallmark of every great programmer