Skip to content

Commit 51df0d4

Browse files
committed
update spec guide for 1.9.0-alpha16
1 parent f4703cc commit 51df0d4

1 file changed

Lines changed: 39 additions & 35 deletions

File tree

content/guides/spec.adoc

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,28 @@ toc::[]
1111

1212
== Getting started
1313

14-
The <<xref/../../../about/spec#,spec>> library specifies the structure of data, validates or destructures it, and can generate data based on the spec. The https://clojure.github.io/clojure/branch-master/clojure.spec-api.html[clojure.spec] namespace is included in the Clojure core distribution, so no extra library is required to use it. You will need to declare a dependency on the latest alpha version of Clojure (or higher) however:
14+
The <<xref/../../../about/spec#,spec>> library specifies the structure of data, validates or destructures it, and can generate data based on the spec.
15+
16+
To use spec, declare a dependency on the latest alpha version of Clojure (or higher):
1517

1618
[source, clojure]
1719
----
18-
[org.clojure/clojure "1.9.0-alpha15"]
20+
[org.clojure/clojure "1.9.0-alpha16"]
1921
----
2022

21-
To start working with spec, require the `clojure.spec` namespace at the REPL:
23+
To start working with spec, require the `clojure.spec.alpha` namespace at the REPL:
2224

2325
[source,clojure]
2426
----
25-
(require '[clojure.spec :as s])
27+
(require '[clojure.spec.alpha :as s])
2628
----
2729

2830
Or include spec in your namespace:
2931

3032
[source,clojure]
3133
----
3234
(ns my.ns
33-
(:require [clojure.spec :as s]))
35+
(:require [clojure.spec.alpha :as s]))
3436
----
3537

3638
== Predicates
@@ -45,9 +47,9 @@ Any existing Clojure function that takes a single argument and returns a truthy
4547
;;=> 1000
4648
----
4749

48-
The `conform` function takes something that can be a spec and a data value. Here we are passing a predicate which is implicitly converted into a spec. The return value is "conformed". Here, the conformed value is the same as the original value - we'll see later where that starts to deviate. If the value does not conform to the spec, the special value `:clojure.spec/invalid` is returned.
50+
The `conform` function takes something that can be a spec and a data value. Here we are passing a predicate which is implicitly converted into a spec. The return value is "conformed". Here, the conformed value is the same as the original value - we'll see later where that starts to deviate. If the value does not conform to the spec, the special value `:clojure.spec.alpha/invalid` is returned.
4951

50-
If you don't want to use the conformed value or check for `:clojure.spec/invalid`, the helper https://clojure.github.io/clojure/branch-master/clojure.spec-api.html#clojure.spec/valid?[`valid?`] can be used instead to return a boolean.
52+
If you don't want to use the conformed value or check for `:clojure.spec.alpha/invalid`, the helper https://clojure.github.io/clojure/branch-master/clojure.spec-api.html#clojure.spec/valid?[`valid?`] can be used instead to return a boolean.
5153

5254
[source,clojure]
5355
----
@@ -185,7 +187,7 @@ In addition to `explain`, you can use https://clojure.github.io/clojure/branch-m
185187
[source,clojure]
186188
----
187189
(s/explain-data ::name-or-id :foo)
188-
;;=> #:clojure.spec{
190+
;;=> #:clojure.spec.alpha{
189191
;; :problems ({:path [:name],
190192
;; :pred string?,
191193
;; :val :foo,
@@ -200,7 +202,7 @@ In addition to `explain`, you can use https://clojure.github.io/clojure/branch-m
200202

201203
[NOTE]
202204
====
203-
This result also demonstrates the new namespace map literal syntax added in 1.9.0-alpha8. Maps may be prefixed with `#:` or `#::` (for autoresolve) to specify a default namespace for all keys in the map. In this example, this is equivalent to `{:clojure.spec/problems ...}`
205+
This result also demonstrates the new namespace map literal syntax added in 1.9.0-alpha8. Maps may be prefixed with `#:` or `#::` (for autoresolve) to specify a default namespace for all keys in the map. In this example, this is equivalent to `{:clojure.spec.alpha/problems ...}`
204206
====
205207

206208
== Entity Maps
@@ -651,9 +653,9 @@ Another option is to use `s/assert` within your code to assert that a value sati
651653
(person-name 100)
652654
;; CompilerException clojure.lang.ExceptionInfo: Spec assertion failed
653655
;; val: 100 fails predicate: map?
654-
;; :clojure.spec/failure :assertion-failed
655-
;; #:clojure.spec{:problems [{:path [], :pred map?, :val 100, :via [], :in []}],
656-
;; :failure :assertion-failed}
656+
;; :clojure.spec.alpha/failure :assertion-failed
657+
;; #:clojure.spec.alpha{:problems [{:path [], :pred map?, :val 100, :via [], :in []}],
658+
;; :failure :assertion-failed}
657659
----
658660

659661
A deeper level of integration is to call conform and use the return value to destructure the input. This will be particularly useful for complex inputs with alternate options.
@@ -765,7 +767,7 @@ The Clojure macroexpander will look for and conform :args specs registered for m
765767
(declare 100)
766768
;; ExceptionInfo: Call to clojure.core/declare did not conform to spec:
767769
;; In: [0] val: 100 fails at: [:args :names] predicate: simple-symbol?
768-
;; :clojure.spec/args (100)
770+
;; :clojure.spec.alpha/args (100)
769771
----
770772

771773
Because macros are always checked during macro expansion, you do not need to call instrument for macro specs.
@@ -877,11 +879,11 @@ In Maven, declare your dependency as a test scope dependency:
877879
</project>
878880
----
879881

880-
In your code you also need to include the `clojure.spec.gen` namespace:
882+
In your code you also need to include the `clojure.spec.gen.alpha` namespace:
881883

882884
[source,clojure]
883885
----
884-
(require '[clojure.spec.gen :as gen])
886+
(require '[clojure.spec.gen.alpha :as gen])
885887
----
886888

887889
=== Sampling Generators
@@ -1026,7 +1028,7 @@ Building your own generator gives you the freedom to be either narrower and/or b
10261028
There are three ways to build up custom generators - in decreasing order of preference:
10271029

10281030
. Let spec create a generator based on a predicate/spec
1029-
. Create your own generator from the tools in clojure.spec.gen
1031+
. Create your own generator from the tools in clojure.spec.gen.alpha
10301032
. Use test.check or other test.check compatible libraries (like https://github.com/gfredericks/test.chuck[test.chuck])
10311033

10321034
[WARNING]
@@ -1067,11 +1069,11 @@ Note that `with-gen` (and other places that take a custom generator) take a no-a
10671069

10681070
One downside to this approach is we are missing what property testing is really good at: automatically generating data across a wide search space to find unexpected problems.
10691071

1070-
The clojure.spec.gen namespace has a number of functions for generator "primitives" as well as "combinators" for combining them into more complicated generators.
1072+
The clojure.spec.gen.alpha namespace has a number of functions for generator "primitives" as well as "combinators" for combining them into more complicated generators.
10711073

10721074
[NOTE]
10731075
====
1074-
Nearly all of the functions in the clojure.spec.gen namespace are merely wrappers that dynamically load functions of the same name in test.check. You should refer to the documentation for https://clojure.github.io/test.check/[test.check] for more details on how all of the clojure.spec.gen generator functions work.
1076+
Nearly all of the functions in the clojure.spec.gen.alpha namespace are merely wrappers that dynamically load functions of the same name in test.check. You should refer to the documentation for https://clojure.github.io/test.check/[test.check] for more details on how all of the clojure.spec.gen.alpha generator functions work.
10751077
====
10761078

10771079
In this case we want our keyword to have open names but fixed namespaces. There are many ways to accomplish this but one of the simplest is to use https://clojure.github.io/clojure/branch-master/clojure.spec-api.html#clojure.spec.gen/fmap[`fmap`] to build up a keyword based on generated strings:
@@ -1151,15 +1153,15 @@ Finally, https://clojure.github.io/clojure/branch-master/clojure.spec-api.html#c
11511153
;;=> (-1.0 -1.0 -1.5 1.25 -0.5 -1.0 -3.125 -1.5625 1.25 -0.390625)
11521154
----
11531155

1154-
To learn more about generators, read the test.check https://clojure.github.io/test.check/intro.html[tutorial] or https://clojure.github.io/test.check/generator-examples.html[examples]. Do keep in mind that while clojure.spec.gen is a large subset of clojure.test.check.generators, not everything is included.
1156+
To learn more about generators, read the test.check https://clojure.github.io/test.check/intro.html[tutorial] or https://clojure.github.io/test.check/generator-examples.html[examples]. Do keep in mind that while clojure.spec.gen.alpha is a large subset of clojure.test.check.generators, not everything is included.
11551157

11561158
== Instrumentation and Testing
11571159

1158-
spec provides a set of development and testing functionality in the `clojure.spec.test` namespace, which we can include with:
1160+
spec provides a set of development and testing functionality in the `clojure.spec.test.alpha` namespace, which we can include with:
11591161

11601162
[source,clojure]
11611163
----
1162-
(require '[clojure.spec.test :as stest])
1164+
(require '[clojure.spec.test.alpha :as stest])
11631165
----
11641166

11651167
=== Instrumentation
@@ -1178,9 +1180,11 @@ Instrument takes a fully-qualified symbol so we use `pass:[`]` here to resolve i
11781180
(ranged-rand 8 5)
11791181
CompilerException clojure.lang.ExceptionInfo: Call to #'spec.examples.guide/ranged-rand did not conform to spec:
11801182
val: {:start 8, :end 5} fails at: [:args] predicate: (< (:start %) (:end %))
1181-
:clojure.spec/args (8 5)
1182-
:clojure.spec/failure :instrument-check-failed
1183-
#:clojure.spec{:problems [{:path [:args], :pred (< (:start %) (:end %)), :val {:start 8, :end 5}, :via [], :in []}], :args (8 5), :failure :instrument-check-failed}
1183+
:clojure.spec.alpha/args (8 5)
1184+
:clojure.spec.alpha/failure :instrument-check-failed
1185+
#:clojure.spec.alpha{:problems [{:path [:args], :pred (< (:start %) (:end %)), :val {:start 8, :end 5}, :via [], :in []}],
1186+
:args (8 5),
1187+
:failure :instrument-check-failed}
11841188
----
11851189

11861190
The error fails in the second args predicate that checks `(< start end)`. Note that the `:ret` and `:fn` specs are not checked with instrumentation as validating the implementation should occur at testing time.
@@ -1189,16 +1193,16 @@ Instrumentation can be turned off using the complementary function `unstrument`.
11891193

11901194
=== Testing
11911195

1192-
We mentioned earlier that `clojure.spec.test` provides tools for automatically testing functions. When functions have specs, we can use https://clojure.github.io/clojure/branch-master/clojure.spec-api.html#clojure.spec.test/check[`check`], to automatically generate tests that check the function using the specs.
1196+
We mentioned earlier that `clojure.spec.test.alpha` provides tools for automatically testing functions. When functions have specs, we can use https://clojure.github.io/clojure/branch-master/clojure.spec-api.html#clojure.spec.test/check[`check`], to automatically generate tests that check the function using the specs.
11931197

11941198
`check` will generate arguments based on the `:args` spec for a function, invoke the function, and check that the `:ret` and `:fn` specs were satisfied.
11951199

11961200
[source,clojure]
11971201
----
1198-
(require '[clojure.spec.test :as stest])
1202+
(require '[clojure.spec.test.alpha :as stest])
11991203
12001204
(stest/check `ranged-rand)
1201-
;;=> ({:spec #object[clojure.spec$fspec_impl$reify__13728 0x4a47e374 "clojure.spec$fspec_impl$reify__13728@4a47e374"],
1205+
;;=> ({:spec #object[clojure.spec.alpha$fspec_impl$reify__13728 ...],
12021206
;; :clojure.spec.test.check/ret {:result true, :num-tests 1000, :seed 1466805740290},
12031207
;; :sym spec.examples.guide/ranged-rand,
12041208
;; :result true})
@@ -1228,14 +1232,14 @@ This broken function will still create random integers, just not in the expected
12281232
;; (fn* [p1__3469#] (>= (:ret p1__3469#) (-> p1__3469# :args :start)))
12291233
;; (fn* [p1__3470#] (< (:ret p1__3470#) (-> p1__3470# :args :end))))),
12301234
;; :sym spec.examples.guide/ranged-rand,
1231-
;; :result {:clojure.spec/problems [{:path [:fn],
1232-
;; :pred (>= (:ret %) (-> % :args :start)),
1233-
;; :val {:args {:start -3, :end 0}, :ret -5},
1234-
;; :via [],
1235-
;; :in []}],
1236-
;; :clojure.spec.test/args (-3 0),
1237-
;; :clojure.spec.test/val {:args {:start -3, :end 0}, :ret -5},
1238-
;; :clojure.spec/failure :test-failed}}
1235+
;; :result {:clojure.spec.alpha/problems [{:path [:fn],
1236+
;; :pred (>= (:ret %) (-> % :args :start)),
1237+
;; :val {:args {:start -3, :end 0}, :ret -5},
1238+
;; :via [],
1239+
;; :in []}],
1240+
;; :clojure.spec.test.alpha/args (-3 0),
1241+
;; :clojure.spec.test.alpha/val {:args {:start -3, :end 0}, :ret -5},
1242+
;; :clojure.spec.alpha/failure :test-failed}}
12391243
----
12401244

12411245
`check` has reported an error in the `:fn` spec. We can see the arguments passed were -3 and 0 and the return value was -5, which is out of the expected range.

0 commit comments

Comments
 (0)