This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-05-03
Channels
- # beginners (111)
- # boot (1)
- # braveandtrue (4)
- # calva (2)
- # cider (16)
- # clara (35)
- # cljdoc (4)
- # cljs-dev (22)
- # clojure (80)
- # clojure-dev (17)
- # clojure-europe (3)
- # clojure-italy (57)
- # clojure-japan (1)
- # clojure-nl (4)
- # clojure-serbia (1)
- # clojure-spec (25)
- # clojure-uk (108)
- # clojurescript (67)
- # cursive (17)
- # data-science (5)
- # datascript (6)
- # datomic (6)
- # devcards (1)
- # events (1)
- # expound (13)
- # figwheel (2)
- # figwheel-main (6)
- # fulcro (7)
- # jobs-discuss (8)
- # kaocha (1)
- # luminus (3)
- # nrepl (6)
- # off-topic (58)
- # re-frame (1)
- # reitit (16)
- # remote-jobs (1)
- # ring (1)
- # shadow-cljs (70)
- # spacemacs (10)
- # sql (42)
- # testing (1)
- # tools-deps (8)
- # vim (1)
just trying out alpha2
for the first time and finding (s/or ...)
to be StackOverflowError
ing on everything i try. seems like im missing something pretty big but havent been able to piece it together—do the regex macros need to be used with s/spec*
?
is there a concise way of expressing something similar to s/or
where data that conforms to multiple predicates returns all of the matches instead of just the first? something similar to:
(s/def ::example (s/... :e even? :s #(< % 42))
(s/conform ::example 2) ;; => ([:e 2] [:s 2])
no, not really
I'm not sure how to approach this problem... I have multiple implementations of an "auth provider" (e.g. db, ldap, etc.) and they are represented as a namespaced map like this:
#:auth-provider{:active? true
:type "ldap"
:config {:port 636
:host ""
:bind-dn-format "uid={username},cn=users,cn=accounts,dc=demo1,dc=freeipa,dc=org"
:search-base "dc=demo1,dc=freeipa,dc=org"
:connection-timeout 10000
:response-timeout 10000
:ssl? true}}
The problem here is the :config
key. It's widely different across different implementations and I'd like to have different specs for that.
My problem is that AFAIK you can have only one spec for such a key - in my case that's fairly generic:
(s/def :auth-provider/config (s/map-of keyword? any?))
(s/def ::auth-provider-spec (s/keys :req [:auth-provider/type
:auth-provider/active?]
:opt [:auth-provider/id
:auth-provider/default-role
:auth-provider/config
:auth-provider/priority-order
:auth-provider/role-mapping]))
Now I want to "override" spec for the :auth-provider/config
key for each implemantation - currently I use this hacky approach:
(s/def ::ldap-config (s/keys :req-un [::host ::port ::connection-timeout ::response-timeout]
:opt-un [::bind-dn-format ::search-base]))
(s/def ::ldap-provider-spec (s/and
::auth-specs/auth-provider-spec
;; this is less descriptive than using `s/keys` directly
;; but we cannot use `s/keys` because `:auth-provider/config` default
;; spec is already registered in auth-specs namespace
;; and you cannot have two different specs for the same namespaced key (i.e. `:auth-provider/config`)
#(s/valid? ::ldap-config (:auth-provider/config %))))
But that's not only awkward it's also problematic from the "error reporting" point of view - in case something inside the :config
key is invalid I get pretty useless error message that the spec failed but I don't know why:
... Reason: Invalid LDAP configuration: -- Spec failed ---------
... Relevant specs ------- :auth.providers.ldap-provider/ldap-provider-spec: (clojure.spec.alpha/merge :auth.specs/auth-provider-spec (clojure.core/fn [%] (clojure.spec.alpha/valid? :auth.providers.ldap-provider/ldap-config (:auth-provider/config %)))) ------------------------- Detected 1 error
I tried merge
and multi-spec
(might not know how it should be used properly) but failed basically for the same reason - cannot define different specs for the key :auth-provider/config
Wonder if you could do something with the namespaces on the key? Like, instead of :auth-provider/config
for all the variants, have :auth-provider-ldap/config
, :auth-provider-db/config
, etc.
You’re in the ballpark of s/multi-spec - have you tried that?
As commented in the reply, I got stuck basically for the same reason (not able to define different specs for the same namespaced-key) - I might be doing it wrong, though.
roughly something like this:
(defmulti auth-specs/provider-type :auth-provider/type)
(defmethod auth-specs/provider-type "ldap" [_]
(s/keys :req [:auth-provider/config]))
one way would be to do this one level up - the map containing :auth-provider/config
or I find it's always helpful to come back to the truth of the matter - what values can a key take on? here :auth-provider/config has multiple sets of things
so spec it as s/or of different s/keys specs
(some of which might reuse the same attributes)
it looks like unform
is not aware of nonconforming
or am I doing sth wrong?
(s/def ::bar
(s/or :baz integer?))
(s/def ::foo
(s/nonconforming ; <========
(s/keys :req-un [::bar])))
(s/def ::tez
(s/tuple any? ::foo))
(s/conform ::tez [123 {:bar 4}])
; [123 {:bar 4}]
(s/unform ::tez [123 {:bar 4}])
; Error: nth not supported on this type function Number() { [native code] }
; at Function.
smaller example
(s/def ::bar
(s/or :baz integer?))
(s/def ::foo
(s/nonconforming
(s/keys :req-un [::bar])))
(s/conform ::foo {:bar 4})
(s/unform ::foo {:bar 4})
those both roundtrip fine for me w/o error
are you on cljs? or clj?