This library provides spec-backed forms of defn
, defprotocol
, fn
, let
etc. using the same exact syntax as clojure.core's.
That way, you can strengthen your defns with custom specs (expressed as metadata), while avoiding the hassle of instrumentation, and gaining some extra benefits, such as better performance, error reporting, etc.
[com.nedap.staffing-solutions/speced.def "1.1.0-alpha4"]
Note that self-hosted ClojureScript (e.g. Lumo) is unsupported at the moment.
In JVM Clojure, set *assert*
to false
.
In ClojureScript, set :elide-asserts
to true
.
clojure-future-spec
incompatibilityIf your project happens to depend (directly or transitively; try e.g. lein deps :tree
) on clojure-future-spec, this library will fail to load.
You can fix that by adding e.g. :exclusions [clojure-future-spec]
to whatever dependency was bringing it in.
You also will need to create an empty clojure.future
ns.
With speced.def
, one expresses specs via metadata:
(spec/def ::int int?)
;; You can pass functions, keywords, or (primitive) type hints indifferently, as metadata:
(speced/defn ^string? inc-and-serialize [^::int n, ^boolean b]
(-> n inc str))
...the snippet above compiles to something akin to:
;; note that both preconditions and type hints are emitted, derived from the specs
(defn inc-and-serialize ^String [n, ^boolean b]
{:pre [(int? n) (boolean? b)]
:post [(string? %)]}
(-> n inc str))
Expound is used for error reporting, so the actual emitted code is a bit more substantial.
You can pass specs as part of any nested destructurings.
(speced/defn destructuring-example [{:keys [^string? a] :as ^::thing all}]
;; :pre conditions will be emitted for `a` and `all`
)
speced.def's philosophy is to bypass instrumentation altogether. Clojure's precondition system is simple and reliable, and can be cleanly toggled for dev/prod environments via the clojure.core/*assert*
variable.
In a future, we might provide a way to build your own
defn
, tweaking subjective aspects like instrumentation, while preserving all other features at no cost.
defn
s^Boolean x
is analog to ^boolean? x
^::speced/nilable ^Boolean x
if something can be nil.^string?
will emit a ^String
type hint^string?
-> ^string
speced/defprotocol
, speced/fn
, speced/let
, speced/letfn
are also offered
speced/defn
speced/def-with-doc
: clojure.spec.alpha/def
with a docstring
speced/doc
, along with the spec itselfThere are exactly 2 namespaces meant for public consumption:
nedap.speced.def
: 'speced' forms of defprotocol, defn, fn, let, letfn, etc.nedap.speced.def.doc
: a public docstring registry for specs. Can be queried from arbitrary tools, and particularly REBL.They are deliberately thin so you can browse them comfortably.
Please browse the public namespaces, which are documented, speced and tested.
It is part of this library's philosophy to avoid creating external documentation. We believe specs, particularly with our def-with-doc
helper, can suffice, preventing duplication/drift and non-speced/non-self-documenting code.
That assumes that adopters are willing to jump to the source (particularly to the public parts, and occasionally to the tests which serve as a large corpus of examples), and preferrably have handy tooling that is able to do such jumping.
Copyright © Nedap
This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which is available at http://www.eclipse.org/legal/epl-2.0.
Can you improve this documentation? These fine people already did:
vemv, Jeroen de Jong & jwkoelewijnEdit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close