I know that you can pull the :ret
and :arg
spec from a function spec.
(def my-fn-spec
(s/fspec :args (s/cat :x int?)
:ret int?))
(s/valid? (:args my-fn-spec) [5]) ;; true
(s/valid? (:ret my-fn-spec) 5) ;; true
Is there a way to decompose/query other kinds of specs? For example, I would like to do something like the following to get the spec for the individual fn argument named x
.
(:x (:args my-fn-spec))
;; or maybe
(first (:args my-fn-spec))
I think the TL;DR is not easily with Spec 1 @erp12 but Spec 2 offers more facilities for taking specs apart and programmatically building them.
In Spec 1, you can get the form of a Spec and break it apart, but it isn't easy to turn that back into Spec objects that you can use tho'...
@seancorfield Good to know, thank you! Based on that, would you agree that currently the best option would be to keep the sub-specs in a map and use some utility functions to "materialize" real specs from them. Just spitballin' here but something like ...
(s/def ::spec (s/spec s/spec?))
; Deconstructed Function Spec
(s/def ::arg-specs (s/coll-of ::spec))
(s/def ::ret-spec ::spec)
(s/def ::d-fn-spec (s/keys :req [::arg-specs ::ret-spec]))
; Deconstructed Collection Spec
(s/def ::coll-kind ::spec)
(s/def ::element-spec ::spec)
(s/def ::d-coll-spec (s/keys :req [::coll-kind ::element-spec]))
; Deconstructed Map Spec
(s/def ::key-spec ::spec)
(s/def ::value-spec ::spec)
(s/def ::d-map-spec (s/keys :req [::key-spec ::value-spec]))
(defn construct-spec
[m]
...)
Or do you know of any other pattens followed by the community for stuff like this?
I don't really understand what problem you are trying to solve here... It doesn't look like the sort of thing I've seen anyone trying to do with Spec.
Have you looked at Spec 2? That's much more amenable to programmatic manipulation of specs...
Hi. I'm struggling with generating data from a simple (s/schema)
use case.
(s/def ::x int?)
(s/def ::baz (s/schema [::x]))
(s/def ::bar ::baz)
(s/def ::foo (s/schema [::bar]))
(gen/sample (s/gen (s/spec ::foo)))
The call to (gen/sample)
throws a No implementation of method: :conform* of protocol: #'clojure.alpha.spec.protocols/Spec found for class: clojure.lang.Keyword
exception.
While a straightforward translation to s/keys
seems to work fine:
(s/def ::x int?)
(s/def ::baz (s/keys :opt [::x]))
(s/def ::bar ::baz)
(s/def ::foo (s/keys :opt [::bar]))
(gen/sample (s/gen (s/spec ::foo)))
I'm probably getting something wrong in my schema definitions, but I can't figure out the problem.code looks fine, prob just a bug
in spec
Cool, I'll stick with the (s/keys ..)
version for a while.
Changing the :bar
definition to
(s/register ::bar (s/resolve-spec ::baz))
appears to work around the issue.that makes sense - you're basically copying the spec object rather than relying on resolving through the alias
I have a pretty good hunch on where that bug is
Awesome, thanks!