This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-02-12
Channels
- # aws (3)
- # beginners (28)
- # boot (3)
- # cider (28)
- # clara (5)
- # cljs-dev (107)
- # cljsrn (1)
- # clojure (40)
- # clojure-austin (2)
- # clojure-brasil (5)
- # clojure-canada (1)
- # clojure-italy (1)
- # clojure-spec (39)
- # clojure-uk (38)
- # clojurescript (33)
- # community-development (11)
- # cursive (11)
- # datomic (43)
- # duct (6)
- # emacs (7)
- # flambo (1)
- # fulcro (68)
- # graphql (11)
- # jobs (1)
- # jobs-discuss (8)
- # leiningen (16)
- # luminus (2)
- # lumo (1)
- # off-topic (38)
- # om (2)
- # onyx (15)
- # parinfer (32)
- # portkey (5)
- # re-frame (50)
- # reagent (50)
- # reitit (1)
- # shadow-cljs (63)
- # spacemacs (10)
- # sql (27)
- # unrepl (6)
- # yada (2)
The URL in the sticky note of this channel seems broken : http://clojure.github.io/clojure/branch-master/clojure.spec-api.html
The correct URL may be https://clojure.github.io/spec.alpha/ ?
Yes, that last url is the correct one. Earlier, spec was in clojure and the prior one was correct
beginner question: Can we use spec to validate the correlation between values at different places in a structure?
For example, if I want to write a spec for [a b 1 5 ... 3 a b]
where a
and b
could be anything.
... supposing that the structure is complex enough so that I would need to use s/conform
to match the location of a
and b
at different places.
I could use a classical function to check if they match at different places, but I would like to know if there is a better spec-ish way to do it. Something like declaratively defining the pattern.
For example, something like: "For any a, b : [a b ... a b] is valid."
something like this?
(s/def ::my-coll
(s/* (s/alt :a-b (s/cat :a #{'a} :b #{'b})
:num number?)))
(s/conform ::my-coll ['a 'b 1 2 3 'a 'b])
Or if you wanted to require the coll always begin and end with a b
:
(s/def ::a-b (s/cat :a #{'a} :b #{'b}))
(s/def ::my-coll (s/cat :a-b-start ::a-b
:nums (s/* number?)
:a-b-end ::a-b))
Thank you. I will try it again later tonight.
Is there a way to manually conform function arguments before I call (apply myfn args)
? I.e. having
(spec/fdef myfn :args (spec/cat :userid ::userid))
how do I check that the args
I have conform to that? Thanks!
(I want to use this with expound
. I have command functions invoked from a Slack bot and want to verify that the command the user typed has all the correct arguments and show a nice error if not)wondering: why wasn't check-asserts based on a dynamic var like *compile-asserts*
? Right now it's a bit all or northing at runtime for assertion checking (for the one that are compiled at least)
all or nothing is kind of the typical modes for assertions
you can also grab the :args spec of a spec’ed function with
(-> `myfn s/get-spec :args)
I'm wondering if I can do any better if I want to have two different specs for the same key...
I have a generic auth-provider , e.g. #:auth-provider{:type "ldap" :config {:host "abc" ...}}
This has a generic spec :
(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]))
which is fine for some generic application code.
However, in some scenarios I want to act differently based on the type of the auth-provider.
E.g. for "ldap" I know that certain keys have to be present inside :auth-provider/config
.
I couldn't find a better solution than this:
(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
#(s/valid? ::ldap-config (:auth-provider/config %))))
My problem is that since specs are global I cannot register two different specs for the same key (`auth-provider/config`).
I also tried multi-spec
but couldn't solved it either.
My solution works but it's quite opaque - the error message just says that data fails ::ldap-config
spec (not that e.g. :host
key is missing in config map)look again at multi-spec, @jumar. it would be verbose solution, but sounds like it fits.
@U051HUZLD well, my problem was that I still couldn't define two different specs for :auth-provider/config
key. Basically, based on the value of :type
key I'd implement two multimethods - one for the :type
value "ldap" and one for :default
.
But in both of them I'd need to use something like (s/keys :req [:auth-provider/config])
- and here I'm stuck. I don't know how to define two different specs for :auth-provider/config
key.
if you put type inside config itself - multispecs will be about config keys, net provider's ones
or you can just s/or
the :provider/config, but it will not keep :provider/type and or's branches "in sync"
how do you guys spec a map where keys are generic and values are constant for a type? To give you an example, clojure.xml
will output something like {:tag :first_name, :attrs nil, :content ["John"]}
. How would I spec that I want my ::first-name
to have this structure? The keys
function would require me to make a spec for ::tag
but the value is constant for ::first-name
and at the same time, different in another spec, I can't globally specify ::tag
spec.
@roklenarcic I suspect you'll want a multi-spec for the various types of parsed maps you can get back from clojure.xml
(and the multi-spec would branch on the :tag
key's value)
I'll look into it.
There's something weird with the large-integer
generator. As is, it never generates a number over a 100. Even if I use the large-integer*
generator with options, the numbers are very low.
(gen/sample (gen/large-integer* {:min 1 :max 1000000}))
=> (2 2 1 4 1 1 9 1 2 15)
The test.check
generator clojure doc states:
(def ^{:added "0.9.0"} large-integer
"Generates a platform-native integer from the full available range
(in clj, 64-bit Longs, and in cljs, numbers between -(2^53 - 1) and
(2^53 - 1)).
Use large-integer* for more control."
(large-integer* {}))
But in my experience it generates number in about a -100 +100 range instead of 2^64hm... I guess I expected that generated numbers were uniformly distributed and so it would be extremely likely that a number over a 1000 was generated in 10 tries
@roklenarcic the large-integer generator exhibits growth just like most of the other generators
meaning it respects the size
parameter
gen/sample
with 1 arg gives you samples using sizes 0⇒9
I see, thank you
The reason I was worried is that when I use integer generator to generate ids, I get a lot of non-unique small numbers (because of the small initial range), which makes it very likely for a sequence of generated entities to have non-unique IDs, which causes such-that to fail occasionally, when IDs are specced to be unique.