Home > pour

pour

Pour is a project mainly written in Clojure, based on the EPL-1.0 license.

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

pour is a web form validation library for the "Clojure":http://clojure.org 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.

h2. 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 "[email protected]" :password "12345"})

which in this case would return:

{:errors {} :values {:login "[email protected]", :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.

h2. 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.

h2. 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:

h3. required

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

h3. 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.

h3. maximum-length [maxlen]

Tests that the value length is not larger than maxlen.

h3. 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.

h3. an-integer

Same as a-number but only works on Integers.

h3. a-double

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

h3. email-address

Tests that the value is a valid email address.

h3. 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.

h2. Contact

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

h2. License

Copyright (C) 2010 Väinö Järvelä Copyright (C) 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.

h2. Thanks

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

Previous:.gitignore