Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

vindarel
vindarel

Posted on

Form validation in Common Lisp

I've been using theclavier library for input validation, it works nicely but we could make it a bit more terse.

Let's say you are building many HTML forms. Doing one all manually is OK-ish, not two. You could usecl-forms (I didn't, I'm building a layer to get a form from Mito objects. If you didn't see where I'm doing it look better or stay tuned ;) ) You could do things semi-manually and use Clavier for input validation. It works like this.

Define a list of validators for your fields:

(defmethodvalidators((obj(eql'book)))(dict'isbn(list;; other validator here…(clavier:len:min10:max13;; :message works with clavier's commit of <2024-02-27>;; :message "an ISBN must be between 10 and 13 characters long"))'title(clavier:~="test""this title is too common, please change it!")))
Enter fullscreen modeExit fullscreen mode

You can compose them with boolean logic:

(defparameter*validator*(clavier:||(clavier:blank)(clavier:&&(clavier:is-a-string)(clavier:len:min10)))"Allow a blank value. When non blank, validate.")
Enter fullscreen modeExit fullscreen mode

This validator allows an input to be an empty string, but if it isn't, it validates it.

(funcall*validator*"");; =>TNIL(funcall*validator*"asdf");; =>NIL"Length of \"asdf\" is less than 10"
Enter fullscreen modeExit fullscreen mode

For one, I want a shorter construct for this common need.My PR was rejected so here it is.

Use a:allow-blank keyword:

(defmethodvalidators((obj(eql'book)))(dict'isbn(list:allow-blank(clavier:len:min10:max13
Enter fullscreen modeExit fullscreen mode

and write avalidate-all function:

(defunvalidate-all(validatorsobject)"Run all validators in turn. Return two values: the status (boolean), and a list of messages.  Allow a keyword validator: :allow-blank. Accepts a blank value. If not blank, validate.";; I wanted this to be part of clavier, but well.;; https://github.com/mmontone/clavier/pull/10(let((messagesnil)(validt))(loopforvalidatorinvalidatorsif(and(eql:allow-blankvalidator)(str:blankpobject))returntelsedo(unless(symbolpvalidator)(multiple-value-bind(statusmessage)(clavier:validatevalidatorobject:error-pnil)(unlessstatus(setfvalidnil))(whenmessage(pushmessagemessages)))))(valuesvalid(reverse(uiop:ensure-listmessages)))))
Enter fullscreen modeExit fullscreen mode

This could be made better for a library API maybe? Anyways it works for now©.

See also that Clavier has a "validator-collection" thing, but not shown in the README, and is again too verbose in comparison to a simple list, IMO.

that's it, see ya next time.

Appendix: 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)
  • 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)
  • :allow-blank (not merged, only in my fork)

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Full-stack, Python, Common Lisp in production.Building a video course to learn Lisp efficiently.
  • Location
    France
  • Joined

More fromvindarel

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp