This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-12-13
Channels
- # adventofcode (77)
- # beginners (132)
- # boot (11)
- # cider (40)
- # clara (10)
- # cljsjs (1)
- # cljsrn (4)
- # clojure (148)
- # clojure-android (1)
- # clojure-greece (5)
- # clojure-italy (5)
- # clojure-nl (7)
- # clojure-spec (57)
- # clojure-uk (9)
- # clojurescript (115)
- # core-matrix (1)
- # cursive (3)
- # data-science (1)
- # datomic (1)
- # duct (7)
- # emacs (20)
- # fulcro (29)
- # funcool (4)
- # graphql (31)
- # instaparse (15)
- # java (1)
- # jobs (6)
- # jobs-discuss (95)
- # leiningen (2)
- # off-topic (30)
- # om (4)
- # onyx (7)
- # pedestal (6)
- # quil (4)
- # re-frame (52)
- # reagent (59)
- # rum (1)
- # spacemacs (3)
- # specter (61)
- # test-check (3)
hi, does anyone know how to diagnose the following error?
1. Unhandled java.lang.IllegalArgumentException
No implementation of method: :specize* of protocol:
#'clojure.spec.alpha/Specize found for class: nil
i found this but it seems only tangentially related: https://dev.clojure.org/jira/browse/CLJ-2032
here's the code:
(s/def ::json-primitive
(s/or :n nil :b boolean? :n number? :s string?))
(s/def ::json-structure
(s/with-gen
(let [checker (fn inner [primitives? v]
(cond
(map? v) (and (every? string? (keys v)) (every? (partial inner true) (vals v)))
(coll? v) (every? (partial inner true) v)
primitives? (s/valid? ::json-primitive v)
:else false))]
(partial checker false))
#(gen/recursive-gen (fn [inner] (gen/one-of [(gen/list inner) (gen/vector inner) (gen/map gen/string inner)]))
(s/gen ::json-primitive))))
(s/def ::validation-fn
(s/or :func (s/fspec :args (s/cat :x ::json-structure)
:ret boolean?)
:spec s/spec?))
(s/def ::message-fn
(s/fspec :args (s/cat :x ::json-structure)
:ret string?))
(defn- seq->gen
"Takes a sequence of generators and produces a generator of sequences."
[seq]
(apply gen/tuple seq))
(defn- map-seq->gen
"Takes a sequence of values and a function to apply over them
and produces a generator of the sequence of mapped values."
[f val-seq]
(seq->gen (map f val-seq)))
(s/def ::refinements
(s/with-gen
(s/map-of keyword? (s/tuple (s/nilable keyword?) (s/tuple ::validation-fn ::message-fn)))
#(gen/let [kwds (gen/vector gen/keyword 5 25)
refinements
(map-seq->gen
(fn [kwd]
(gen/let [k (gen/frequency [[4 (gen/elements (clojure.set/difference (set kwds) (set [kwd])))]
[1 (gen/return nil)]])
validation-fn (gen/frequency [[8 (gen/return (with-meta (fn [_] true) {:validates? true}))]
[1 (gen/return (with-meta (fn [_] false) {:validates? false}))]])
message-fn (gen/fmap (fn [s] (with-meta (fn [_] s) {:msg s})) (s/gen string?))]
[kwd [k [validation-fn message-fn]]]))
kwds)]
(into {} refinements))))
and the invocation:
(gen/sample (s/gen ::refinements) 1)
(s/def ::json-primitive (s/or :n nil 😛 boolean? :n number? :s string?))
should that be nil?
yes, this was in response to @johanatan
@lopalghost good catch! thx!
does anyone know a way for an fspec
to consider relations between its target's inputs? like if one of the parameters is functionally constrained by the value of the other one?
i could do it by stuffing the args into a nested vector:
(defn f [[a1 a2]] ...)
and then writing a spec/generator for that vector which combines two other [independent] spec/generators but i was kind of hoping that there is a better story for this...the :args
argument already treats the args as a sequence, so you can use (s/and ...)
to spec both individual inputs and relations between them
there's a good example in the spec guide: https://clojure.org/guides/spec#_spec_ing_functions
tuple is for a collection of fixed size. for variable size you want to use cat
eg
(s/cat :string ::string-not-blank :number pos-int?)
sorry, that should be
(s/cat :string ::string-not-blank :number (s/? pos-int?))
if you want the second term to be optional
in my case it’s a vactor, with one string and when have another thing its that int…
after you conform vector, you can use unform
to turn it back into a sequence
keep in mind you don't need to use conform
at all
the alternative would be something like:
(s/or :two (s/tuple ::string-not-blank)
:one (s/tuple ::string-not-blank pos-int?))
or otherwise, pad the vector with a nil before conforming, if it only has one element
I think cat
would be most idiomatic though
@lopalghost actually s/and
for that purpose will result in a such-that
and you can be at risk of a couldn't satisfy such-that predicate after 100 tries
error
there needs to be a way to generate the two values together so that we know the two will conform with one another
Hi. This is my first time using spec, and taking inspiration from clojure.core.specs.alpha, I decided to write my own version to parse/produce macro definitions. I wanted it to return something less detailed in a flatter hash and I wasn't happy with the fact results from conform
mirror the spec' structure and with other petty details, so this is what I came up with:
To which extent is this a misuse of this library ?
@johanatan not sure how a nested vector would solve the problem, as any spec you apply to the nested vector could also be applied to :args
@lopalghost it solves it by letting me introduce a generator specifically for that tuple
You can't do that with the :arts spec? Sorry if I'm misunderstanding you
:args*
e.g.,
(s/def ::args-tup
(s/with-gen
(s/tuple ::arg1 ::arg2)
#( ... enforce relations here )))
(s/fdef -refinement-kwd->validator
:args (s/cat :tup ::args-tup)
:ret ::ret-val)
(defn- -helper [[arg1 arg2]] ; tuple allows both inputs to be generated simult.
;; omitted
)
(defn- original [arg1 arg2]
(-helper [arg1 arg2]))
you can do it in :args
but you are liable to hit the cannot satisfy such-that
problem
I mean why not just use ::args-tup as the :args spec? Does that cause a problem? I'd try it out myself but I don't have a repl at the moment
ok I cobbled together a stupid example, let me know if this is relevant:
(s/def ::args-tup (s/and (s/tuple pos-int? pos-int?)
#(> (first %) (second %))))
(s/fdef subtract
:args ::args-tup
:ret pos-int?)
(defn subtract
[high low]
(- high low))
didn't supply a generator of course, but stest/check
works with no problems here
Would it be wise to spec no argument, if just for the metadata, if so, how would someone spec :args
for no args?
@lopalghost that use of s/and
has an implied underlying gen/such-that
which depending on circumstances may be impossible or too difficult to satisfy. thus it is always better to generate exactly the right structure you want from scratch rather than relying on such-that
.
@lopalghost also, your fdef
won't work: :args
is an alternating sequence of name
and type/spec
. thus you need s/cat