clavier

2023-02-15

Clavier: A Common Lisp validation library

Upstream URL

github.com/mmontone/clavier

Author

Mariano Montone

License

MIT
README

Clavier

Quicklisp MIT License

Clavier is a general purpose validation library for Common Lisp.

Install

Through Quicklisp:

(ql:quickload :clavier)

Getting started

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

Validation expressions

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

Validators composition

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

Validators messages to be used when validation fails can be customized passing an :message argument when building the validator

Catching and collecting validation errors

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 

Validators list:

  • equal-to-validator
  • not-equal-to-validator
  • blank-validator
  • not-blank-validator
  • true-validator
  • false-validator
  • type-validator
  • string-validator
  • boolean-validator
  • integer-validator
  • symbol-validator
  • keyword-validator
  • function-validator
  • email-validator
  • regex-validator
  • url-validator
  • not-validator
  • and-validator
  • or-validator
  • one-of-validator
  • less-than-validator
  • greater-than-validator
  • length-validator

Dependencies (6)

  • alexandria
  • chronicity
  • cl-fad
  • closer-mop
  • cl-ppcre
  • stefil
  • GitHub
  • Quicklisp