Last active
December 11, 2015 01:58
-
-
Save ohpauleez/4527256 to your computer and use it in GitHub Desktop.
An example of specifications-as-a-value.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns sterling.specs-example | |
(:require [clojure.core.specs :as spec])) | |
(comment | |
;; A preview of some Specifications. | |
;; Out of the box, a single spec can be used with: | |
;; test.generative, core.contracts, Typed Clojure, and Sterling (an interface to Alloy) | |
;; You're also free to extend the system however you need. | |
;; Here is an example of a simple specification. | |
;; Under the hood, specs are just maps. `raw-spec` just returns the map | |
(def inc-spec | |
(spec/raw-spec | |
inc | |
"A simple spec for non-negative inc" ; Optional docstring | |
'[^long x] | |
:constraints '[["The input is non-negative and always result in a positive number" | |
(not (neg? x)) => (pos? %)]])) | |
;; The map looks like this: | |
{:clojure.core.specs/type :defspec, | |
:clojure.core.specs/f #<core$inc clojure.core$inc@3970a4fb>, | |
:clojure.core.specs/args [x], | |
:clojure.core.specs/ext {:constraints [["The input is non-negative and always result in a positive number" (not (neg? x)) => (pos? %)]] | |
:typed [[Number -> Any]]}, | |
:clojure.core.specs/doc "A simple spec for non-negative inc"} | |
; You'll notice type information was added... | |
; Specifying type information is optional. It'll be used if supplied, | |
; otherwise core.specs will attempt match types based on :tag information | |
;; These next two are the same. | |
;; Testing distributions can be "enforced" and used a contracts/constraints | |
(spec/raw-spec | |
inc | |
"An inc that only works for inputs 0-49" | |
'[^{:uniform [0 49] :enforced true} x] | |
:constraints '[["The output will always be less than or equal to 50" | |
(=> (<= % 50))]] | |
:typed '[[Number -> Number]]) | |
(spec/raw-spec | |
inc | |
"An inc that only works for inputs 0-49" | |
'[^{:tag (uniform 0 49)} x] | |
:constraints '[["The input must be between 0-49" | |
;(and (>= x 0) (<= x 49)) | |
(spec/between 0 <= x <= 49)] | |
["The output will always be less than or equal to 50" | |
(=> (<= % 50))]] | |
:typed '[[Number -> Number]]) | |
;; The specs can be used like decorators, generating the constrained | |
;; forms of the function detailed in the spec. | |
;; The following generates a new function with the constraints and type | |
;; information added. | |
;; | |
;; (def constrained-fn (spec/with a-raw-spec :constraints :typed)) | |
;; Here is an example from our earlier spec... | |
(def pos-inc (spec/with inc-spec :constraints)) | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment