-
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 make-keys-spec [keys]
(s/spec* (list `s/keys :req (vec keys))))
(s/explain (make-keys-spec #{::a ::b}) {::a 1})
;; #:user{:a 1} - failed: (contains? % :user/b)
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
[[_ & opts]]
(reify Spec
...))