https://github.com/mmontone/clavier.git
git clone 'https://github.com/mmontone/clavier.git'
(ql:quickload :clavier)
Clavier is a general purpose validation library for Common Lisp.
Download the source code from https://github.com/mmontone/clavier and point .asd system definition files from ./sbcl/system (ln -s <system definition file path>) and then evaluate:
(require :clavier)
from your lisp listener.
You will also need to satisfy these system dependencies:
alexandriacl-ppcrecloser-mopThe easiest way of installing those packages is via Quicklisp.
This library is under the MIT licence.
Validators are class instances that validate the arguments passed to the validate function:
(let ((validator (make-instance 'equal-to-validator :object 22)))
(validate validator 22 :error-p t))
;=> T
If the validator succeeds, the validate function returns T. If it fails, the validate function either signals a validation error, or returns NIL and a validation message depending on the value of the :error-p argument.
(let ((validator (make-instance 'equal-to-validator :object 22)))
(validate validator 33 :error-p nil))
;=>
;NIL
;"33 is not equal to 22"
Validators are implemented as funcallable classes. So, alternatively to using the validate function, it is possible to just funcall the validator, like this:
(let ((validator (make-instance 'equal-to-validator :object 22)))
(funcall validator 22 :error-p t))
;=> T
It is possible to create validators with a more convenient syntax. Each validator provides a builder function. For instance, and equal-to-validator can be built like this:
(funcall (== 100) 100) ;=> T
(funcall (== 100) 99) ;=> NIL
This allows to compose validators, using ==, ~=, &&, || as the composition operands:
(let ((validator (|| (&& (greater-than 20)
(less-than 30))
(|| (&& (greater-than 1)
(less-than 10))
(== 100)))))
(funcall validator 5))
Validators messages to be used when validation fails can be customized passing an :message argument when building the validator
Validation errors can controlled globally by setting the dynamic variable *signal-validation-errors*, which is NIL by default (no validation errors are signaled by default).
There's also the with-signal-validation-errors macro to specify whether validation errors should be signaled or not in a dynamic extent. For instance, this code signals a validation error:
(let ((validator (make-instance 'equal-to-validator :object 22)))
(with-signal-validation-errors (t)
(validate validator 33)))
Use the collecting-validation-errors macro to collect validation errors happening in a dynamic extent:
(let ((validator (make-instance 'equal-to-validator :object 22)))
(collecting-validation-errors (errors found-p)
(progn
(funcall validator 33 :error-p t)
(funcall validator 44 :error-p t))
(print errors)
(print found-p)))
;=>
;(#<VALIDATION-ERROR 44: 44 is not equal to 22 {1008A48673}>
; #<VALIDATION-ERROR 33: 33 is not equal to 22 {1008A47EA3}>)
;T