This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-10-24
Channels
- # announcements (1)
- # aws (2)
- # beginners (147)
- # boot (19)
- # cider (57)
- # clara (52)
- # cljdoc (18)
- # cljs-dev (14)
- # cljsrn (4)
- # clojure (176)
- # clojure-conj (9)
- # clojure-dev (9)
- # clojure-germany (2)
- # clojure-italy (4)
- # clojure-spec (13)
- # clojure-uk (56)
- # clojurescript (72)
- # code-reviews (11)
- # cursive (17)
- # data-science (1)
- # datomic (52)
- # duct (26)
- # emacs (6)
- # events (9)
- # figwheel (1)
- # figwheel-main (21)
- # fulcro (132)
- # funcool (1)
- # graphql (3)
- # jobs-discuss (42)
- # leiningen (3)
- # luminus (45)
- # mount (10)
- # off-topic (2)
- # re-frame (17)
- # reagent (12)
- # reitit (20)
- # ring-swagger (7)
- # rum (3)
- # shadow-cljs (256)
- # slack-help (15)
- # sql (7)
- # tools-deps (50)
- # uncomplicate (1)
- # yada (9)
(dotimes [_ 100]
(binding [s/*recursion-limit* 10]
(count (gen/sample (s/gen ::nested-associative) 100))))
=> nil
(dotimes [_ 100]
(binding [s/*recursion-limit* 1]
(count (gen/sample (s/gen ::nested-associative) 100))))
=>
CompilerException clojure.lang.ExceptionInfo: Unable to construct gen at: [:coll :branch :map 1 :branch] for: :scratch/nested-associative #:clojure.spec.alpha{:path [:coll :branch :map 1 :branch], :form :scratch/nested-associative, :failure :no-gen}
tried 10000 times, limit=9 threw in a ~20 seconds, limit=10 ran for minutes, had to kill it
so, you need to add non-recursive clause to s/or, so it can be chosen when recursion-limit is reached:
(s/def ::nested-associative
(s/or
:leaf string?
:coll (s/coll-of ,,,)
:map (s/map-of ,,,)))
@bmaddy I’m able to get that to reliably generate with s/*recursion-limit* 1
by pulling the recursive s/or
branch into its own spec:
(s/def ::branch
(s/or :leaf string?
:branch ::nested-associative))
(s/def ::nested-associative
(s/or :coll (s/coll-of ::branch
:min-count 0
:max-count 1
:gen-max 1)
:map (s/map-of keyword? ::branch
:min-count 0
:max-count 1
:gen-max 1)))
but I’m not sure why that is, maybe it’s the way that recursive depth is tracked internally and the “inline” recursive s/or
specs lose some context on recursion?(dotimes [_ 1000]
(binding [clojure.spec.alpha/*recursion-limit* 1]
(dorun (gen/sample (s/gen ::nested-associative) 100))))
Oh, I get it now. I'd tried setting s/*recursion-limit*
to a low number before to help avoid StackOverflow issues, but that's actually the problem here. When the recursion limit is hit, it must throw that error. Thanks @misha and @taylor!
Is there a strict validation mode in spec? Whereas if you provided more data then fail?
No; closed specs are generally discouraged. You can do your own strictness using s/and, however.
@basti spell-spec gives you options for either keeping the map open (but reporting likely misspelled keys) or complete closed maps (not recommended) https://github.com/bhauman/spell-spec