This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-09-09
Channels
- # announcements (10)
- # aws (7)
- # babashka (28)
- # babashka-sci-dev (53)
- # beginners (11)
- # clojure (43)
- # clojure-europe (100)
- # clojure-morsels (1)
- # clojure-nl (2)
- # clojure-norway (6)
- # clojure-russia (2)
- # clojure-spec (13)
- # clojure-uk (7)
- # clojurescript (13)
- # conjure (21)
- # datalevin (3)
- # emacs (46)
- # etaoin (4)
- # events (2)
- # fulcro (36)
- # graphql (7)
- # gratitude (1)
- # interceptors (13)
- # jobs-discuss (3)
- # kaocha (13)
- # membrane (3)
- # minecraft (2)
- # nbb (8)
- # off-topic (135)
- # pathom (30)
- # podcasts-discuss (1)
- # re-frame (24)
- # releases (1)
- # shadow-cljs (26)
- # sql (16)
- # squint (6)
- # tools-deps (4)
- # xtdb (8)
What's the easiest way to do something like a "soft cut" e.g. core logic conda
to lock a regex spec into validating an optional argument with a specific spec if it meets some condition, and failing otherwise?
Suppose I have a spec like this:
(s/def ::my-map
(s/keys :opt-un [...]))
(s/def ::my-spec
(s/cat :my-map (s/? ::my-map) :options (s/* (s/cat :k keyword? :v any?))))
If I pass in a map that fails the ::my-map
spec I get an error like
identity - failed: Extra input in: [0] spec: ::my-spec
because it then tries to use that argument as an option. How can I force it to validate maps with the ::my-map
spec?
I've tried stuff like (s/& map? ::my-map)
but that doesn't work eitherjust checking - you have an optional followed by kv pairs, and with what input do you get this error? something that's neither a map or keyword as first arg?
I'm not sure if there's an easy alternative for you - seems like you could possibly treat this as two specs based on even/odd arg count. it's an unusual usage but you could probably build an s/multi that switched based on that and used different specs
I ended up doing something like
(s/&
(s/cat :my-map (s/? map?) :options (s/* (s/cat :k keyword? :v any?)))
(s/keys :opt-un [:my-map])
which works okay I guess but is a little icky I thinkHere's a more detailed example including something with neither a map nor keyword first arg. I just get an extra input error
(s/def ::k
integer?)
(s/def ::my-map
(s/keys :req-un [::k]))
(s/def ::my-spec
(s/cat :my-map (s/? ::my-map) :options (s/* (s/cat :k keyword? :v any?))))
(s/explain-str ::my-spec [{:k 100}])
(s/explain-str ::my-spec [{:k 100} :x :y])
;; => "Success!\n"
(s/explain-str ::my-spec [100])
;; => "(100) - failed: Extra input in: [0] spec: ::my-spec\n"
(s/explain-str ::my-spec [{}])
;; => "({}) - failed: Extra input in: [0] spec: ::my-spec\n"
defmulti
is actually one real-world example of where you have a usage like this. The metadata attribute map is optional and after that it supports dispatch-fn
as a positional argument and then a few optional key-value arguments like :default
and :hierarchy
if I recall correctly.
This came up for me because I was working on a def
macro that did something similar (supports and optional attribute map and keyword options) and I tried to tweak the spec to validate one of the keys in the attribute map specifically and it made things fail with confusing errors. In the example above I want the last failure to tell me it's failing because :k
is not an integer?
This is the working version I came up with:
(s/def ::my-spec
(s/& (s/cat :my-map (s/? map?) :options (s/* (s/cat :k keyword? :v any?)))
(s/keys :opt-un [::my-map])))
(s/explain-str ::my-spec [{}])
=> "{} - failed: (contains? % :k) in: [:my-map] at: [:my-map] spec: ::my-map\n"
I was wondering if maybe there was some easier way to do this, e.g. some way to define my so-called "soft cut" inline rather than having to wrap the whole thing in s/&
If I were to start using Spec today is it recommended to use Spec 1 or Spec 2? Also, my codebase is Clojure 1.8 and can't upgrade. The only issue I see with this is that ident?
is missing but that's easy enough to add. Is there any strong reasons to avoid using Spec with Clojure versions before 1.9?
spec 2 has not been released and is not under active dev at this moment
I think someone did have a backport of spec at one point (we are not maintaining anything official though)