This is the sanity-clause Reference Manual, version 0.7.4, generated automatically by Declt version 4.0 beta 2 "William Riker" on Sun Sep 15 06:38:46 2024 GMT+0.
The main system appears first, followed by any subsystem dependency.
sanity-clause
Sanity clause is a data contract and validation library.
Matt Novenstern
LGPLv3
.. image:: https://github.com/fisxoj/sanity-clause/actions/workflows/test.yml/badge.svg
:target: https://travis-ci.org/fisxoj/sanity-clause
:alt: Github Actions CI status badge
.. image:: https://coveralls.io/repos/github/fisxoj/sanity-clause/badge.svg?branch=master
:target: https://coveralls.io/github/fisxoj/sanity-clause?branch=master
:alt: Coveralls status badge
.. image:: https://img.shields.io/badge/Contributor%20Covenant-v1.4%20adopted-ff69b4.svg
:alt: Contributor Covenant
:target: CODE_OF_CONDUCT.md
:Source: ‘https://github.com/fisxoj/sanity-clause <https://github.com/fisxoj/sanity-clause>‘_
:Docs: ‘https://fisxoj.github.io/sanity-clause/ <https://fisxoj.github.io/sanity-clause/>‘_
..
You can’t fool me. There ain’t no santy clause!
– Chico Marx
Sanity clause is a data validation/contract library. You might use it for configuration data, validating an api response, or documents from a datastore. In a dynamically typed language, it helps you define clearly defined areas of doubt and uncertainty. We should love our users, but we should never blindly trust their inputs.
To make use of it, you define schemas, which can be property lists with keys and instances of :class:‘sanity-clause.field:field‘ subclasses as values (eg. :class:‘sanity-clause.field:integer-field‘, :class:‘sanity-clause.field:string-field‘, &c.) or using the class-based interface via :class:‘sanity-clause.schema:validated-metaclass‘. For example::
(list :name (make-field :string) :age (make-field :integer))
You can load these sorts of schemas from a file by writing them as sexps with keywords, like this::
schema.sexp
(:key (:string :validator (:not-empty) :default "potato")
:key2 (:integer :validator ((:int :min 0)) :default 2))
and then loading them using :function:‘sanity-clause.loadable-schema:load-schema‘ to load them.
To use class-based schemas using :class:‘sanity-clause:validated-metaclass‘ you can do things like::
(defclass person ()
((favorite-dog :type symbol
:field-type :member
:members (:wedge :walter)
:required t)
(age :type (integer 0)
:required t)
(potato :type string
:required t))
(:metaclass sanity-clause:validated-metaclass))
which will validate their initargs when you instantiate them (**BUT NOT WHEN YOU SET SLOTS**). Hopefully, that will be added eventually, perhaps as an optional feature.
~~~~~~~
Example
~~~~~~~
“v2-info.json“::
{
"title": "Swagger Sample App",
"description": "This is a sample server Petstore server.",
"termsOfService": "http://swagger.io/terms/",
"contact": {
"name": "API Support",
"url": "http://www.swagger.io/support",
"email": "support@swagger.io"
},
"license": {
"name": "Apache 2.0",
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
},
"version": "1.0.1"
}
“example.lisp“::
;; load required libraries
(ql:quickload ’(jonathan sanity-clause))
(defclass contact-object ()
((name :type string
:data-key "name"
:documentation "The identifying name of the contact person/organization.")
(url :type string
:data-key "url"
:field-type :uri
:documentation "The URL pointing to the contact information. MUST be in the format of a URL.")
(email :type string
:data-key "email"
:field-type :email
:documentation "The email address of the contact person/organization. MUST be in the format of an email address."))
(:metaclass sanity-clause:validated-metaclass))
(defclass license-object ()
((name :type string
:data-key "name"
:documentation "The license name used for the API.")
(url :type string
:data-key "url"
:field-type :uri
:documentation "A URL to the license used for the API. MUST be in the format of a URL."))
(:metaclass sanity-clause:validated-metaclass))
(defclass info-object ()
((title :type string
:data-key "title"
:required t
:documentation "The title of the application.")
(description :type string
:data-key "description"
:documentation "A short description of the application. GFM syntax can be used for rich text representation.")
(terms-of-service :type string
:data-key "termsOfService"
:documentation "The Terms of Service for the API.")
(contact :type contact-object
:field-type :nested
:data-key "contact"
:element-type contact-object
:documentation "The contact information for the exposed API.")
(license :type license-object
:field-type :nested
:element-type license-object
:data-key "license"
:documentation "The license information for the exposed API.")
(version :type string
:documentation "Provides the version of the application API (not to be confused with the specification version)."
:data-key "version"
:required t))
(:metaclass sanity-clause:validated-metaclass))
;;; Deserialize the json from the file into instances of these classes
(let ((v2-info (alexandria:read-file-into-string (merge-pathnames "v2-info.json" *load-truename*))))
(sanity-clause:load ’info-object (jojo:parse v2-info :as :alist)))
;; => #<INFO-OBJECT {10045F9C93}>
(slot-value * ’license)
;; => #<LICENSE-OBJECT {1006600BE3}>
(slot-value * ’name)
;; => "Apache 2.0"
0.7.4
alexandria
(system).
arrows
(system).
cl-ppcre
(system).
closer-mop
(system).
local-time
(system).
str
(system).
trivial-types
(system).
parse-float
(system).
quri
(system).
util.lisp
(file).
validator.lisp
(file).
protocol.lisp
(file).
field.lisp
(file).
loadable-schema.lisp
(file).
schema.lisp
(file).
sanity-clause.lisp
(file).
Files are sorted by type and then listed depth-first from the systems components trees.
sanity-clause/sanity-clause.asd
sanity-clause/util.lisp
sanity-clause/validator.lisp
sanity-clause/protocol.lisp
sanity-clause/field.lisp
sanity-clause/loadable-schema.lisp
sanity-clause/schema.lisp
sanity-clause/sanity-clause.lisp
sanity-clause/util.lisp
sanity-clause
(system).
do-key-values
(macro).
get-value
(function).
lisp-name->env-name
(function).
sanity-clause/validator.lisp
sanity-clause
(system).
email
(function).
ensure-validator
(function).
hydrate-validators
(function).
int
(function).
not-empty
(function).
str
(function).
uuid
(function).
sanity-clause/protocol.lisp
sanity-clause
(system).
sanity-clause/field.lisp
sanity-clause
(system).
attribute-of
(reader method).
boolean-field
(class).
constant-field
(class).
conversion-error
(condition).
data-key-of
(reader method).
(setf data-key-of)
(writer method).
deserialize
(method).
deserialize
(method).
deserialize
(method).
deserialize
(method).
deserialize
(method).
deserialize
(method).
deserialize
(method).
deserialize
(method).
deserialize
(method).
deserialize
(method).
deserialize
(method).
deserialize
(method).
dump-field-p
(function).
email-field
(class).
error-messages-of
(reader method).
field
(class).
find-field
(function).
get-value
(method).
get-value
(method).
initialize-instance
(method).
initialize-instance
(method).
initialize-instance
(method).
integer-field
(class).
list-field
(class).
load
(method).
load-field-p
(function).
make-field
(function).
map-field
(class).
member-field
(class).
nested-field
(class).
one-field-of-field
(class).
one-schema-of-field
(class).
print-object
(method).
print-object
(method).
print-object
(method).
print-object
(method).
real-field
(class).
required-value-error
(condition).
resolve
(method).
resolve
(method).
resolve
(method).
resolve
(method).
serialize
(method).
string-field
(class).
timestamp-field
(class).
uri-field
(class).
uuid-field
(class).
validate
(method).
validate
(method).
validation-error
(condition).
all-validators
(function).
constant-test-of
(reader method).
constant-value-of
(reader method).
data-flow-of
(reader method).
default-of
(reader method).
define-final-class
(macro).
element-type-of
(reader method).
field-choices-of
(reader method).
(setf field-choices-of)
(writer method).
field-error
(condition).
field-of
(reader method).
key-field-of
(reader method).
(setf key-field-of)
(writer method).
members-of
(reader method).
missing
(type).
missing-field-name-of
(reader method).
nested-element
(class).
parents-of
(reader method).
(setf parents-of)
(writer method).
raised-error-of
(reader method).
required-p
(reader method).
schema-choices-of
(reader method).
(setf schema-choices-of)
(writer method).
validator-of
(reader method).
value-error
(condition).
value-field-of
(reader method).
(setf value-field-of)
(writer method).
value-of
(reader method).
sanity-clause/loadable-schema.lisp
sanity-clause
(system).
load-schema
(function).
sanity-clause/schema.lisp
sanity-clause
(system).
compute-effective-slot-definition
(method).
direct-slot-definition-class
(method).
dump
(method).
dump
(method).
effective-slot-definition-class
(method).
get-value
(method).
load
(method).
load
(method).
load
(method).
make-instance
(method).
shared-initialize
(method).
validate-superclass
(method).
validated-metaclass
(class).
class-initargs
(function).
field-of
(reader method).
(setf field-of)
(writer method).
initargs-for-slot
(function).
merge-plist
(function).
slot-type-to-field-initargs
(function).
take-properties
(function).
validated-direct-slot-definition
(class).
validated-effective-slot-definition
(class).
validated-slot-definition
(class).
Packages are listed by definition order.
sanity-clause.protocol
sanity-clause.validator
sanity-clause
sanity-clause.loadable-schema
sanity-clause.field
sanity-clause.util
sanity-clause.schema
sanity-clause.protocol
The methods that govern behavior in sanity-clause.
The methods relating to fields are:
* :function:‘resolve‘
* :function:‘deserialize‘
* :function:‘serialize‘
* :function:‘validate‘
* :function:‘get-value‘
The methods relating to schemas are:
* :function:‘load‘
* :function:‘dump‘
common-lisp
.
sanity-clause.validator
Some validation functions that can be used with fields to make sure data has certain properties.
alexandria
.
arrows
.
common-lisp
.
email
(function).
ensure-validator
(function).
hydrate-validators
(function).
int
(function).
not-empty
(function).
str
(function).
uuid
(function).
sanity-clause
Main package of the :package:‘sanity-clause‘ system.
:package:‘sanity-clause‘ helps define data contracts like "this field will always have a valid integer greater than zero in it". It’s also useful for serializing and deserializing data to and from different formats. Contracts are built in the form of schemas, which are composed of :class:‘sanity-clause.field:field‘ s.
for example::
(setq schema (list :name (make-field ’string)
:age (make-field ’integer :validator (lambda (v) (unless (> v 0) "impossible age!")))))
(setq some-data ’((:name . "matt")
(:age . "7")))
(load schema some-data)
;; => (:name "matt" :age 7)
;; note: the string for age got converted by DESERIALIZE from a string to an integer.
To learn more about what fields exist, check out :package:‘sanity-clause.field‘.
To see more validation functions, check out :package:‘sanity-clause.validator‘.
To see how to load a schema from a file or keyword spec, check out :package:‘sanity-clause.schema‘.
alexandria
.
common-lisp
.
sanity-clause.protocol
.
sanity-clause.loadable-schema
Loadable schemas can be expressed as plists of keywords and then can be loaded by :function:‘load‘, either from a file, or a list.
You could, for example, define the configuration of a program that reads from the environment with::
(setq schema (sanity-clause.loadable-schema:load #P"my-schema.sexp"))
And then you could load it from the environment with::
(sanity-clause.schema:load schema :env)
your “my-schema.sexp“ might look like::
(:name (:string :validator (:not-empty) :default "lisa" :required t)
:age (:integer :validator ((:int :min 0)) :required t))
alexandria
.
common-lisp
.
load-schema
(function).
sanity-clause.field
Field classes that can be used to validate data.
Also contains :function:‘sanity-clause.protocol:get-value‘, :function:‘sanity-clause.protocol:deserialize‘, and :function:‘sanity-clause.protocol:validate‘, which represent the lifecycle of loading data from some other object.
alexandria
.
arrows
.
common-lisp
.
attribute-of
(generic reader).
boolean-field
(class).
constant-field
(class).
conversion-error
(condition).
data-key-of
(generic reader).
(setf data-key-of)
(generic writer).
dump-field-p
(function).
email-field
(class).
error-messages-of
(generic reader).
field
(class).
find-field
(function).
integer-field
(class).
list-field
(class).
load-field-p
(function).
make-field
(function).
map-field
(class).
member-field
(class).
nested-field
(class).
one-field-of-field
(class).
one-schema-of-field
(class).
real-field
(class).
required-value-error
(condition).
string-field
(class).
timestamp-field
(class).
uri-field
(class).
uuid-field
(class).
validation-error
(condition).
all-validators
(function).
constant-test-of
(generic reader).
constant-value-of
(generic reader).
data-flow-of
(generic reader).
default-of
(generic reader).
define-final-class
(macro).
element-type-of
(generic reader).
field-choices-of
(generic reader).
(setf field-choices-of)
(generic writer).
field-error
(condition).
field-of
(generic reader).
key-field-of
(generic reader).
(setf key-field-of)
(generic writer).
members-of
(generic reader).
missing
(type).
missing-field-name-of
(generic reader).
nested-element
(class).
parents-of
(generic reader).
(setf parents-of)
(generic writer).
raised-error-of
(generic reader).
required-p
(generic reader).
schema-choices-of
(generic reader).
(setf schema-choices-of)
(generic writer).
validator-of
(generic reader).
value-error
(condition).
value-field-of
(generic reader).
(setf value-field-of)
(generic writer).
value-of
(generic reader).
sanity-clause.util
alexandria
.
arrows
.
common-lisp
.
do-key-values
(macro).
get-value
(function).
lisp-name->env-name
(function).
sanity-clause.schema
The :class:‘validated-metaclass‘ is a way of defining classes that have contracts enforced for them.
::
(defclass person ()
((favorite-dog :type symbol
:field-type :member
:members (:wedge :walter)
:data-key "favoriteDog"
:required t)
(age :type (integer 0)
:data-key "age"
:required t)
(potato :type string
:data-key "potato"
:required t))
(:metaclass validated-metaclass))
The above defines a class that can be instantiated with :function:‘sanity-clause.protocol:load, but will error if the initargs don’t satisfy the contract required by the field.
::
(sanity-clause:load ’person ’(("favoriteDog" . "wedge")
("age" . 10)
("potato" . "weasel"))
Some special types can be specifed with lisp type specs, like “age“ above, which will generate an :class:‘sanity-clause.field:integer-field‘, with validations requiring the value be at least 0.
**Nota Bene:** At the moment, there is no validation done on updating slots after instances are created and only instances created with :function:‘sanity-clause.protocol:load‘ are checked. Using :function:‘make-instance‘ doesn’t validate anything.
alexandria
.
arrows
.
common-lisp
.
validated-metaclass
(class).
class-initargs
(function).
field-of
(generic reader).
(setf field-of)
(generic writer).
initargs-for-slot
(function).
merge-plist
(function).
slot-type-to-field-initargs
(function).
take-properties
(function).
validated-direct-slot-definition
(class).
validated-effective-slot-definition
(class).
validated-slot-definition
(class).
Definitions are sorted by export status, category, package, and then by lexicographic order.
Is this field required for serialization (fields that have flow of :dump or :both)?
Checks that the input resembles an email.
Find a validator function by keyword-spec and return the function represented by the spec unless it’s already a function.
Find the class that corresponds to :param:‘type‘ by name
Generic reader function for lists and class instances. Returns a “(values value found-p)“ so you can tell if the value was in the list or not. Can also read from the environment if given “:env“ as OBJECT.
Takes a list of validators in the form of keywords and turns them into living function references.
Accepts a :param:‘value‘ as an integer or string.
If :param:‘value‘ is a string, interpret it as a value with base- :param:‘radix‘.
If specified, make sure :param:‘min‘ <= :param:‘value‘ <= :param:‘max‘.
Is this field required for deserialization (fields that have flow of :load or :both)?
Takes a :type:‘pathname‘ or schema spec list like::
(:key (:string :validator (:not-empty) :default "potato")
:key2 (:integer :validator ((:int :min 0)) :default 2))
and returns a schema plist with fields. The field names are transformed into the “:data-key“ for the field by the :param:‘data-key-transformer‘, which is helpful when reading strings from a config file and putting them into a plist keyed with symbols.
Make a field instance of class “type-FIELD“ and give it initargs :param:‘args‘.
Checks that some value has been supplied. Note: this won’t work well with boolean values because NIL is falsey.
Checks that :param:‘value‘ is a string.
If specified, checks that :param:‘min-length‘ <= “(length value)“ <= :param:‘max-length‘.
Checks that a value is a string that resembles a uuid.
Converts the value retrieved from the raw data into the datatype the field expects to work with, or fails, raising a :class:‘sanity-clause.field:conversion-error‘.
one-schema-of-field
) data) ¶list-field
) value) ¶nested-field
) value) ¶timestamp-field
) value) ¶real-field
) value) ¶integer-field
) value) ¶boolean-field
) value) ¶member-field
) value) ¶string-field
) value) ¶WARNING: This isn’t fully tested/supported, but it might work! I reserve the right to change the API in breaking ways, though.
dump takes some data an serializes it to a plist or alist based on :param:‘format‘, which can be set to, well, “:plist“ or “:alist“.
validation-error
)) ¶Tries to fetch the value corresponding to the field from some datastructure. :param:‘field-name‘ is used if no attribute is explicitly set on the field.
validated-slot-definition
) object) ¶constant-field
) object) ¶Deserializes :param:‘data‘ into an instance of :param:‘schema‘. Fills in default values and validates fields. If :param:‘schema‘ is “:env“, it will try to load from environment variables.
A function that encapsulates getting, corecing, and validating values for a field. Calls :function:‘get-value‘, :function:‘deserialize‘, and :function:‘validate‘.
one-field-of-field
) data &optional parents) ¶Converts the value of a field into another representation.
Run the validation checks for a given field and raise a :class:‘sanity-clause.field:validation-error‘ if it is invalid.
constant-field
) value) ¶validated-metaclass
) name direct-slot-definitions) ¶sb-mop
.
validated-metaclass
) &key) ¶sb-mop
.
validated-metaclass
) &key) ¶sb-mop
.
list-field
) &key) ¶one-field-of-field
) &key) ¶validated-metaclass
) &rest initargs &key data) ¶conversion-error
) stream) ¶validation-error
) stream) ¶required-value-error
) stream) ¶validated-metaclass
) (c standard-object
)) ¶sb-mop
.
An error that signals something went wrong while calling “converter“ for a field.
The error that was caught while converting.
:from-error
This slot is read-only.
An error that signals a required value is missing.
The name of the field that is missing a required value.
:field-name
This slot is read-only.
Error that indicates a field is invalid.
A list of any error messages generated by the a field.
(quote nil)
:error-messages
This slot is read-only.
A field type for bolean values.
A field that expects to get the same value every time. Will throw a :class:‘conversion-error‘ if VALUE isn’t equal to CONSTANT according to TEST.
The constant value to be serialized or deserialized.
:constant
This slot is read-only.
Function to use to compare the constant value to other values.
(quote equal)
:test
This slot is read-only.
A field for values that should be emails.
(quote sanity-clause.validator:email)
A base class for all fields that controls how they are (de?)serialized.
Name of the attribute to write the field’s value to when serializing, if null, inferred from the name of the field.
(or null symbol string)
:attribute
This slot is read-only.
Name of the attribute to read the field’s value from when deserializing, if null, inferred form the name of the field.
(or null string symbol)
:data-key
Value to use during serialization when no value is set.
:missing
:default
This slot is read-only.
(or symbol function list)
(constantly nil)
:validator
This slot is read-only.
If data should only ever be loaded into this field, this is :both (the default). If data should only be deserialized from the field and ignored when serializing, :load. If data should only be serialized from the field but ignored during loading, :dump.
(member :both :load :dump)
:both
:flow
This slot is read-only.
Is this field required? Cause the field to fail validation if it’s not filled.
boolean
:required
This slot is read-only.
A field that holds an integer value.
(quote sanity-clause.validator:int)
A field that contains a list of values satsified by another field.
A field that maps values of one kind to values to another kind, like strings to strings, or numbers to objects.
examples::
(make-field :map :key-field :string :value-field :integer)
(deserialize * ’(("potato" . 4) ("chimp" . 11)))
A field that expects a member of a set of symbols.
(error "a member field requires a list of symbols that are acceptable members.")
:members
This slot is read-only.
A field that represents a complex object located at this slot.
A field type that allows any of the fields specified.
Fields that this field could decode to.
list
(error ":field-choices is required in one-field-of-field.")
:field-choices
A field type that allows any of the schemas specified.
Use the “:schema-choices“ initarg to provide a list of schema classes to try.
**Note**: If your schema choices are very lenient (ie. every field is not required), this field will likely behave in unexpected ways. That is, if you specify a list of classes that only have optional fields, sanity clause won’t be able to figure out which one to use and will probably return the missing value instead of valid data. You probably want at least one charactersitic field to be required.
Fields that this field could decode to.
list
(error ":schema-choices is required in one-schema-of-field.")
:schema-choices
A field that contains a real value (eg. possibly a float).
A field that contains a string.
A field that contains a timestamp
A field for values that should be emails.
A field for values that should resemble UUIDs.
(quote sanity-clause.validator:uuid)
standard-class
.
A macro for definining classes that are finalized after definition.
Returns a generator function that yields a validator function each call.
Attempts to convert :param:‘value‘ to a “t“ or “nil“ by comparing it to a list of stringy true or false values. Throws a :class:‘<validation-error>‘ if it can’t figure out if :param:‘value‘ is truthy or falsey.
Collect the initargs for :param:‘class‘, which is either a class or a symbol naming a class.
Collects arguments for and initializes a field and then returns it along with the cleaned up :param:‘initargs‘. This list can then be passed as the initargs to :class:‘validated-field-slot-definition‘.
Convert kebab case to upper snake case, e.g. “some-name => SOME_NAME“
Merge the keys :param:‘keys‘ on :param:‘list1‘ and :param:‘list2‘.
Sometimes, it’s useful to try to infer the field type from a lisp type-spec. For example::
(integer 0 10)
should produce a field that expects integers “(<= 0 n 10)“.
In the event the type isn’t a simple type, assume it’s a class with metaclass :class:‘validated-metaclass‘ and try to use that instead.
Takes keys from :param:‘take-list‘ from the provided plist :param:‘from‘.
constant-field
)) ¶Function to use to compare the constant value to other values.
test
.
constant-field
)) ¶The constant value to be serialized or deserialized.
field
)) ¶If data should only ever be loaded into this field, this is :both (the default). If data should only be deserialized from the field and ignored when serializing, :load. If data should only be serialized from the field but ignored during loading, :dump.
nested-element
)) ¶The field that respresents the elements of the list.
one-field-of-field
)) ¶one-field-of-field
)) ¶Fields that this field could decode to.
field-error
)) ¶validated-slot-definition
)) ¶automatically generated reader method
validated-slot-definition
)) ¶automatically generated writer method
member-field
)) ¶automatically generated reader method
required-value-error
)) ¶field-error
)) ¶field-error
)) ¶conversion-error
)) ¶one-schema-of-field
)) ¶one-schema-of-field
)) ¶Fields that this field could decode to.
value-error
)) ¶Base class for all errors thrown by :package:‘sanity-clause.field‘.
error
.
:parents
Base class for errors involving values.
error
.
The field that respresents the elements of the list.
(or sanity-clause.field:field symbol trivial-types:proper-list)
(error "a nested field requires an element-type to deserialize members to.")
:element-type
This slot is read-only.
standard-direct-slot-definition
.
validated-slot-definition
.
standard-effective-slot-definition
.
validated-slot-definition
.
sanity-clause.field:field
:field-instance
Jump to: | (
A B C D E F G H I K L M N P R S T U V |
---|
Jump to: | (
A B C D E F G H I K L M N P R S T U V |
---|
Jump to: | A C D E F K M P R S T V |
---|
Jump to: | A C D E F K M P R S T V |
---|
Jump to: | B C E F I L M N O P R S T U V |
---|
Jump to: | B C E F I L M N O P R S T U V |
---|