socialchorus/nail_polish — pull request #1 by v-yarotsky (2014-05-19 17:54:08+00:00)
Title: Add NailPolish.Validation (initial implementation)

Initial implementation of model validations micro-framework.

## The Idea

Backbone.js provides some extension points for validation out-of-box, like [validate](http://documentcloud.github.io/backbone/#Model-validate) and [validationError](http://documentcloud.github.io/backbone/#Model-validationError) on the Backbone.Model. `validationError` can be virtually anything, as Backbone.js itself does not make any assumptions regarding it's contents except it expects it to be `undefined` if the model is valid.

This pull request provides an "Error Object Builder" which can be used in the `#validate` hook, and it takes care of putting together a uniform error object to return, or an `undefined` if all validations passed.

Example usage:

```javascript
MyApp.MyModel = Backbone.Model.extend({
...
validate: function(attributes) {
var validate = new NailPolish.Validation();
validate.
attribute("name").
addRule("is required", validate.is.required()).
addRule("is too long", validate.is.tooLong(10)).
addRule("must start with a letter", validate.is.notMatching(/^[a-zA-Z]/)).
addRule("may not start with Q", function(value) {
return undefined !== value && value[0] == "Q";
});
return validate.validate(attributes);
}
...
});
```

The return value in case there were errors could look like this:

```json
{
"name": ["is too long", "may not start with Q"]
}
```

As you can see, there's a number of standard matchers:
- `is.required()`
- `is.tooLong(maxLength)`
- `is.tooShort(minLength)`
- `is.notMatching(regexp)`

Other matchers can be added to NailPolish within particular application by extending the `NailPolish.Validation.prototype.is` object.

Also, custom matchers can be inlined (see the example above).

## What's next

Next step would be to make the base `NailPolish.Presenter` recognize and populate model errors in it's resulting json, so that errors are available to templates.

Also, it is a good idea to introduce the `NailPolish.Model`, which would hook into `save` method and trigger an `invalid` event with errors json from server so that it looks same for `NailPolish.Presenter` as if it was `#validate` errors.

## Can it be better

Currently, validation rules need to be "bullet-proof", i.e. they should not make any assumptions when it comes to the value, as it can be `undefined`, `null`, `""`, or whatever else. This leads to some duplication in matchers. The other approach could be to wrap the execution of these matchers in a `try...catch`, but I'm not sure whether it's a good idea from the debugging/testing perspective.