/clavier

:heavy_check_mark: General purpose validation library for Common Lisp

Primary LanguageCommon LispMIT LicenseMIT

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))

For example, this is how to accept a blank object, but validate it if it isn't blank:

(defparameter *validator* (clavier:||
                                   (clavier:blank)
                                   (clavier:&& (clavier:is-a-string)
                                               (clavier:len :min 10)))
  "Allow a blank value. When non blank, validate.")

(funcall *validator* "")
;; =>
T
NIL

(funcall *validator* "asdfasdfasdf")
;; =>
T
NIL

(funcall *validator* "asdf")
;; =>
NIL
"Length of \"asdf\" is less than 10"

(funcall *validator* 2)
;; =>
NIL
"2 is not a string"

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 be 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:

This is the list of available validator classes and their shortcut function:

  • equal-to-validator (==)
  • not-equal-to-validator (~=)
  • blank-validator (blank)
  • not-blank-validator (not-blank)
  • true-validator (is-true)
  • false-validator (is-false)
  • type-validator (is-a type)
  • string-validator (is-a-string)
  • boolean-validator (is-a-boolean)
  • integer-validator (is-an-integer)
  • symbol-validator (is-a-symbol)
  • keyword-validator (is-a-keyword)
  • list-validator (is-a-list)
  • function-validator (fn function message)
  • email-validator (valid-email)
  • regex-validator (matches-regex regex-pattern)
  • url-validator (valid-url)
  • datetime-validator (valid-datetime)
  • pathname-validator (valid-pathname)
  • not-validator (~ validator)
  • and-validator (&& validator1 validator2)
  • or-validator (|| validator1 validator2)
  • one-of-validator (one-of options)
  • less-than-validator (less-than number)
  • greater-than-validator (greater-than number)
  • length-validator (len)