Permalink
Browse files

Rewrite custom validation

  • Loading branch information...
1 parent e55b29e commit 9dcd976546c390b3fe4e8fc81a83403e1e8dec9c @1602 committed Nov 18, 2011
Showing with 39 additions and 30 deletions.
  1. +21 −17 lib/validatable.js
  2. +10 −9 test/hookable_test.coffee
  3. +8 −4 test/validations_test.coffee
View
@@ -10,17 +10,7 @@ Validatable.validatesNumericalityOf = getConfigurator('numericality');
Validatable.validatesInclusionOf = getConfigurator('inclusion');
Validatable.validatesExclusionOf = getConfigurator('exclusion');
Validatable.validatesFormatOf = getConfigurator('format');
-Validatable.validate = function () {
- args = [].slice.call(arguments);
- var valFn = function () {}; // noop
- if (typeof args[args.length - 1] === 'function'){
- valFn = args.pop();
- }
- wrapperFn = function customValidator(attr, conf, err) {
- return valFn.call(this, err);
- };
- configure(this, wrapperFn, args)
-};
+Validatable.validate = getConfigurator('custom');
// implementation of validators
var validators = {
@@ -77,13 +67,16 @@ var validators = {
} else {
err();
}
+ },
+ custom: function (attr, conf, err) {
+ conf.customValidator.call(this, err);
}
};
-function getConfigurator(name) {
+function getConfigurator(name, opts) {
return function () {
- configure(this, name, arguments);
+ configure(this, name, arguments, opts);
};
}
@@ -124,15 +117,21 @@ function cleanErrors(inst) {
function validationFailed(inst, v) {
var attr = v[0];
var conf = v[1];
+ var opts = v[2] || {};
+
+ if (typeof attr !== 'string') return false;
// here we should check skip validation conditions (if, unless)
// that can be specified in conf
if (skipValidation(inst, conf, 'if')) return false;
if (skipValidation(inst, conf, 'unless')) return false;
var fail = false;
- var validator = typeof conf.validation === "function" ? conf.validation : validators[conf.validation];
- validator.call(inst, attr, conf, function onerror(kind) {
+ var validator = validators[conf.validation];
+ var validatorArguments = [];
+ validatorArguments.push(attr);
+ validatorArguments.push(conf);
+ validatorArguments.push(function onerror(kind) {
var message;
if (conf.message) {
message = conf.message;
@@ -154,6 +153,7 @@ function validationFailed(inst, v) {
inst.errors.add(attr, message);
fail = true;
});
+ validator.apply(inst, validatorArguments);
return fail;
}
@@ -221,7 +221,7 @@ function blank(v) {
return false;
}
-function configure(cls, validation, args) {
+function configure(cls, validation, args, opts) {
if (!cls._validations) {
Object.defineProperty(cls, '_validations', {
writable: true,
@@ -237,9 +237,12 @@ function configure(cls, validation, args) {
} else {
conf = {};
}
+ if (validation === 'custom' && typeof args[args.length - 1] === 'function') {
+ conf.customValidator = args.pop();
+ }
conf.validation = validation;
args.forEach(function (attr) {
- cls._validations.push([attr, conf]);
+ cls._validations.push([attr, conf, opts]);
});
}
@@ -253,3 +256,4 @@ Errors.prototype.add = function (field, message) {
this[field].push(message);
}
};
+
View
@@ -18,62 +18,63 @@ User = schema.define 'User',
createdByAdmin: Boolean
it "should trigger after initialize", (test)->
- User.afterInitialize = ()->
+ User.afterInitialize = ()->
User.afterInitialize = null
test.done()
user = new User
it "should trigger before create", (test)->
- User.beforeCreate = ()->
+ User.beforeCreate = ()->
User.beforeCreate = null
test.done()
User.create {}, ()-> test.ok "saved"
it "should trigger after create", (test)->
- User.afterCreate = ()->
+ User.afterCreate = ()->
User.afterCreate = null
test.done()
User.create {}, ()-> test.ok "saved"
it "should trigger before save", (test)->
- User.beforeSave = ()->
+ User.beforeSave = ()->
User.beforeSave = null
test.done()
user = new User
user.save ()-> test.ok "saved"
it "should trigger after save", (test)->
- User.afterSave = ()->
+ User.afterSave = ()->
User.afterSave = null
test.done()
user = new User
user.save ()-> test.ok "saved"
it "should trigger before update", (test)->
- User.beforeUpdate = ()->
+ User.beforeUpdate = ()->
User.beforeUpdate = null
test.done()
User.create {}, (err, user)->
user.updateAttributes {email:"1@1.com"}, ()-> test.ok "updated"
it "should trigger after update", (test)->
- User.afterUpdate = ()->
+ User.afterUpdate = ()->
User.afterUpdate = null
test.done()
User.create {}, (err, user)->
user.updateAttributes {email:"1@1.com"}, ()-> test.ok "updated"
it "should trigger before destroy", (test)->
- User.beforeDestroy = ()->
+ User.beforeDestroy = ()->
User.beforeDestroy = null
test.done()
User.create {}, (err, user)->
user.destroy()
it "should trigger after destroy", (test)->
- User.afterDestroy = ()->
+ User.afterDestroy = ()->
User.afterDestroy = null
test.done()
User.create {}, (err, user)->
user.destroy()
+
@@ -214,16 +214,20 @@ it 'should validate format', (test) ->
test.done()
-it 'should validate a field using a custom validator', (test)->
+it 'should validate a field using a custom validator', (test) ->
- User.validate 'email', (err)-> err("crash") if @email.length is 0
+ validator = (err) ->
+ err('crash') if @name == 'bad name'
+
+ User.validate 'name', validator, message: crash: 'custom message'
user = new User validAttributes
test.ok user.isValid()
user = new User validAttributes
- user.email = ""
- test.ok not user.isValid()
+ user.name = 'bad name'
+ test.ok not user.isValid(), 'invalid due custom name validator'
+ test.equal user.errors.name[0], 'custom message'
test.done()

0 comments on commit 9dcd976

Please sign in to comment.