Skip to content

Latest commit

 

History

History
142 lines (103 loc) · 4.28 KB

README.md

File metadata and controls

142 lines (103 loc) · 4.28 KB

typed.clj/spec

Type-like specs.

Rationale

Higher-order functions often contain fine-grained dependencies between their arguments and return values. For example, the identity function requires its output to exactly match its input.

typed.clj/spec enhances the expressivity of spec by giving you the tools to specify such dependencies directly. This spec metalanguage treats these kinds of dependencies as first-class concepts, so you can specify and generatively test your favourite higher-order functions.

The aim of this library is to combine the expressive power of a type-like syntax with the pragmatism and versatility of spec. I'm really excited about the possibilities of bringing together the advantages of both worlds.

I hope you enjoy using typed.clj/spec!

Quickstart

Either:

  1. Add a dependency to typed.clj/spec using your favourite build tool (see Releases and Dependency Information).

  2. Clone this repository and run ./script/repl in the typed/clj.spec directory to follow along.

To use the generative testing features of typed.clj/spec, also add an explicit dependency to [org.clojure/test.check "1.0.0"] (automatic if cloning this repository).

;; require these namespaces
(require '[clojure.alpha.spec :as s]
         '[clojure.alpha.spec.gen :as gen]
         '[typed.clj.spec :as t])

;; start writing polymorphic specs
(s/def ::identity
  #_"Polymorphic type for clojure.core/identity"
  (t/all :binder (t/binder :x (t/bind-tv))
         :body
         (s/fspec :args (s/cat :x (t/tv :x))
                  :ret (t/tv :x))))

;; using normal spec functions to use validate them 
(assert (s/valid? ::identity identity))
(assert (s/valid? ::identity (comp first
                                   (juxt identity identity)
                                   (fn [x] x))))
(assert (not (s/valid? ::identity (fn [x] nil))))

;; start a repl from ./script/repl in this repo
;; and see tests for more interesting specs.
;; eg.,
(require '[typed-test.clj.spec.transducers :as x])

;; is (map inc) a transducer from integer? to integer? (yes)
(assert
  (binding [s/*fspec-iterations* 5]
    (s/valid? (t/tapp ::x/Transducer {:in integer?
                                      :out integer?})
              (map inc))))

;; is (map str) a transducer from integer? to symbol? (no)
(assert (not
          (s/valid? (t/tapp ::x/Transducer {:in integer?
                                            :out symbol?})
                    (map str))))

Tutorial

See doc/tutorial.md.

Examples

See tests for more examples:

Releases and Dependency Information

Latest stable release is 1.0.12.

deps.edn JAR dependency information:

  typed.clj/spec {:mvn/version "1.0.12"}

deps.edn Git dependency information:

  • Note: use clj -Sresolve to resolve the :tag to a :sha
  typed.clj/spec {:git/url "https://github.com/typedclojure/typedclojure"
                  :deps/root "typed/clj.spec"
                  :tag "1.0.12"}

Leiningen dependency information:

[typed.clj/spec "1.0.12"]

Maven dependency information:

<dependency>
  <groupId>typed.clj</groupId>
  <artifactId>spec</artifactId>
  <version>1.0.12</version>
</dependency>

License

Copyright © Ambrose Bonnaire-Sergeant, Rich Hickey & contributors.

Licensed under the EPL (see the file epl-v10.html).