Permalink
Browse files

declare validation rules on the class not the instance

  • Loading branch information...
1 parent 45b746c commit fb6a91b6bf962bd0e23d27003f0e44d2b35198aa @olivernn committed Sep 24, 2010
Showing with 74 additions and 46 deletions.
  1. +8 −1 src/model.js
  2. +13 −0 src/model_instance_methods.js
  3. +35 −38 src/model_validations.js
  4. +18 −7 test/tests/model_validations.js
View
@@ -10,9 +10,11 @@ var Model = function(name, class_methods, instance_methods) {
this.uid = [name, Model.UID.generate()].join("-")
};
- // Persistence is special, remove it from class_methods.
+ // Persistence & validations are special, remove them from class_methods.
var persistence = class_methods.persistence
+ var validation_rules = class_methods.validates;
delete class_methods.persistence
+ delete class_methods.validates;
// Apply class methods and extend with any custom class methods. Make sure
// vitals are added last so they can't be overridden.
@@ -29,6 +31,11 @@ var Model = function(name, class_methods, instance_methods) {
// Initialise persistence with a reference to the class.
if (persistence) model.persistence = persistence(model)
+ // Initialise a validator object for this class.
+ if (validation_rules) {
+ model.validator = Model.Validator(validation_rules);
+ };
+
// Add default and custom instance methods.
jQuery.extend(model.prototype, Model.Callbacks, Model.InstanceMethods, Model.Validations,
instance_methods);
@@ -110,5 +110,18 @@ Model.InstanceMethods = {
update: function(attributes) {
this.merge(attributes).trigger("update");
return this;
+ },
+
+ valid: function() {
+ this.errors.clear();
+ this.validate();
+ if (this.constructor.validator) {
+ this.constructor.validator.run.call(this);
+ };
+ return this.errors.size() === 0;
+ },
+
+ validate: function() {
+ return this;
}
};
View
@@ -1,46 +1,43 @@
-Model.Validations = {
- runValidations: function () {
- var self = this;
- var validations = {
- validatesPresenceOf: function (attrValue, attrName, options) {
- if (!attrValue) {
- self.errors.add(attrName, "should not be blank");
- };
- },
+Model.Validator = function (rules) {
+ var rules = rules;
- validatesLengthOf: function (attrValue, attrName, options) {
- if (attrValue.length < options.min || attrValue.length > options.max) {
- self.errors.add(attrName, "is too short or too long");
- };
- }
- };
+ var validationMethods = {
+ presenceOf: function (attrName, attrValue, options) {
+ if (!attrValue) {
+ this.errors.add(attrName, "should not be blank");
+ };
+ },
- for (rule in validations) {
- var attributesToValidate = this[rule] || [];
- for (var i=0; i < attributesToValidate.length; i++) {
- if (typeof(attributesToValidate[i]) == "string") {
- // no options passed, just attribute names
- var attrName = attributesToValidate[i];
- var options = {};
- } else {
- // options passed
- var attrName = attributesToValidate[i].attr;
- var options = attributesToValidate[i];
- };
- validations[rule](this.attr(attrName), attrName, options);
+ lengthOf: function (attrName, attrValue, options) {
+ if (attrValue.length < options.min || attrValue.length > options.max) {
+ this.errors.add(attrName, "is too short or too long");
};
+ }
+ };
+
+ var ruleWithoutOptions = function (ruleName, ruleValue) {
+ for (var i=0; i < ruleValue.length; i++) {
+ validationMethods[ruleName].call(this, ruleValue[i], this.attr(ruleValue[i]), {});
};
+ };
- },
+ var ruleWithOptions = function (ruleName, ruleValue) {
+ for (attributeName in ruleValue) {
+ validationMethods[ruleName].call(this, attributeName, this.attr(attributeName), ruleValue[attributeName]);
+ };
+ };
- valid: function() {
- this.errors.clear();
- this.validate();
- this.runValidations();
- return this.errors.size() === 0;
- },
+ var run = function () {
+ for (rule in rules) {
+ if ($.isArray(rules[rule])) {
+ ruleWithoutOptions.call(this, rule, rules[rule]);
+ } else {
+ ruleWithOptions.call(this, rule, rules[rule]);
+ };
+ };
+ };
- validate: function() {
- return this;
- }
+ return {
+ run: run
+ };
};
@@ -1,9 +1,12 @@
module("Model.Validations")
test("validatesPresenceOf", function () {
- var Post = Model("post", {}, {
- validatesPresenceOf: ['title']
- });
+
+ var Post = Model("post", {
+ validates: {
+ presenceOf: ['title']
+ }
+ }, {});
var validPost = new Post ({ title: "Foo", body: "..." });
var invalidPost_noTitle = new Post ({body: "..."});
@@ -15,8 +18,12 @@ test("validatesPresenceOf", function () {
})
test("validatesLengthOf", function () {
- var Post = Model("post", {}, {
- validatesLengthOf: [{ attr: 'title', min: 5, max: 10 }]
+ var Post = Model("post", {
+ validates: {
+ lengthOf: {
+ 'title': { min: 5, max: 10}
+ }
+ }
});
var validPost = new Post ({ title: "just right", body: "..." });
@@ -29,8 +36,12 @@ test("validatesLengthOf", function () {
})
test("validatesLengthOf with default options", function () {
- var Post = Model("post", {}, {
- validatesLengthOf: [{ attr: 'title', max: 10 }]
+ var Post = Model("post", {
+ validates: {
+ lengthOf: {
+ 'title': { max: 10 }
+ }
+ }
});
var validPost = new Post ({ title: "just right", body: "..." });

0 comments on commit fb6a91b

Please sign in to comment.