Input/output cases and field-table defaults for functions, written next to the function:
(defmeta f {:doc "What f returns." :inout-tests [[{} 1] ; in/out cases: one [in expected] pair each, [{:k 2} 2]]}) ; in = f's one argument
(defn-typed f {:k [:int {:default 1}]} -> :any ; the input map's rows, a default in its type's props
...k...) ; every row key is a local of the same name
defmeta (above f) expands to (declare f) + the registration of its cases and keys, and leaves
its map for the defn-typed below, which puts :doc and the other keys into f's attr-map.
defn-typed turns the input map into [:map …] and expands to (def f-props [:map …]),
(defn f--positional [k] ...) and (defn f {:malli/schema [:=> [:cat f-props] :any]} [m]
(let [{:keys [k] :or {k 1}} m] (f--positional k))); every call site goes through expand-call.
The macro marks a row with a default :optional: instrumentation checks the call before the
defaults are filled. Callers require both unprefixed: (:require [defn-typed.core :refer [defn-typed defmeta]]).
A defmeta case passes iff (= expected (f in)). The legacy sources, tests and an attr-map
{:inout-tests [[[args…] expected] …]}, keep [[args…] expected] pairs, (= expected (apply f args));
registered cases win. Works in clj and cljs; this namespace never loads malli: :malli/schema
is plain var metadata until a dev/test/REPL loader runs malli.instrument collect! + instrument!.
check-var / check-ns return data (any REPL, including the browser runtime);deftests! (clj) defines one clojure.test test per such var so run-tests and CI see them;test-var! (clj) runs a var's :test fn and its cases under one clojure.test report.Input/output cases and field-table defaults for functions, written next to the function:
(defmeta f
{:doc "What f returns."
:inout-tests [[{} 1] ; in/out cases: one [in expected] pair each,
[{:k 2} 2]]}) ; in = f's one argument
(defn-typed f
{:k [:int {:default 1}]} -> :any ; the input map's rows, a default in its type's props
...k...) ; every row key is a local of the same name
`defmeta` (above f) expands to (declare f) + the registration of its cases and keys, and leaves
its map for the defn-typed below, which puts :doc and the other keys into f's attr-map.
`defn-typed` turns the input map into [:map …] and expands to (def f-props [:map …]),
(defn f--positional [k] ...) and (defn f {:malli/schema [:=> [:cat f-props] :any]} [m]
(let [{:keys [k] :or {k 1}} m] (f--positional k))); every call site goes through expand-call.
The macro marks a row with a default `:optional`: instrumentation checks the call before the
defaults are filled. Callers require both unprefixed: (:require [defn-typed.core :refer [defn-typed defmeta]]).
A defmeta case passes iff (= expected (f in)). The legacy sources, `tests` and an attr-map
`{:inout-tests [[[args…] expected] …]}`, keep [[args…] expected] pairs, (= expected (apply f args));
registered cases win. Works in clj and cljs; this namespace never loads malli: `:malli/schema`
is plain var metadata until a dev/test/REPL loader runs malli.instrument collect! + instrument!.
- `check-var` / `check-ns` return data (any REPL, including the browser runtime);
- `deftests!` (clj) defines one clojure.test test per such var so run-tests and CI see them;
- `test-var!` (clj) runs a var's `:test` fn and its cases under one clojure.test report.cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |