Skip to content

Latest commit

 

History

History
148 lines (107 loc) · 4.57 KB

README.md

File metadata and controls

148 lines (107 loc) · 4.57 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.2.0.

deps.edn JAR dependency information:

  org.typedclojure/typed.clj.spec {:mvn/version "1.2.0"}

deps.edn Git dependency information:

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

Leiningen dependency information:

[org.typedclojure/typed.clj.spec "1.2.0"]

Maven dependency information:

<dependency>
  <groupId>org.typedclojure</groupId>
  <artifactId>typed.clj.spec</artifactId>
  <version>1.2.0</version>
</dependency>

Documentation

API Reference

License

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

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