1 rio.Form = {
  2 	
  3 	build: function(options) {
  4 		var attributes = options.attributes || {};
  5 		var attr = rio.Attr.create({ 
  6 			attrAccessors: Object.keys(attributes),
  7 			methods: {
  8 				reset: function() {
  9 					Object.keys(attributes).each(function(attribute) {
 10 						var initialValue = attributes[attribute].initialValue || "";
 11 						initialValue = initialValue.constructor == rio.Binding ? initialValue.value() : initialValue;
 12 						this[attribute].update(initialValue || "");
 13 						this.errors[attribute].update("");
 14 					}.bind(this));
 15 				},
 16 				
 17 				values: function() {
 18 					var values = {};
 19 					Object.keys(attributes).each(function(attribute) {
 20 						values[attribute] = this[attribute].value();
 21 					}.bind(this));
 22 					return values;
 23 				},
 24 				
 25 				commit: function() {
 26 					if (this.valid()) {
 27 						(options.onCommit || Prototype.emptyFunction)(this.values());
 28 					}
 29 				},
 30 				
 31 				errorsFor: function(field) {
 32 					return this.errors[field];
 33 				},
 34 				
 35 				valid: function() {
 36 					return this.validate();
 37 				},
 38 				
 39 				validate: function() {
 40 					var valid = true;
 41 					Object.keys(attributes).each(function(attribute) {
 42 						(attributes[attribute].validates || []).uniq().each(function(validate) {
 43 							var errorMessage = Object.isString(validate) ? 
 44 								rio.Validators[validate](this[attribute].value()) :
 45 								validate(this.values());
 46 							errorMessage = errorMessage || "";
 47 							if (!errorMessage.blank()) {
 48 								valid = false;
 49 							}
 50 							this.errors[attribute].update(errorMessage);
 51 						}.bind(this));
 52 					}.bind(this));
 53 					return valid;
 54 				}
 55 			}
 56 		});
 57 		var form = new attr();
 58 		
 59 		
 60 		var errorAttr = rio.Attr.create({
 61 			attrAccessors: Object.keys(attributes).map(function(attribute) { return [attribute, ""]; })
 62 		});
 63 		form.errors = new errorAttr();
 64 		form.reset();
 65 
 66 		Object.keys(attributes).each(function(attribute) {
 67 			form[attribute].bind(form.validate.bind(form), true);
 68 		});
 69 		
 70 		
 71 		return form;
 72 	}
 73 	
 74 	
 75 };
 76 rio.Form.toString = function() { return "Form"; };
 77 
 78 rio.Validators = {
 79 	email: function(value) {
 80 		return value.validEmail() ? "" : "not a valid email address";
 81 	},
 82 	
 83 	presence: function(value) {
 84 		return value && !value.blank() ? "" : "cannot be blank";
 85 	},
 86 	
 87 	toString: function() { return "Validators"; }
 88 };