-
Notifications
You must be signed in to change notification settings - Fork 27
Differences from spec.alpha
Alex Miller edited this page Jan 21, 2019
·
20 revisions
An overview of the differences between spec.alpha and spec-alpha2.
- Specs created with spec or regex ops (
and
,or
,tuple
,cat
, etc) must now be only data (symbols, sets, keywords, and lists), no function objects
- As mentioned above, the spec API functions can no longer be invoked with things that evaluate to a function object, only with data that defines a spec.
- Symbols can't be used directly but can be quoted:
(s/conform 'int? 10)
- Anonymous functions can't be used directly but can be quoted:
(s/conform '#(> % 10) 100)
- Functions that return a spec object can be wrapped in an anonymous function and quoted:
(s/conform '#((seqable-of int?) %) [100])
- Symbols can't be used directly but can be quoted:
The new s/spec*
functional entry point can be used to construct spec objects from spec forms without invoking the spec op macros or using eval:
(require '[clojure.spec-alpha2 :as s])
(defn or-of
"Make or spec where tags match names"
[& spec-names]
(let [tag-names (->> spec-names (map name) (map keyword))]
(s/spec* (cons `s/or (interleave tag-names spec-names)))))
(s/def ::a int?)
(s/def ::b keyword?)
(s/conform (or-of ::a ::b) 100)
;; [:a 100]
Custom spec ops can now be created and installed with a two-step process. First, create a spec op macro that explicates (fully-qualifies) a form and invokes the functional interface:
(defmacro my-spec
[& opts]
`(s/spec* '~(s/explicate (ns-name *ns*) `(my-spec ~@opts))))
Second, calls to spec*
get routed (via the spec name) to the multimethod create-spec
that actually creates the spec by reifying the Spec protocol:
(defmethod create-spec 'my-ns/my-spec
[[_ & opts]]
(reify Spec
...))