Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
frenchy64 committed Nov 22, 2024
1 parent 0680cdd commit 19c6562
Show file tree
Hide file tree
Showing 27 changed files with 1,588 additions and 140 deletions.
62 changes: 49 additions & 13 deletions .github/workflows/clojure.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ on:

jobs:
build-clj:
timeout-minutes: 5

strategy:
matrix:
# Supported Java versions: LTS releases and latest
jdk: [8, 11, 17, 21]
clojure: [11]

name: Clojure ${{ matrix.clojure }} (Java ${{ matrix.jdk }})
name: Java ${{ matrix.jdk }}

runs-on: ubuntu-latest

Expand All @@ -26,23 +28,34 @@ jobs:
with:
distribution: zulu
java-version: ${{ matrix.jdk }}
- uses: actions/cache@v4
- uses: actions/cache/restore@v4
id: cache-restore
with:
path: |
~/.m2/repository
~/.gitlibs
key: ${{ runner.os }}-test-deps-${{ hashFiles('**/deps.edn') }}-${{ matrix.clojure }}-${{ matrix.jdk }}
key: ${{ runner.os }}-build-clj-${{ hashFiles('**/deps.edn') }}-${{ matrix.jdk }}
restore-keys: |
${{ runner.os }}-test-deps-${{ hashFiles('**/deps.edn') }}-${{ matrix.clojure }}-
${{ runner.os }}-test-deps-
${{ runner.os }}-build-clj-${{ hashFiles('**/deps.edn') }}-
${{ runner.os }}-build-clj-
- name: Setup Clojure
uses: DeLaGuardo/setup-clojure@master
with:
cli: latest
- name: Run tests
run: CLOJURE_ALIAS=clojure-${{ matrix.clojure }} bin/kaocha
run: bin/kaocha
- name: Always Save Cache
id: cache-save
if: always() && steps.cache-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
key: ${{ steps.cache-restore.outputs.cache-primary-key }}
path: |
~/.m2/repository
~/.gitlibs
build-cljs:
timeout-minutes: 5
name: ClojureScript
strategy:
matrix:
Expand All @@ -56,14 +69,15 @@ jobs:
with:
distribution: zulu
java-version: 11
- uses: actions/cache@v4
- uses: actions/cache/restore@v4
id: cache-restore
with:
path: |
~/.m2/repository
~/.gitlibs
key: ${{ runner.os }}-test-deps-${{ hashFiles('**/deps.edn') }}
key: ${{ runner.os }}-build-cljs-${{ hashFiles('**/deps.edn') }}
restore-keys: |
${{ runner.os }}-test-deps-
${{ runner.os }}-build-cljs-
- name: Setup Clojure
uses: DeLaGuardo/setup-clojure@master
with:
Expand All @@ -72,12 +86,23 @@ jobs:
uses: actions/setup-node@v4.0.3
with:
node-version: 16
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run tests on ${{ matrix.mode }}
run: bin/node ${{ matrix.mode }}
- name: Always Save Cache
id: cache-save
if: always() && steps.cache-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
key: ${{ steps.cache-restore.outputs.cache-primary-key }}
path: |
~/.m2/repository
~/.gitlibs
build-bb:
timeout-minutes: 5
name: Babashka

runs-on: ubuntu-latest
Expand All @@ -88,20 +113,31 @@ jobs:
with:
distribution: zulu
java-version: 11
- uses: actions/cache@v4
- uses: actions/cache/restore@v4
id: cache-restore
with:
path: |
~/.m2/repository
~/.deps.clj
~/.gitlibs
key: ${{ runner.os }}-test-deps-${{ hashFiles('**/deps.edn') }}-${{ hashFiles('**/bb.edn') }}
key: ${{ runner.os }}-build-bb-${{ hashFiles('**/deps.edn') }}-${{ hashFiles('**/bb.edn') }}
restore-keys: |
${{ runner.os }}-test-deps-${{ hashFiles('**/deps.edn') }}-
${{ runner.os }}-test-deps-
${{ runner.os }}-build-bb-${{ hashFiles('**/deps.edn') }}-
${{ runner.os }}-build-bb-
- name: Setup Clojure
uses: DeLaGuardo/setup-clojure@master
with:
cli: latest
bb: latest
- name: Run tests
run: bb test-bb
- name: Always Save Cache
id: cache-save
if: always() && steps.cache-restore.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
key: ${{ steps.cache-restore.outputs.cache-primary-key }}
path: |
~/.m2/repository
~/.deps.clj
~/.gitlibs
2 changes: 1 addition & 1 deletion bin/kaocha
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
#!/usr/bin/env bash
# Should work if the env var is empty
clojure -A:$CLOJURE_ALIAS -M:test -m kaocha.runner "$@"
clojure -M:test -m kaocha.runner "$@"
8 changes: 6 additions & 2 deletions deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
org.clojure/test.check {:mvn/version "1.1.1"}
;; pretty errors, optional deps
fipp/fipp {:mvn/version "0.6.26"}
mvxcvi/arrangement {:mvn/version "2.1.0"}}
:aliases {:test {:extra-paths ["test"]
mvxcvi/arrangement {:mvn/version "2.1.0"}
;; for constrained schema generators
org.clojure/math.combinatorics {:mvn/version "0.1.6"}}
:aliases {:test {:extra-paths ["test"
;;remove me
"dev"]
:extra-deps {com.gfredericks/test.chuck {:mvn/version "0.2.14"}
lambdaisland/kaocha {:mvn/version "1.91.1392"}
lambdaisland/kaocha-cljs {:mvn/version "1.5.154"}
Expand Down
1 change: 1 addition & 0 deletions dev/user.clj
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
[clojure.pprint :refer [pprint]]
[clojure.test :as test]
[clojure.tools.namespace.repl :as r]
malli.constraint
[clojure.walk :refer [macroexpand-all]]))

(r/set-refresh-dirs "src/malli" "dev" "test/malli")
Expand Down
67 changes: 67 additions & 0 deletions docs/constraints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Constraints

Typical nested schemas like `[:vector :string]` have corresponding
levels in the values they describe: the `:vector` for the outer
value and `:string for the first level of nesting.

The exceptions are composite schemas like `[:and :int [:< 42]]` which
describe the same value. This is problematic for generation: one
schema must generate values and the other filter them, yielding brittle
generators. Validators may also perform redundant checks, such has both
`:int` and `[:< 42]` needing to check the class of the validated value.

Constraints are intended to address this situation. A parent schema
has other "constraint" schemas attached to them which may collaborate
with the each other to yield reliable generators and lean validators.

For example, `[:int {:max 41}]` is actually two schemas (when constraints are enabled):
- the parent schema `:int`
- a constraint `[:max 41]`

## Reading this document

This document assumes this has been evaluated in the current namespace:

```clojure
(require '[malli.core :as m]
'[malli.constraint.protocols :as mcp]
'[malli.constraint :as mc])

(defn constraint-options []
(-> {:registry (m/default-schemas)}
mc/with-base-constraints))
```

## Activating Constraints

Constraints are an opt-in Malli feature.

To activate constraints locally, use `mc/with-base-constraints` to upgrade
your options map. You can see an example in `constraint-options` above.

To activate the base constraints globally, call `(malli.constraint/activate-base-constraints!)`.

Constraints are themselves Schemas that also live in the registry.

Behind the scenes, an atom `malli.constraint.extension/constraint-extensions`
is used to configure constraints. The entire atom is ignored if `::m/constraint-options`
WIPWIPWIP

TODO rename constraint-options? or the atom? default-constraint-options?


## Constraint vs Schema

A constraint implements the same protocols as a Schema, and additionally
`malli.constraint.protocols/Constraint`.

Schemas that support schemas also implement
`malli.constraint.protocols/ConstrainedSchema`.

Validators on schemas ensure they check preconditions

## Constraint Extensions Registry

Constraints schema represents

Constraint extensions are described as a schema in `malli.dev.constraint/ConstraintExtension`.
33 changes: 33 additions & 0 deletions src/malli/constraint.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
(ns malli.constraint)

#?(:cljs (goog-define mode "on")
:clj (def mode (or (System/getProperty "malli.constraint/mode") "on")))

(defprotocol Constraint
(-constraint? [this])
(-constraint-form [this]))

(defprotocol ConstrainedSchema
(-constrained-schema? [this])
(-get-constraint [this])
(-set-constraint [this c]))

(extend-type #?(:clj Object, :cljs default)
Constraint
(-constraint? [_] false)
(-intersect [_ _ _])

ConstrainedSchema
(-constrained-schema? [this] false)
(-get-constraint [this])
(-set-constraint [this c]))

(extend-type nil
Constraint
(-constraint? [_] false)
(-constraint-form [_])

ConstrainedSchema
(-constrained-schema? [this] false)
(-get-constraint [this])
(-set-constraint [this c]))
22 changes: 22 additions & 0 deletions src/malli/constraint/extension.cljc
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
(ns malli.constraint.extension)

#_
[:atom [:map
[:registry [:map-of Type IntoSchema]]
[:extensions [:map-of Type [:map
[:-walk
{:optional true}
[:=> [:maybe Schema] Schema Walker Path Constraint Options]]]]]]]
(defonce ^:private constraint-extensions (atom {}))

(defn get-constraint-extension [type]
(get-in @constraint-extensions [:extensions type]))

(defn get-constraint [type]
(get-in @constraint-extensions [:registry type]))

(defn register-constraints [reg]
(swap! constraint-extensions update :registry #(merge % reg)))

(defn register-constraint-extensions! [extensions]
(swap! constraint-extensions update :extensions #(merge-with into % extensions)))
Loading

0 comments on commit 19c6562

Please sign in to comment.