pour is a web form validation library for the Clojure programming language
Clojure
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
src/pour
test/pour
.gitignore
COPYING
README.textile
project.clj

README.textile

pour is a web form validation library for the
Clojure programming language.

The purpose of the library is to validate form fields to specified
constraints/validators and also to convert incoming fields, which are strings,
to valid data in the application domain. In the future this library might be
able to generate HTML or JavaScript code from form definitions.

At the moment nothing binds this library to web, it can be used to validate
any data in the form of a map.

Usage

Forms are defined with a macro defform which defines a new named function
which is used to validate a map of form data. The following code is an
example which might be used for validating login form fields (sans the actual
login/password validation):

(use ['pour.core :only ['defform]])
(use 'pour.validators)

(defform test-form
  :login [required "Login is required"
          email-address "Login should be a valid email address"]
  :password [required "Password is required"
             (minimum-length 5) "Password should be at least 5 chars long"])

Running the code, a new function named test-form is defined. The format of
the macro is: the name of the resulting function, with any number of key value
combinations where the key is the name of a field and the value is a vector
that defines validator and error message pairs. The validators must return
either the input parameter or a conversion of it, which is then passed on to
the next validator; nil designates an error.

To validate input you just pass the map of data to that function:

(test-form {:login "foo@example.com" :password "12345"})

which in this case would return:

{:errors {} :values {:login "foo@example.com", :password "12345"}}

as you can see, the returned map is split in two sections :errors and
:values. The errors are listed in the :errors section, if any, and the
converted values in the :values section. To access these, you can use the
keywords directly, but the library also defines two functions errors and
values for fetching them (these provide a bit more abstraction if the
returned map format changes in the future).

The next example shows the error handling:

(test-form {:login "foo" :password "12345"})

which results in:

{:errors {:login "Login should be a valid email address"},
 :values {:login nil, :password "12345"}}

as you can see, on error the :errors section is filled with data, and the
value of the field with an error is set to nil. The validators fail fast,
so only the first error is reported. To check for errors, you can use
errors? function which returns a boolean.

Even if you don’t provide all the fields in your input map, all the fields
defined in the form will be validated with nil as the value for missing keys.
To get a list of fields in the form use fields function for it; but note
that the fields returned are not in any order.

Validators

Validator functions are simply functions which takes a single argument, and
returns that argument or a converted version of it on succesful validation,
otherwise it returns nil.

An example validator without conversion:

(defn required [param] (if (pos? (count param)) param nil))

this validator checks that the param should have one or more elements in it.
A check which could be used for non-empty strings or other sequences. As you
can see, when the check is succesful, it returns the original param without
touching it; otherwise nil.

As said before, if there is a chain of validators, the returned value from the
validators will be passed on to the next. Kinda like with Clojure’s ,
except that validators only supports a single argument.

To get a validator with configurable behavior, you can write a function which
returns a function which will be the actual validator:

(defn minimum-length [minlen]
  (fn [param] (if (>= (count param) minlen) param nil)))

You can use anonymous functions too, as shown in the following example; which
also shows how the conversion works:

(defn a-number [param]
  (try (do (Integer/parseInt param))
       (catch NumberFormatException _ nil)))

(defform converter-example
  :age [required "Age is required"
        a-number "Age must be a numeric value"
        #(if (> % 13) % nil) "Must be older than 13 years"])

When checking the age, the starting value is though to be a string, for which
required checks that the string is not empty, next a-number converts it to
an integer and after that our anonymous function checks the age.

There is a helper function for creating validators from simple predicates
called pred-to-validator:

(def over-13 (pred-to-validator #(> % 13)))

(defform converter-example
  :age [required "Age is required"
        a-number "Age must be a numeric value"
        over-13 "Must be older than 13 years"])

or it’s two variants:

(def over-13 (pred-to-validator-> (> 13)))

(def over-13 (pred-to-validator->> (< 13)))

which works just like Clojures built-in and →> where the first value
of the chain is the value to be validated, only difference is that the
original value is returned when the chain return other than nil. There are
two variants of these if you wish to return the chain result:
pred-to-validator-do→ and pred-to-validator-do→>.

It’s also possible to create short-circuiting validators, optional is a
built-in example for that:

(defform optional-example
  :choice [(optional 0) ""
           a-number "Choice must be a numeric value"])

when nil is passed to optional it returns the argument, otherwise it
passes the starting value to the next validator. Notice that there is no
error condition, so the error string can be empty. There is a special
function to use short-circuiting in the validators: stop-with-value, which
takes a single argument, which is the value provided on short-circuit. These
short-circuit functions can be put anywhere in the validation chain.

Built-in Validators

In pour.validators namespace, there are some built-in validators. Some of
them we already used in the previous examples, but here is a list of current
validators:

required

Tests that the value is defined and is not empty. It’s designed mainly for
Strings.

minimum-length [minlen]

Tests that the value length is not smaller than minlen. It’s actually a
function which returns the actual validator when called.

maximum-length [maxlen]

Tests that the value length is not larger than maxlen.

a-number

Converts the value to a number from a String, or passes a number as is. If
the value cannot be converted to a number, it returns nil.

an-integer

Same as a-number but only works on Integers.

a-double

Same as a-number but converts all numbers to a Double.

email-address

Tests that the value is a valid email address.

optional [value-to-return]

If the value is nil, then the validation chain short-circuits and returns
value-to-return. Otherwise it passes on the original value.

Contact

To contact me, send email to my first name without umlauts vaino at
complexusage.net

License

Copyright © 2010 Väinö Järvelä
Copyright © Rich Hickey (assert_args.clj)

The use and distribution terms for this software are covered by the
Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
see COPYING file.

By using this software in any fashion, you are agreeing to be bound by the
terms of this license. You must not remove this notice, or any other, from
this software.

Thanks

Thanks to Rasmsus Svensson for all the help in the beginning of this project.