This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-07-02
Channels
- # aleph (1)
- # architecture (4)
- # beginners (39)
- # boot (12)
- # cider (25)
- # cljs-dev (3)
- # cljsrn (5)
- # clojure (175)
- # clojure-dusseldorf (1)
- # clojure-italy (13)
- # clojure-nl (4)
- # clojure-russia (1)
- # clojure-spec (52)
- # clojure-uk (110)
- # clojurescript (35)
- # data-science (2)
- # datomic (61)
- # editors (8)
- # emacs (2)
- # fulcro (7)
- # graphql (15)
- # hoplon (1)
- # hyperfiddle (3)
- # jobs (4)
- # jobs-discuss (12)
- # juxt (2)
- # lein-figwheel (6)
- # leiningen (35)
- # off-topic (4)
- # onyx (5)
- # parinfer (1)
- # pedestal (63)
- # re-frame (38)
- # reitit (7)
- # ring-swagger (7)
- # rum (2)
- # shadow-cljs (27)
- # tools-deps (10)
- # uncomplicate (16)
s/gen allows you to override a specific generator?
I see, thanks!
I have a map where one of the namespaced keys ::foo
for example, in the whole program can be one of 3 values #{"foo" "bar" "baz"}
, but in one part of the program can only be #{"foo" "bar"}
because I've filtered out "baz". Is there a way of expressing this in spec? I've been looking around and I haven't found anything (might be morning brane and solved by more coffee, but I'm not sure)
Interesting… I think this is awkward because it’s expressing something that’s brittle and contrary to the growth ideals of spec?
i.e. saying “this set must have only these keys” is analogous to saying “this map must have these keys and no others”.
The solution with maps in this situation is often to use select-keys
in your function, so the function is robust to inputs with arbitrary other keys as it will ignore them.
Could the solution in your situation be to intersect the set-argument with #{"foo" "bar"}
so anything else is ignored?
hmm.. I hadn't thought about the growth ideals properly when thinking about this. It makes me think that the envelope should be very permissive and that I should create new maps for the payload with new specs going through the rest of the system. I think that is why I keep asking these questions as spec affords some forms and punishes others (for good reasons such as growth), but it can be difficult to see it all the time and design accordingly.
Yes, if you build specs where you find yourself trying to spec “and nothing else” you’ll struggle. Obviously I don’t really know what you’re doing, but your new ideas seem to make perfect sense from a general architectural perspective i.e. the transport layer of an architecture typically shouldn’t know about specifics of the application/content layer.
I often find if I'm struggling against one of the affordances of something in clojure it is because I'm not thinking about it very well. I think this might be one of those cases. Thx!
@U0525KG62 I have had that case as well though not for part of the program but rather for part of an api response. My approach was to split the set into the two possible solutions and then use s/or
and s/merge
to express the parts that are common and differentiate the other ones
that might sound too abstract so here is an example: https://github.com/hiposfer/kamal/blob/master/src/hiposfer/kamal/specs/directions.clj#L55
Depends on what you want out of it I think, and what those things mean in your code.
You can make ::filtered-foo
which is #{"foo" "bar"}
and ::foo
is now s/or
of ::filtered-foo
or #{"baz"}
.
Just avoid having ::foo
itself mean two different things depending on context, as that breaks specs being globally consistent
I basically have a lot of "type fields" and often filter down to particular types in certain parts of the system and would like to constrain things in those sections (esp things like generative testing)
You could also leave ::foo
as being #{"foo" "bar" "baz"}
and in specific places just say that ::foo.subset
is (s/and #(not= % "baz") ::foo)
yeah, it just means that the key has to change going through so any code that does work on the supertype wouldn't be pointing at the right key.
it just makes an envelope and payload style tricky to do (as payload might have loads of types)
so this is tricky to model in spec then
{::id <some uuid>
::timestamp <some timestamp>
::payload <a number of different things that are maps that vary depending on domain>}
isn’t this the use case for a multi-spec
on ::payload
?
if you want to be able to constrain ::payload
later as you are only dealing with one of the domains.
Well, you can either have ::domain-1/payload
, ::domain-2/payload
and so on, or you could spec ::payload
with s/or
, conform it and check if the conformed value is the branch you expected
do keep in mind that I'm no clojure.spec expert, just brainstorming a bit :man-shrugging:
Well, you can use namespaced variants of :xxx/payload
and still define it as :req-un
-- that way you can see which version you're working with -- and still just use :payload
in the map.
I'm not sure I understand you @seancorfield. Does that give me the ability to say "this bit of code here only works with this domain of what might go in payload rather than all the domains"
You can have multiple specs with the same set of (unqualified) keys -- but each spec can use different definitions for those keys by using different qualified versions of a key.
(s/keys :req-un [:foo/bar])
and (s/keys :req-un [:quux/bar])
-- the actual map has :bar
in both cases but the specs are distinct.
cool. That was what I thought. That you could basically redefine what the *un*qualified keys meant where you wanted, but that you couldn't do that with qualified keys in a map. I didn't know about the :req-un
sugar you had their tho (or had forgotten)
>That you could basically redefine what the *un*qualified keys meant where you wanted, Just wasn’t sure what u meant here
Much existing Clojure code does not use maps with namespaced keys and so keys can also specify :req-un and :opt-un for required and optional unqualified keys. These variants specify namespaced keys used to find their specification, but the map only checks for the unqualified version of the keys.
hmm.. I hadn't thought about the growth ideals properly when thinking about this. It makes me think that the envelope should be very permissive and that I should create new maps for the payload with new specs going through the rest of the system. I think that is why I keep asking these questions as spec affords some forms and punishes others (for good reasons such as growth), but it can be difficult to see it all the time and design accordingly.