This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-01-20
Channels
- # announcements (1)
- # beginners (48)
- # cljdoc (6)
- # cljs-dev (1)
- # cljsjs (1)
- # clojure (13)
- # clojure-dev (6)
- # clojure-estonia (1)
- # clojure-europe (1)
- # clojure-finland (8)
- # clojure-gamedev (3)
- # clojure-spec (35)
- # clojure-uk (25)
- # clojurescript (9)
- # datascript (1)
- # datomic (18)
- # figwheel-main (2)
- # fulcro (5)
- # graphql (1)
- # jobs (16)
- # off-topic (76)
- # pathom (39)
- # re-frame (6)
- # reagent (7)
- # remote-jobs (6)
- # rum (3)
- # shadow-cljs (54)
- # spacemacs (8)
- # speculative (2)
- # yada (72)
@misha thanks for this solution. I did that in a way for something a bit different and the problem I bumped into was that you cannot require the namespace containing the specs in another namespace and use it with a shortcut. Let's say the previous code was in a namespace a
.
(ns b
(:require [myapp.lib.a :as a]))
(s/valid? ::a/foo <whatever>)
(s/valid? :quz/resource <whatever>) <-- I have to remember that this comes from namespace myapp.lib.a
and doing this
(ns b)
(s/valid? :quz/resource <whatever>)
the dependency graph of spec definitions is not right and the compiler will complain (it happened to me and I spent time renaming a lot of specs)
Thus, even though I can do it, I tend to feel that it's a clumsy solution.Another question that comes to my mind, how can I validate a map whose keys are string (typically data from an HTML form).
Doing this (s/def ::form-data (s/keys :req ["foo" "bar"]))
is half of the spec. I'd like to qualify the content of the keys.
Again I feel like missing a syntax like this: (s/def ::form-data (s/keys :req [(s/key "foo" string?) (s/key "bar" int?)]))
.
i keep running into an issue with managing the complexity of my specs, and was wondering whether i'm "doing it all wrong". specifically, of quite a few specs, i need to have multiple variations of the same "schema", depending on the context. to give an example, a user should not need to have an ID before it is inserted into the database, but it does need an ID when it is. this is a simple example, but this pattern repeats. since ideally, i want my code to be able to declare whether it expects a a "stored user" or not, i currently compose these things as follows:
(s/def :user (s/keys ...))
(s/def :user/inserted (s/merge :user (s/keys ...))
on the surface this seemed like a good idea, but after a while of using this, i discovered downsides to this. most importantly: as soon as you have other specs that depend upon inserted users or not (e.g. a "company" vs "inserted company"), you repeat this pattern a lot, even when there is not necessarily a difference between a "company" and "inserted company".
as an alternative to this, i was thinking of making the state an explicit property i can multi-spec on. this makes the approach more data-driven. but then i wouldn't be able to directly say, "i expect an inserted user" in the code through specs anymore.
are there any alternatives to this ?
i hope my question is making a bit of sense 🙂this code is a good example: https://github.com/lagenorhynque/spec-examples/blob/master/specs/clj/spec_examples/geometry/specs.clj#L13
now, code cannot just fdef
anymore saying it expects a ::shape/cube
or a ::shape/sphere
, it can only fdef on ::shape
this is another discussion on the same topic => https://lispcast.com/reduce-complexity-with-variants/
@lmergen I think Rich Hickey has noticed that problem, too
he talked about it at the conj and hinted at a big change to spec to make this easier
basically, you define a map spec separately from the selection
which lets you separate out the definition of the entity from the context
awesome
i have faced this same problem myself
proliferation of specs because, for instance, if you have all the CRUD operations, they each require slightly different data
though you'd like to think of them as operating on the same entity
I think it’s most useful to think of it as oriented around value sets, as described by predicates
maps are composites of their attributes and the key is that semantics are derived from the attributes, not from the composite itself
not sure that’s the important bit
the new idea from Rich’s last keynote is that different functions can speak more precisely about which subset of the composite it cares about, and we can have better tools for describing what a function does with those inputs wrt to the output