Comparing version 0.2.1 to 0.2.2
@@ -30,4 +30,8 @@ var Butler = new Class({ | ||
setupAccessors: function(){ | ||
this.setAccessor(Object.merge({}, this._accessors, this.options.accessors)); | ||
var accessors = this._accessors; | ||
this._accessors = {}; | ||
this.setAccessor(Object.merge({}, accessors, this.options.accessors)); | ||
return this; | ||
@@ -71,10 +75,13 @@ }, | ||
Object.each(obj, function(fnc, type) { | ||
var f; | ||
if (fnc && !accessors[type]) { | ||
f = accessors[type] = function(){ | ||
return this._processAccess(name, fnc.pass(arguments, this)); | ||
var orig = fnc; | ||
if (!fnc._orig) { | ||
fnc = function(){ | ||
return this._processAccess(name, orig.pass(arguments, this)); | ||
}.bind(this); | ||
f._orig = fnc; | ||
fnc._orig = orig; | ||
} | ||
accessors[type] = fnc; | ||
}, this); | ||
@@ -81,0 +88,0 @@ |
@@ -1,1 +0,1 @@ | ||
(function(a){var b={},c=function(d){var e=b[d];if(!e){e=b[d]={};var f=e.exports={};a[d].call(f,c,e,f,window)}return e.exports};window.Neuro=c("0")})({0:function(a,b,c,d){var e=a("1");e.Model=a("2").Model,e.Collection=a("a").Collection,e.View=a("c").View,c=b.exports=e},1:function(a,b,c,d){var e={version:"0.2.1"};c=b.exports=e},2:function(a,b,c,d){var e=a("3").Model,f=a("8").Butler,g=function(a){return function(b){var c=this.getAccessor(b,a),d=this._accessorName;return c&&d!=b?c():this.parent(b)}.overloadGetter()};e.implement(new f),c.Model=new Class({Extends:e,setup:function(a,b){return this.setupAccessors(),this.parent(a,b),this},__set:function(a,b){var c=this.getAccessor(a,"set");return c&&this._accessorName!=a?c.apply(this,arguments):this.parent(a,b)}.overloadSetter(),get:g("get"),getPrevious:g("getPrevious"),setAccessor:function(a,b){return a&&b&&(b.get&&!b.getPrevious&&(b.getPrevious=b.get),this.parent(a,b)),this}.overloadSetter()})},3:function(a,b,c,d){var e=a("4").Is,f=a("5").Silence,g=a("6").Connector,h=a("8").Butler,i=a("9"),j=function(a){switch(typeOf(a)){case"array":a=a.slice();break;case"object":if(!a.$constructor||a.$constructor&&!instanceOf(a.$constructor,Class))a=Object.clone(a)}return a},k=function(a){return function(b){return this[a][b]}.overloadGetter()},l=function(a){return function(){var b=this.keys(),c={};return b.each(function(b){c[b]=j(this[a](b))}.bind(this)),c}},m=new Class(i(["change","destroy","reset"],{signalChangeProperty:function(a,b,c){return!this.isSilent()&&this.fireEvent("change:"+a,[this,a,b,c]),this}})),n=new Class({Implements:[g,h,Events,Options,f,m],primaryKey:undefined,_data:{},_changed:!1,_changedProperties:{},_previousData:{},_setting:0,options:{primaryKey:undefined,defaults:{}},initialize:function(a,b){if(instanceOf(a,this.constructor))return a;this.setOptions(b),this.setup(a,b)},setup:function(a,b){return this.primaryKey=this.options.primaryKey,this.silence(function(){this.set(this.options.defaults)}.bind(this)),a&&this.set(a),this},__set:function(a,b){var c=this.get(a);return e.Equal(c,b)||(this._changed=!0,this._data[a]=this._changedProperties[a]=j(b)),this}.overloadSetter(),_set:function(a,b){return this._setting++,this.__set(a,b),this._setting--,this},set:function(a,b){var c;return a&&(c=this.isSetting(),!c&&this._setPrevious(this.getData()),a=instanceOf(a,n)?a.getData():a,this._set(a,b),c||(this.changeProperty(this._changedProperties),this.change(),this._resetChanged())),this},isSetting:function(){return!!this._setting},unset:function(a){var b={},c,d=0,e;a=Array.from(a),c=a.length;while(c--)b[a[d++]]=void 0;return this.set(b),this},reset:function(a){var b={},c=this.options.defaults,d,e=0,f;if(a){a=Array.from(a),d=a.length;while(d--)f=a[e++],b[f]=c[f]}else b=c;return this.set(b),this.signalReset(),this},get:k("_data"),getData:l("get"),_setPrevious:function(a,b){return this._previousData[a]=b,this}.overloadSetter(),getPrevious:k("_previousData"),getPreviousData:l("getPrevious"),_resetChanged:function(){return this._changed&&(this._changed=!1,this._changedProperties={}),this},change:function(){return this._changed&&this.signalChange(),this},changeProperty:function(a,b){return this._changed&&this.signalChangeProperty(a,b,this.getPrevious(a)),this}.overloadSetter(),destroy:function(){return this.signalDestroy(),this},toJSON:function(){return this.getData()},spy:function(a,b){return Type.isString(a)&&a in this._data&&Type.isFunction(b)&&this.addEvent("change:"+a,b),this}.overloadSetter(),unspy:function(a,b){return Type.isString(a)&&a in this._data&&this.removeEvents("change:"+a,b),this}.overloadSetter()});["each","subset","map","filter","every","some","keys","values","getLength","keyOf","contains","toQueryString"].each(function(a){n.implement(a,function(){return Object[a].apply(Object,[this._data].append(Array.from(arguments)))})}),c.Model=n},4:function(a,b,c,d){(function(a){var b=Object.prototype.toString,c=Object.prototype.hasOwnProperty,d=window.Type,e=a.Is={},f=window.Type=function(a,b){var c=new d(a,b),g;return c?(g="is"+a,e[a]=e.not[a]=f[g]=d[g],c):c}.extend(d);f.prototype=d.prototype;for(var g in d)f.hasOwnProperty(g)&&g.test("is")&&(g=g.replace("is",""),e[g]=f["is"+g]);e.NaN=function(a){return a!==a},e.Null=function(a){return a===null},e.Undefined=function(a){return a===void 0};var h={string:function(a,b){return a==String(b)},number:function(a,b){return a!=+a?b!=+b:a==0?1/a==1/b:a==+b},date:function(a,b){return+a==+b},"boolean":function(a,b){return this.date(a,b)},regexp:function(a,b){return a.source==b.source&&a.global==b.global&&a.multiline==b.multiline&&a.ignoreCase==b.ignoreCase}},i=function(a,b){return a.hasOwnProperty(b)},j=function(a,b,c){if(a===b)return a!==0||1/a==1/b;if(a==null||b==null)return a===b;if(a.isEqual&&e.Function(a.isEqual))return a.isEqual(b);if(b.isEqual&&e.Function(b.isEqual))return b.isEqual(a);var d=typeOf(a),f=typeOf(b);if(d!=f)return!1;if(h[d])return h[d](a,b);if(d!="object"||f!="object")return!1;var g=c.length;while(g--)if(c[g]==a)return!0;c.push(a);var k=0,l=!0;if(d=="array"){k=a.length,l=k==b.length;if(l)while(k--)if(!(l=k in a==k in b&&j(a[k],b[k],c)))break}else{if("constructor"in a!="constructor"in b||a.constructor!=b.constructor)return!1;for(var m in a)if(i(a,m)){k++;if(!(l=i(b,m)&&j(a[m],b[m],c)))break}if(l){for(m in b)if(i(b,m)&&!(k--))break;l=!k}}return c.pop(),l};e.Equal=function(a,b){return j(a,b,[])},function(a){var b={};for(var c in a)i(a,c)&&(b[c]=function(b){return function(c,d){return!a[b].call(a,c,d)}}(c));a.not=b}(e)})(typeof c!="undefined"?c:window)},5:function(a,b,c,d){var e=new Class({_silent:0,silence:function(a){return this._silent++,a&&a.call(this),this._silent--,this},isSilent:function(){return!!this._silent}});c.Silence=e},6:function(a,b,c,d){a("7");var e=function(a,b,c,d){return a=="string"&&(c=d&&d[c]?d.bound(c):undefined),c},f=function(a,b){var c={};return Object.each(a,function(a,d){d=d=="*"?b:b+":"+d,c[d]=a}),c},g=function(a,b,c){Object.each(b,function(b,d){b=Array.from(b),b.each(function(b){var h=typeOf(b);switch(h){case"object":instanceOf(b,Class)||g.call(this,a,f(b,d),c);break;case"string":case"function":b=e.call(this,h,d,b,c),b&&this[a](d,b)}},this)},this)},h=function(a){var b=a=="connect"?"addEvent":"removeEvent";return function(c,d){var e=this.options.connector;return g.call(this,b,e,c),!d&&c&&c[a](this,!0),this}},i=new Class({Implements:[Class.Binds],options:{connector:{}},connect:h("connect"),disconnect:h("disconnect")});c.Connector=i},7:function(a,b,c,d){Class.Binds=new Class({$bound:{},bound:function(a){return this.$bound[a]?this.$bound[a]:this.$bound[a]=this[a].bind(this)}})},8:function(a,b,c,d){var e=new Class({_accessors:{},_accessorName:undefined,options:{accessors:{}},setupAccessors:function(){return this.setAccessor(Object.merge({},this._accessors,this.options.accessors)),this},isAccessing:function(){return!!this._accessorName},_processAccess:function(a,b){var c;return a&&(this._accessorName=a,c=b(),this._accessorName=void 0),c},setAccessor:function(a,b){var c={};return!!a&&Type.isObject(b)&&(Object.each(b,function(b,d){var e;b&&!c[d]&&(e=c[d]=function(){return this._processAccess(a,b.pass(arguments,this))}.bind(this),e._orig=b)},this),this._accessors[a]=c),this}.overloadSetter(),getAccessor:function(a,b){var c=this._accessors[a];return b?c&&c[b]:c},unsetAccessor:function(a,b){return a&&(b?this._accessors[a][b]=void 0:this._accessors[a]=void 0),this}});c.Butler=e},9:function(a,b,c,d){c=b.exports=function(a,b,c){return Type.isFunction(b)||(c=b,b=undefined),c=c||{},Array.from(a).each(function(a){c["signal"+a.capitalize()]=b?b(a):function(){return!this.isSilent()&&this.fireEvent(a,this),this}}),c}},a:function(a,b,c,d){var e=a("b").Collection;c.Collection=e},b:function(a,b,c,d){var e=a("2").Model,f=a("5").Silence,g=a("6").Connector,h=a("9"),i=new Class(h(["empty","sort"],h(["add","remove"],function(a){return function(b){return!this.isSilent()&&this.fireEvent(a,[this,b]),this}}))),j=new Class({Implements:[g,Events,Options,f,i],_models:[],_Model:e,length:0,primaryKey:undefined,options:{primaryKey:undefined,Model:undefined,modelOptions:undefined},initialize:function(a,b){this.setOptions(b),this.setup(a,b)},setup:function(a,b){return this.primaryKey=this.options.primaryKey,this.options.Model&&(this._Model=this.options.Model),a&&this.add(a),this},hasModel:function(a){var b=this.primaryKey,c,d;return c=this._models.contains(a),b&&!c&&(d=instanceOf(a,e)?a.get(b):a[b],c=this.some(function(a){return d===a.get(b)})),!!c},_add:function(a,b){return a=new this._Model(a,this.options.modelOptions),this.hasModel(a)||(a.addEvent("destroy",this.bound("remove")),b=this.length==0?void 0:b,b!=void 0?this._models.splice(b,0,a):this._models.push(a),this.length=this._models.length,this.signalAdd(a)),this},add:function(a,b){a=Array.from(a);var c=a.length,d=0;while(c--)this._add(a[d++],b);return this},get:function(a){var b=arguments.length,c=0,d;if(b>1){d=[];while(b--)d.push(this.get(arguments[c++]));return d}return this._models[a]},_remove:function(a){return this.hasModel(a)&&(a.removeEvent("destroy",this.bound("remove")),this._models.erase(a),this.length=this._models.length,this.signalRemove(a)),this},remove:function(a){a=Array.from(a).slice();var b=a.length,c=0;while(b--)this._remove(a[c++]);return this},replace:function(a,b){var c;return a&&b&&this.hasModel(a)&&!this.hasModel(b)&&(c=this.indexOf(a),c>-1&&(this.add(b,c),this.remove(a))),this},sort:function(a){return this._models.sort(a),this.signalSort(),this},reverse:function(){return this._models.reverse(),this.signalSort(),this},empty:function(){return this.remove(this._models),this.signalEmpty(),this},toJSON:function(){return this.map(function(a){return a.toJSON()})}});["forEach","each","invoke","every","filter","clean","indexOf","map","some","associate","link","contains","getLast","getRandom","flatten","pick"].each(function(a){j.implement(a,function(){return Array.prototype[a].apply(this._models,arguments)})}),c.Collection=j},c:function(a,b,c,d){var e=a("d").View;c.View=e},d:function(a,b,c,d){var e=a("6").Connector,f=a("5").Silence,g=a("9"),h=function(a){return function(){var b=this.options.events,c=this.element;return c&&b&&Object.each(b,function(b,c){var d=Array.from(b),e=d.length,f=0,g;while(e--)g=d[f++],this.element[a](c,typeOf(g)=="function"?g:this.bound(g))},this),this}},i=new Class(g(["ready","render","dispose","destroy"],{signalInject:function(a,b){return!this.isSilent()&&this.fireEvent("inject",[this,a,b]),this}})),j=new Class({Implements:[e,Events,Options,f,i],options:{element:undefined,events:{}},initialize:function(a){this.setOptions(a),this.setup(a),this.signalReady()},setup:function(a){return this.options.element&&this.setElement(this.options.element),this},toElement:function(){return this.element},setElement:function(a){return a&&(this.element&&this.destroy(),a=this.element=document.id(a),a&&this.attachEvents()),this},attachEvents:h("addEvent"),detachEvents:h("removeEvent"),create:function(){return this},render:function(a){return this.signalRender(),this},inject:function(a,b){return this.element&&(a=document.id(a),b=b||"bottom",this.element.inject(a,b),this.signalInject(a,b)),this},dispose:function(){return this.element&&(this.element.dispose(),this.signalDispose()),this},destroy:function(){var a=this.element;return a&&(a&&(this.detachEvents(),a.destroy(),this.element=undefined),this.signalDestroy()),this}});c.View=j}}) | ||
(function(a){var b={},c=function(d){var e=b[d];if(!e){e=b[d]={};var f=e.exports={};a[d].call(f,c,e,f,window)}return e.exports};window.Neuro=c("0")})({0:function(a,b,c,d){var e=a("1");e.Model=a("2").Model,e.Collection=a("b").Collection,e.View=a("d").View,e.Is=a("4").Is,e.Mixins={Butler:a("8").Butler,Connector:a("6").Connector,Silence:a("5").Silence,Snitch:a("f").Snitch},c=b.exports=e},1:function(a,b,c,d){var e={version:"0.2.1"};c=b.exports=e},2:function(a,b,c,d){var e=a("3").Model,f=a("8").Butler,g=a("a").Snitch,h=a("9"),i=function(a){return function(b){var c=this.getAccessor(b,a),d=this._accessorName;return c&&d!=b?c():this.parent(b)}.overloadGetter()};e.implement(new f),e.implement(new g),e.implement(h(["error"],{signalErrorProperty:function(a,b){!this.isSilent()&&this.fireEvent("error:"+a,[this,a,b])}})),c.Model=new Class({Extends:e,_errored:!1,_erroredProperties:{},setup:function(a,b){return this.setupAccessors(),this.setupValidators(),this.parent(a,b),this},__set:function(a,b){var c=this.getAccessor(a,"set");return c&&this._accessorName!=a?c.apply(this,arguments):this.validate(a,b)?this.parent(a,b):(this._errored=!0,this._erroredProperties[a]=b,this)}.overloadSetter(),set:function(a,b){return this.parent(a,b),!this.isSetting()&&this._errored&&(this._onErrorProperty(this._erroredProperties),this.signalError(),this._resetErrored()),this},get:i("get"),getPrevious:i("getPrevious"),_resetErrored:function(){return this._errored&&(this._errored=!1,this._erroredProperties={}),this},_onErrorProperty:function(a,b){return this.signalErrorProperty(a,b),this}.overloadSetter(),setAccessor:function(a,b){return a&&b&&(b.get&&!b.getPrevious&&(b.getPrevious=b.get),this.parent(a,b)),this}.overloadSetter(),proof:function(){return this.parent(this.getData())}})},3:function(a,b,c,d){var e=a("4").Is,f=a("5").Silence,g=a("6").Connector,h=a("8").Butler,i=a("9"),j=function(a){switch(typeOf(a)){case"array":a=a.slice();break;case"object":if(!a.$constructor||a.$constructor&&!instanceOf(a.$constructor,Class))a=Object.clone(a)}return a},k=function(a){return function(b){return this[a][b]}.overloadGetter()},l=function(a){return function(){var b=this.keys(),c={};return b.each(function(b){c[b]=j(this[a](b))}.bind(this)),c}},m=new Class({Implements:[g,h,Events,Options,f],primaryKey:undefined,_data:{},_changed:!1,_changedProperties:{},_previousData:{},_setting:0,options:{primaryKey:undefined,defaults:{}},initialize:function(a,b){if(instanceOf(a,this.constructor))return a;this.setOptions(b),this.setup(a,b)},setup:function(a,b){return this.primaryKey=this.options.primaryKey,this.silence(function(){this.set(this.options.defaults)}.bind(this)),a&&this.set(a),this},__set:function(a,b){var c=this.get(a);return e.Equal(c,b)||(this._changed=!0,this._data[a]=this._changedProperties[a]=j(b)),this}.overloadSetter(),_set:function(a,b){return this._setting++,this.__set(a,b),this._setting--,this},set:function(a,b){var c;return a&&(c=this.isSetting(),!c&&this._setPrevious(this.getData()),a=instanceOf(a,m)?a.getData():a,this._set(a,b),!c&&this._changed&&(this._onChangeProperty(this._changedProperties),this.signalChange(),this._resetChanged())),this},isSetting:function(){return!!this._setting},unset:function(a){var b={},c,d=0,e;a=Array.from(a),c=a.length;while(c--)b[a[d++]]=void 0;return this.set(b),this},reset:function(a){var b={},c=this.options.defaults,d,e=0,f;if(a){a=Array.from(a),d=a.length;while(d--)f=a[e++],b[f]=c[f]}else b=c;return this.set(b),this.signalReset(),this},get:k("_data"),getData:l("get"),_setPrevious:function(a,b){return this._previousData[a]=b,this}.overloadSetter(),getPrevious:k("_previousData"),getPreviousData:l("getPrevious"),_resetChanged:function(){return this._changed&&(this._changed=!1,this._changedProperties={}),this},_onChangeProperty:function(a,b){return this._changed&&this.signalChangeProperty(a,b,this.getPrevious(a)),this}.overloadSetter(),destroy:function(){return this.signalDestroy(),this},toJSON:function(){return this.getData()},spy:function(a,b){return Type.isString(a)&&a in this._data&&Type.isFunction(b)&&this.addEvent("change:"+a,b),this}.overloadSetter(),unspy:function(a,b){return Type.isString(a)&&a in this._data&&this.removeEvents("change:"+a,b),this}.overloadSetter()});m.implement(i(["change","destroy","reset"],{signalChangeProperty:function(a,b,c){return!this.isSilent()&&this.fireEvent("change:"+a,[this,a,b,c]),this}})),["each","subset","map","filter","every","some","keys","values","getLength","keyOf","contains","toQueryString"].each(function(a){m.implement(a,function(){return Object[a].apply(Object,[this._data].append(Array.from(arguments)))})}),c.Model=m},4:function(a,b,c,d){(function(a){var b=Object.prototype.toString,c=Object.prototype.hasOwnProperty,d=window.Type,e=a.Is={},f=window.Type=function(a,b){var c=new d(a,b),g;return c?(g="is"+a,e[a]=e.not[a]=f[g]=d[g],c):c}.extend(d);f.prototype=d.prototype;for(var g in d)f.hasOwnProperty(g)&&g.test("is")&&(g=g.replace("is",""),e[g]=f["is"+g]);e.NaN=function(a){return a!==a},e.Null=function(a){return a===null},e.Undefined=function(a){return a===void 0};var h={string:function(a,b){return a==String(b)},number:function(a,b){return a!=+a?b!=+b:a==0?1/a==1/b:a==+b},date:function(a,b){return+a==+b},"boolean":function(a,b){return this.date(a,b)},regexp:function(a,b){return a.source==b.source&&a.global==b.global&&a.multiline==b.multiline&&a.ignoreCase==b.ignoreCase}},i=function(a,b){return a.hasOwnProperty(b)},j=function(a,b,c){if(a===b)return a!==0||1/a==1/b;if(a==null||b==null)return a===b;if(a.isEqual&&e.Function(a.isEqual))return a.isEqual(b);if(b.isEqual&&e.Function(b.isEqual))return b.isEqual(a);var d=typeOf(a),f=typeOf(b);if(d!=f)return!1;if(h[d])return h[d](a,b);if(d!="object"||f!="object")return!1;var g=c.length;while(g--)if(c[g]==a)return!0;c.push(a);var k=0,l=!0;if(d=="array"){k=a.length,l=k==b.length;if(l)while(k--)if(!(l=k in a==k in b&&j(a[k],b[k],c)))break}else{if("constructor"in a!="constructor"in b||a.constructor!=b.constructor)return!1;for(var m in a)if(i(a,m)){k++;if(!(l=i(b,m)&&j(a[m],b[m],c)))break}if(l){for(m in b)if(i(b,m)&&!(k--))break;l=!k}}return c.pop(),l};e.Equal=function(a,b){return j(a,b,[])},function(a){var b={};for(var c in a)i(a,c)&&(b[c]=function(b){return function(c,d){return!a[b].call(a,c,d)}}(c));a.not=b}(e)})(typeof c!="undefined"?c:window)},5:function(a,b,c,d){var e=new Class({_silent:0,silence:function(a){return this._silent++,a&&a.call(this),this._silent--,this},isSilent:function(){return!!this._silent}});c.Silence=e},6:function(a,b,c,d){a("7");var e=function(a,b,c,d){return a=="string"&&(c=d&&d[c]?d.bound(c):undefined),c},f=function(a,b){var c={};return Object.each(a,function(a,d){d=d=="*"?b:b+":"+d,c[d]=a}),c},g=function(a,b,c){Object.each(b,function(b,d){b=Array.from(b),b.each(function(b){var h=typeOf(b);switch(h){case"object":instanceOf(b,Class)||g.call(this,a,f(b,d),c);break;case"string":case"function":b=e.call(this,h,d,b,c),b&&this[a](d,b)}},this)},this)},h=function(a){var b=a=="connect"?"addEvent":"removeEvent";return function(c,d){var e=this.options.connector;return g.call(this,b,e,c),!d&&c&&c[a](this,!0),this}},i=new Class({Implements:[Class.Binds],options:{connector:{}},connect:h("connect"),disconnect:h("disconnect")});c.Connector=i},7:function(a,b,c,d){Class.Binds=new Class({$bound:{},bound:function(a){return this.$bound[a]?this.$bound[a]:this.$bound[a]=this[a].bind(this)}})},8:function(a,b,c,d){var e=new Class({_accessors:{},_accessorName:undefined,options:{accessors:{}},setupAccessors:function(){var a=this._accessors;return this._accessors={},this.setAccessor(Object.merge({},a,this.options.accessors)),this},isAccessing:function(){return!!this._accessorName},_processAccess:function(a,b){var c;return a&&(this._accessorName=a,c=b(),this._accessorName=void 0),c},setAccessor:function(a,b){var c={};return!!a&&Type.isObject(b)&&(Object.each(b,function(b,d){var e=b;b._orig||(b=function(){return this._processAccess(a,e.pass(arguments,this))}.bind(this),b._orig=e),c[d]=b},this),this._accessors[a]=c),this}.overloadSetter(),getAccessor:function(a,b){var c=this._accessors[a];return b?c&&c[b]:c},unsetAccessor:function(a,b){return a&&(b?this._accessors[a][b]=void 0:this._accessors[a]=void 0),this}});c.Butler=e},9:function(a,b,c,d){c=b.exports=function(a,b,c){return Type.isFunction(b)||(c=b,b=undefined),c=c||{},Array.from(a).each(function(a){c["signal"+a.capitalize()]=b?b(a):function(){return!this.isSilent()&&this.fireEvent(a,this),this}}),c}},a:function(a,b,c,d){var e=new Class({_validators:{},options:{validators:{}},setupValidators:function(){var a=this._validators;return this._validators={},this.setValidator(Object.merge({},a,this.options.validators)),this},setValidator:function(a,b){var c=b;return b._orig||(b=b.bind(this),b._orig=c),this._validators[a]=b,this}.overloadSetter(),getValidator:function(a){return this._validators[a]}.overloadGetter(),validate:function(a,b){var c=this.getValidator(a),d=!0;return c&&(d=c(b)),d},proof:function(a){return e.proof(a,this._validators,this)}});e.proof=function(a,b){return Object.every(b,function(b,c){return c in a&&b(a[c])})},c.Snitch=e},b:function(a,b,c,d){var e=a("c").Collection,f=a("2").Model,g=a("a").Snitch,h=function(a,b){return this.parent(b,a)};e.implement(new g),c.Collection=new Class({Extends:e,setup:function(a,b){return this.setupValidators(),this.parent(a,b),this},_add:function(a,b){return this.validate(instanceOf(a,f)?a.getData():a)?this.parent(a,b):this.signalError(a,b),this},validate:function(a){return a=Array.from(a),a.every(function(a){return instanceOf(a,f)?a.every(h,this):Object.every(a,h,this)},this)},proofModel:function(a){return a=Array.from(a),a.every(function(a){return g.proof(instanceOf(a,f)?a.getData():a,this._validators,this)},this)},proof:function(){return this.proofModel(this._models)},signalError:function(a,b){!this.isSilent()&&this.fireEvent("error",[this,a,b])}})},c:function(a,b,c,d){var e=a("2").Model,f=a("5").Silence,g=a("6").Connector,h=a("9"),i=new Class({Implements:[g,Events,Options,f],_models:[],_Model:e,length:0,primaryKey:undefined,options:{primaryKey:undefined,Model:undefined,modelOptions:undefined},initialize:function(a,b){this.setOptions(b),this.setup(a,b)},setup:function(a,b){return this.primaryKey=this.options.primaryKey,this.options.Model&&(this._Model=this.options.Model),a&&this.add(a),this},hasModel:function(a){var b=this.primaryKey,c,d;return c=this._models.contains(a),b&&!c&&(d=instanceOf(a,e)?a.get(b):a[b],c=this.some(function(a){return d===a.get(b)})),!!c},_add:function(a,b){return a=new this._Model(a,this.options.modelOptions),this.hasModel(a)||(a.addEvent("destroy",this.bound("remove")),b=this.length==0?void 0:b,b!=void 0?this._models.splice(b,0,a):this._models.push(a),this.length=this._models.length,this.signalAdd(a)),this},add:function(a,b){a=Array.from(a);var c=a.length,d=0;while(c--)this._add(a[d++],b);return this},get:function(a){var b=arguments.length,c=0,d;if(b>1){d=[];while(b--)d.push(this.get(arguments[c++]));return d}return this._models[a]},_remove:function(a){return this.hasModel(a)&&(a.removeEvent("destroy",this.bound("remove")),this._models.erase(a),this.length=this._models.length,this.signalRemove(a)),this},remove:function(a){a=Array.from(a).slice();var b=a.length,c=0;while(b--)this._remove(a[c++]);return this},replace:function(a,b){var c;return a&&b&&this.hasModel(a)&&!this.hasModel(b)&&(c=this.indexOf(a),c>-1&&(this.add(b,c),this.remove(a))),this},sort:function(a){return this._models.sort(a),this.signalSort(),this},reverse:function(){return this._models.reverse(),this.signalSort(),this},empty:function(){return this.remove(this._models),this.signalEmpty(),this},toJSON:function(){return this.map(function(a){return a.toJSON()})}});i.implement(h(["empty","sort"],h(["add","remove"],function(a){return function(b){return!this.isSilent()&&this.fireEvent(a,[this,b]),this}}))),["forEach","each","invoke","every","filter","clean","indexOf","map","some","associate","link","contains","getLast","getRandom","flatten","pick"].each(function(a){i.implement(a,function(){return Array.prototype[a].apply(this._models,arguments)})}),c.Collection=i},d:function(a,b,c,d){var e=a("e").View;c.View=e},e:function(a,b,c,d){var e=a("6").Connector,f=a("5").Silence,g=a("9"),h=function(a){return function(){var b=this.options.events,c=this.element;return c&&b&&Object.each(b,function(b,c){var d=Array.from(b),e=d.length,f=0,g;while(e--)g=d[f++],this.element[a](c,typeOf(g)=="function"?g:this.bound(g))},this),this}},i=new Class(g(["ready","render","dispose","destroy"],{signalInject:function(a,b){return!this.isSilent()&&this.fireEvent("inject",[this,a,b]),this}})),j=new Class({Implements:[e,Events,Options,f,i],options:{element:undefined,events:{}},initialize:function(a){this.setOptions(a),this.setup(a),this.signalReady()},setup:function(a){return this.options.element&&this.setElement(this.options.element),this},toElement:function(){return this.element},setElement:function(a){return a&&(this.element&&this.destroy(),a=this.element=document.id(a),a&&this.attachEvents()),this},attachEvents:h("addEvent"),detachEvents:h("removeEvent"),create:function(){return this},render:function(a){return this.signalRender(),this},inject:function(a,b){return this.element&&(a=document.id(a),b=b||"bottom",this.element.inject(a,b),this.signalInject(a,b)),this},dispose:function(){return this.element&&(this.element.dispose(),this.signalDispose()),this},destroy:function(){var a=this.element;return a&&(a&&(this.detachEvents(),a.destroy(),this.element=undefined),this.signalDestroy()),this}});c.View=j},f:function(a,b,c,d){var e=new Class({_validators:{},options:{validators:{}},setupValidators:function(){var a=this._validators;return this._validators={},this.setValidator(Object.merge({},a,this.options.validators)),this},setValidator:function(a,b){var c=b;return b._orig||(b=b.bind(this),b._orig=c),this._validators[a]=b,this}.overloadSetter(),getValidator:function(a){return this._validators[a]}.overloadGetter(),validate:function(a,b){var c=this.getValidator(a),d=!0;return c&&(d=c(b)),d},proof:function(a){return e.proof(a,this._validators,this)}});e.proof=function(a,b){return Object.every(b,function(b,c){return c in a&&b(a[c])})},c.Snitch=e}}) |
240
neuro.js
@@ -16,4 +16,11 @@ (function(modules) { | ||
Neuro.Model = require("2").Model; | ||
Neuro.Collection = require("a").Collection; | ||
Neuro.View = require("c").View; | ||
Neuro.Collection = require("b").Collection; | ||
Neuro.View = require("d").View; | ||
Neuro.Is = require("4").Is; | ||
Neuro.Mixins = { | ||
Butler: require("8").Butler, | ||
Connector: require("6").Connector, | ||
Silence: require("5").Silence, | ||
Snitch: require("f").Snitch | ||
}; | ||
exports = module.exports = Neuro; | ||
@@ -28,3 +35,3 @@ }, | ||
"2": function(require, module, exports, global) { | ||
var Model = require("3").Model, Butler = require("8").Butler; | ||
var Model = require("3").Model, Butler = require("8").Butler, Snitch = require("a").Snitch, signalFactory = require("9"); | ||
var curryGetter = function(type) { | ||
@@ -40,6 +47,15 @@ return function(prop) { | ||
Model.implement(new Butler); | ||
Model.implement(new Snitch); | ||
Model.implement(signalFactory([ "error" ], { | ||
signalErrorProperty: function(prop, val) { | ||
!this.isSilent() && this.fireEvent("error:" + prop, [ this, prop, val ]); | ||
} | ||
})); | ||
exports.Model = new Class({ | ||
Extends: Model, | ||
_errored: false, | ||
_erroredProperties: {}, | ||
setup: function(data, options) { | ||
this.setupAccessors(); | ||
this.setupValidators(); | ||
this.parent(data, options); | ||
@@ -53,6 +69,31 @@ return this; | ||
} | ||
if (!this.validate(prop, val)) { | ||
this._errored = true; | ||
this._erroredProperties[prop] = val; | ||
return this; | ||
} | ||
return this.parent(prop, val); | ||
}.overloadSetter(), | ||
set: function(prop, val) { | ||
this.parent(prop, val); | ||
if (!this.isSetting() && this._errored) { | ||
this._onErrorProperty(this._erroredProperties); | ||
this.signalError(); | ||
this._resetErrored(); | ||
} | ||
return this; | ||
}, | ||
get: curryGetter("get"), | ||
getPrevious: curryGetter("getPrevious"), | ||
_resetErrored: function() { | ||
if (this._errored) { | ||
this._errored = false; | ||
this._erroredProperties = {}; | ||
} | ||
return this; | ||
}, | ||
_onErrorProperty: function(prop, val) { | ||
this.signalErrorProperty(prop, val); | ||
return this; | ||
}.overloadSetter(), | ||
setAccessor: function(name, val) { | ||
@@ -66,3 +107,6 @@ if (name && val) { | ||
return this; | ||
}.overloadSetter() | ||
}.overloadSetter(), | ||
proof: function() { | ||
return this.parent(this.getData()); | ||
} | ||
}); | ||
@@ -99,10 +143,4 @@ }, | ||
}; | ||
var Signals = new Class(signalFactory([ "change", "destroy", "reset" ], { | ||
signalChangeProperty: function(prop, newVal, oldVal) { | ||
!this.isSilent() && this.fireEvent("change:" + prop, [ this, prop, newVal, oldVal ]); | ||
return this; | ||
} | ||
})); | ||
var Model = new Class({ | ||
Implements: [ Connector, Butler, Events, Options, Silence, Signals ], | ||
Implements: [ Connector, Butler, Events, Options, Silence ], | ||
primaryKey: undefined, | ||
@@ -156,5 +194,5 @@ _data: {}, | ||
this._set(prop, val); | ||
if (!isSetting) { | ||
this.changeProperty(this._changedProperties); | ||
this.change(); | ||
if (!isSetting && this._changed) { | ||
this._onChangeProperty(this._changedProperties); | ||
this.signalChange(); | ||
this._resetChanged(); | ||
@@ -209,10 +247,4 @@ } | ||
}, | ||
change: function() { | ||
_onChangeProperty: function(prop, val) { | ||
if (this._changed) { | ||
this.signalChange(); | ||
} | ||
return this; | ||
}, | ||
changeProperty: function(prop, val) { | ||
if (this._changed) { | ||
this.signalChangeProperty(prop, val, this.getPrevious(prop)); | ||
@@ -242,2 +274,8 @@ } | ||
}); | ||
Model.implement(signalFactory([ "change", "destroy", "reset" ], { | ||
signalChangeProperty: function(prop, newVal, oldVal) { | ||
!this.isSilent() && this.fireEvent("change:" + prop, [ this, prop, newVal, oldVal ]); | ||
return this; | ||
} | ||
})); | ||
[ "each", "subset", "map", "filter", "every", "some", "keys", "values", "getLength", "keyOf", "contains", "toQueryString" ].each(function(method) { | ||
@@ -446,3 +484,5 @@ Model.implement(method, function() { | ||
setupAccessors: function() { | ||
this.setAccessor(Object.merge({}, this._accessors, this.options.accessors)); | ||
var accessors = this._accessors; | ||
this._accessors = {}; | ||
this.setAccessor(Object.merge({}, accessors, this.options.accessors)); | ||
return this; | ||
@@ -466,9 +506,10 @@ }, | ||
Object.each(obj, function(fnc, type) { | ||
var f; | ||
if (fnc && !accessors[type]) { | ||
f = accessors[type] = function() { | ||
return this._processAccess(name, fnc.pass(arguments, this)); | ||
var orig = fnc; | ||
if (!fnc._orig) { | ||
fnc = function() { | ||
return this._processAccess(name, orig.pass(arguments, this)); | ||
}.bind(this); | ||
f._orig = fnc; | ||
fnc._orig = orig; | ||
} | ||
accessors[type] = fnc; | ||
}, this); | ||
@@ -516,15 +557,88 @@ this._accessors[name] = accessors; | ||
a: function(require, module, exports, global) { | ||
var Collection = require("b").Collection; | ||
exports.Collection = Collection; | ||
var Snitch = new Class({ | ||
_validators: {}, | ||
options: { | ||
validators: {} | ||
}, | ||
setupValidators: function() { | ||
var validators = this._validators; | ||
this._validators = {}; | ||
this.setValidator(Object.merge({}, validators, this.options.validators)); | ||
return this; | ||
}, | ||
setValidator: function(prop, fnc) { | ||
var orig = fnc; | ||
if (!fnc._orig) { | ||
fnc = fnc.bind(this); | ||
fnc._orig = orig; | ||
} | ||
this._validators[prop] = fnc; | ||
return this; | ||
}.overloadSetter(), | ||
getValidator: function(prop) { | ||
return this._validators[prop]; | ||
}.overloadGetter(), | ||
validate: function(prop, val) { | ||
var validator = this.getValidator(prop), pass = true; | ||
if (validator) { | ||
pass = validator(val); | ||
} | ||
return pass; | ||
}, | ||
proof: function(obj) { | ||
return Snitch.proof(obj, this._validators, this); | ||
} | ||
}); | ||
Snitch.proof = function(obj, validators) { | ||
return Object.every(validators, function(fnc, prop) { | ||
return prop in obj && fnc(obj[prop]); | ||
}); | ||
}; | ||
exports.Snitch = Snitch; | ||
}, | ||
b: function(require, module, exports, global) { | ||
var Collection = require("c").Collection, Model = require("2").Model, Snitch = require("a").Snitch; | ||
var validateFnc = function(val, prop) { | ||
return this.parent(prop, val); | ||
}; | ||
Collection.implement(new Snitch); | ||
exports.Collection = new Class({ | ||
Extends: Collection, | ||
setup: function(models, options) { | ||
this.setupValidators(); | ||
this.parent(models, options); | ||
return this; | ||
}, | ||
_add: function(model, at) { | ||
if (!this.validate(instanceOf(model, Model) ? model.getData() : model)) { | ||
this.signalError(model, at); | ||
} else { | ||
this.parent(model, at); | ||
} | ||
return this; | ||
}, | ||
validate: function(models) { | ||
models = Array.from(models); | ||
return models.every(function(model) { | ||
return instanceOf(model, Model) ? model.every(validateFnc, this) : Object.every(model, validateFnc, this); | ||
}, this); | ||
}, | ||
proofModel: function(models) { | ||
models = Array.from(models); | ||
return models.every(function(model) { | ||
return Snitch.proof(instanceOf(model, Model) ? model.getData() : model, this._validators, this); | ||
}, this); | ||
}, | ||
proof: function() { | ||
return this.proofModel(this._models); | ||
}, | ||
signalError: function(model, at) { | ||
!this.isSilent() && this.fireEvent("error", [ this, model, at ]); | ||
} | ||
}); | ||
}, | ||
c: function(require, module, exports, global) { | ||
var Model = require("2").Model, Silence = require("5").Silence, Connector = require("6").Connector, signalFactory = require("9"); | ||
var Signals = new Class(signalFactory([ "empty", "sort" ], signalFactory([ "add", "remove" ], function(name) { | ||
return function(model) { | ||
!this.isSilent() && this.fireEvent(name, [ this, model ]); | ||
return this; | ||
}; | ||
}))); | ||
var Collection = new Class({ | ||
Implements: [ Connector, Events, Options, Silence, Signals ], | ||
Implements: [ Connector, Events, Options, Silence ], | ||
_models: [], | ||
@@ -647,2 +761,8 @@ _Model: Model, | ||
}); | ||
Collection.implement(signalFactory([ "empty", "sort" ], signalFactory([ "add", "remove" ], function(name) { | ||
return function(model) { | ||
!this.isSilent() && this.fireEvent(name, [ this, model ]); | ||
return this; | ||
}; | ||
}))); | ||
[ "forEach", "each", "invoke", "every", "filter", "clean", "indexOf", "map", "some", "associate", "link", "contains", "getLast", "getRandom", "flatten", "pick" ].each(function(method) { | ||
@@ -655,7 +775,7 @@ Collection.implement(method, function() { | ||
}, | ||
c: function(require, module, exports, global) { | ||
var View = require("d").View; | ||
d: function(require, module, exports, global) { | ||
var View = require("e").View; | ||
exports.View = View; | ||
}, | ||
d: function(require, module, exports, global) { | ||
e: function(require, module, exports, global) { | ||
var Connector = require("6").Connector, Silence = require("5").Silence, signalFactory = require("9"); | ||
@@ -748,3 +868,45 @@ var eventHandler = function(handler) { | ||
exports.View = View; | ||
}, | ||
f: function(require, module, exports, global) { | ||
var Snitch = new Class({ | ||
_validators: {}, | ||
options: { | ||
validators: {} | ||
}, | ||
setupValidators: function() { | ||
var validators = this._validators; | ||
this._validators = {}; | ||
this.setValidator(Object.merge({}, validators, this.options.validators)); | ||
return this; | ||
}, | ||
setValidator: function(prop, fnc) { | ||
var orig = fnc; | ||
if (!fnc._orig) { | ||
fnc = fnc.bind(this); | ||
fnc._orig = orig; | ||
} | ||
this._validators[prop] = fnc; | ||
return this; | ||
}.overloadSetter(), | ||
getValidator: function(prop) { | ||
return this._validators[prop]; | ||
}.overloadGetter(), | ||
validate: function(prop, val) { | ||
var validator = this.getValidator(prop), pass = true; | ||
if (validator) { | ||
pass = validator(val); | ||
} | ||
return pass; | ||
}, | ||
proof: function(obj) { | ||
return Snitch.proof(obj, this._validators, this); | ||
} | ||
}); | ||
Snitch.proof = function(obj, validators) { | ||
return Object.every(validators, function(fnc, prop) { | ||
return prop in obj && fnc(obj[prop]); | ||
}); | ||
}; | ||
exports.Snitch = Snitch; | ||
} | ||
}); |
{ | ||
"name": "Neuro", | ||
"description": "A MVC written with MooTools.", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"license": "MIT (http://mootools.net/license.txt)", | ||
@@ -6,0 +6,0 @@ "main": "src/main.js", |
257
README.md
@@ -6,3 +6,3 @@ Neuro | ||
__Version: 0.2.1 (Alpha)__ | ||
__Version: 0.2.2 (Alpha)__ | ||
@@ -40,2 +40,3 @@ [![Build Status](https://secure.travis-ci.org/GCheung55/Neuro.png)](http://travis-ci.org/GCheung55/Neuro) | ||
* [Mixin: Silence](#mixin-silence) | ||
* [Mixin: Snitch](#mixin-snitch) | ||
@@ -65,2 +66,4 @@ ### constructor (initialize) | ||
* `reset: function(model){}` - Triggered when the model is reset to its default values. | ||
* `error: function(model){}` - Triggered when the model data does not validate during the setting process. | ||
* `error:key: function(model, key, value){}` - Triggered when a specific model data property does not validate during the setting process. | ||
@@ -310,2 +313,29 @@ #### Notes: | ||
### setupValidators | ||
--- | ||
see [Mixin: Snitch](#mixin-snitch) | ||
### setValidator | ||
--- | ||
see [Mixin: Snitch](#mixin-snitch) | ||
### getValidator | ||
--- | ||
see [Mixin: Snitch](#mixin-snitch) | ||
### validate | ||
--- | ||
see [Mixin: Snitch](#mixin-snitch) | ||
### proof | ||
--- | ||
Method that proofs the model instance. | ||
see [Mixin: Snitch](#mixin-snitch) | ||
#### Syntax: | ||
```javascript | ||
model.proof(); | ||
``` | ||
#### Returns: (Boolean) Every property in the `_validators` object must exist in the model instances `_data` object and every function in `_validators` must return `true` in order for `proof` to return `true`, otherwise `false`. | ||
#### Note: This overrides the original `proof` method, but makes use of it to "proof" the model instance. | ||
### connect | ||
@@ -397,2 +427,3 @@ --- | ||
* [Mixin: Silence](#mixin-silence) | ||
* [Mixin: Snitch](#mixin-snitch) | ||
@@ -425,2 +456,3 @@ ### constructor (initialize) | ||
* `sort: function(collection){}` - Triggered when `sort` or `reverse` occurs. | ||
* `error: function(collection, model, at){}` - Triggered when a model is added to the collection that does not pass validation IF validators exist in the collection instance. | ||
@@ -450,4 +482,12 @@ #### Notes: | ||
--- | ||
Adding a model to the collection should always go through this method. It appends the model to the internal `_model` array and triggers the `add` event if the collection does not already contain the model. If an `Object` is passed in, the `Object` will be converted to a model instance before being appended to `_model`. Adding a model will increase the collections `length` property. It is possible to insert a model instance into `_model` at a specific index by passing a second argument to `add`. A `remove` method is attached to the models `destroy` event so that the model can be properly removed if the model `destroy` event is triggered. | ||
Adding a model to the collection should always go through this method. It appends the model to the internal `_model` array and triggers the `add` event if the collection does not already contain the model. | ||
If `_validators` exist, then each model or object added must pass validation in order to be added to the collection instance. Otherwise a `error` event will be triggered. | ||
If an `Object` is passed in, the `Object` will be converted to a model instance before being appended to `_model`. Adding a model will increase the collections `length` property. | ||
It is possible to insert a model instance into `_model` at a specific index by passing a second argument to `add`. | ||
A `remove` method is attached to the models `destroy` event so that the model can be properly removed if the model `destroy` event is triggered. | ||
#### Syntax: | ||
@@ -469,2 +509,3 @@ ```javascript | ||
* `add` | ||
# `error` | ||
@@ -624,2 +665,55 @@ #### Examples: | ||
### setupValidators | ||
--- | ||
see [Mixin: Snitch](#mixin-snitch) | ||
### setValidator | ||
--- | ||
see [Mixin: Snitch](#mixin-snitch) | ||
### getValidator | ||
--- | ||
see [Mixin: Snitch](#mixin-snitch) | ||
### validate | ||
--- | ||
Validate every property in a model that is passed into `validate`. | ||
see [Mixin: Snitch](#mixin-snitch) | ||
#### Syntax: | ||
```javascript | ||
collection.validate(models); | ||
``` | ||
#### Arguments: | ||
1. models - (Object | Model | Array) An object, a model instance, or an array mix of both to be validated. | ||
#### Returns: (Boolean) True if all properties in the models validate, false otherwise. | ||
### proofModel | ||
--- | ||
Proof every property in the models that are passed into `proofModel`. Every validator property needs to exist in the model and every validator function must return `true` in order for `proofModel` to return `true`. | ||
#### Syntax: | ||
```javascript | ||
collection.proofModel(models); | ||
``` | ||
#### Arguments: | ||
1. model - (Object | Model | Array) An object, a model instance, or an array mix of both to be proofed. | ||
#### Returns: (Boolean) True if all properties in the models proof, false otherwise. | ||
### proof | ||
--- | ||
Method that proofs the models in the collection instance. | ||
see [Mixin: Snitch](#mixin-snitch) | ||
#### Syntax: | ||
```javascript | ||
collection.proof(); | ||
``` | ||
#### Returns: (Boolean) | ||
#### Note: This overrides the original `proof` method, but makes use of it to "proof" the collections models. | ||
### addEvent | ||
@@ -1234,2 +1328,3 @@ --- | ||
A Utility Class. It provides a way to define custom setters/getters on a Class. | ||
### options.accessors | ||
@@ -1255,3 +1350,3 @@ --- | ||
--- | ||
Existing accessors in `_accessors` need to be decorated so they are merged with `options.accessors` before being sent to `setAccessor`. | ||
Existing accessors in `_accessors` are merged with `options.accessors` before being sent to `setAccessor`. This should be called in the `initailize` or `setup` method. | ||
@@ -1278,3 +1373,3 @@ #### Syntax: | ||
--- | ||
A method to decorate custom setters/getters that will allow the use of `isAccessing` to prevent recursive calls to the same custom setter/getter. | ||
A method to decorate custom setters/getters that will allow the use of `isAccessing` to prevent recursive calls to the same custom setter/getter. The decorated custom setters/getters is an object of name/function pairs that is stored in `_accessors` by name. | ||
@@ -1313,2 +1408,5 @@ #### Syntax: | ||
// manually executed because klass doesn't have an initialize or setup method to execute setupAccessors. | ||
currentClass.setupAccessors(); | ||
var fullNameAccessor = currentClass.getAccessor('fullName'); | ||
@@ -1393,3 +1491,3 @@ | ||
## Mixin: Silent | ||
__Silent__ is a MooTools Class object without a constructor. It is used as a mixin for other Class objects, providing a solution to disable before a function executes, and re-enabling afterwards. | ||
A Utility Class. It provides a solution to disable before a function executes, and re-enabling afterwards. | ||
@@ -1420,1 +1518,150 @@ ### isSilent | ||
#### Returns: Class instance. | ||
## Mixin: Snitch | ||
--- | ||
A Utility Class. Use this class to set/get validator functions. A `validate` method offers a way to easily retrieve a validator to test a value. A `proof` method is a simple object spec test that tests an object for existence of keys and runs validation tests on the values of those keys. | ||
### options.validators | ||
--- | ||
A key/value object where the key is the property name and value is a function. The function will be passed an argument to test against and should return a boolean. | ||
### Syntax: key/value pairs | ||
```javascript | ||
{ | ||
name: function, | ||
name: function | ||
} | ||
``` | ||
#### Arguments | ||
1. name - (String) Name of the validator function | ||
2. function - (Function) The function will be passed an argument to test against and should return a `Boolean` | ||
### setupValidators | ||
--- | ||
Existing validators in `_validators` are merged with `options.validators` to be attached by `setValidator`. This should be called in the `initailize` or `setup` method. | ||
#### Syntax: | ||
```javascript | ||
currentClass.setupValidators(); | ||
``` | ||
#### Returns: Class instance. | ||
### setValidator | ||
--- | ||
Set functions by property. The function will be decorated to be bound to the class instance. | ||
#### Syntax: | ||
```javascript | ||
currentClass.setValidator(name, function) | ||
currentClass.setValidator(obj); | ||
``` | ||
#### Arguments: | ||
* Two Arugments: | ||
1. name - (String) Name of the validator. | ||
2. function - (Function) The validation function to test against a passed parameter. | ||
* One Argument: | ||
1. obj - (Object) Name/function object. | ||
#### Returns: Class instance. | ||
#### Note: The original undecorated function is stored on the decorated function in the `_orig` attribute. | ||
#### Example: | ||
```javascript | ||
var klass = new Class({ | ||
Implements: Snitch, | ||
options: { | ||
validators: { | ||
fullName: Type.isString // Type.isString is a method in MooTools-Core that tests arguments whether they are strings or not by returning a boolean | ||
} | ||
} | ||
}); | ||
var currentClass = new klass(); | ||
// manually executed because klass doesn't have an initialize or setup method to execute setupValidators. | ||
currentClass.setupValidators(); | ||
// returns the validation function | ||
var fullNameValidator = currentClass.getValidator('fullName'); | ||
// the undecorated original function | ||
fullNameValidator._orig; | ||
``` | ||
### getValidator | ||
--- | ||
Retrieve a stored validation function by property name. | ||
#### Syntax: | ||
```javascript | ||
currentClass.getValidator(name[, name]); | ||
``` | ||
#### Arguments | ||
1. name - (String) The name of the validator to return. Consecutive names will return an object of name/function matches. | ||
#### Returns: | ||
* More than One Consecutive Argument | ||
* (Object) Name/function pairs containing matches validator functions and their corresponding names. An unexisting validator will return `undefined` in place of the function. | ||
* One argument | ||
* (Function) Validation function corresponding to the name. | ||
#### Example: | ||
```javascript | ||
currentClass.getValidator('fullName'); // returns function or undefined | ||
currentClass.getValidator('age', 'fullName'); // returns an object containing age and fullName properties | ||
``` | ||
### validate | ||
--- | ||
Convenient method to retrieve a validator by property to test the value against. By default it always returns true. If a validator exists, it returns the results of validation. | ||
#### Syntax: | ||
```javascript | ||
currentClass.validate(property, value); | ||
``` | ||
#### Arguments: | ||
1. property - (String) Name of the validator to retrieve. | ||
2. value - (Mixed) Value to validate by the retrieved validator. | ||
#### Returns: | ||
* (Boolean) Value of whether validation has passed or not. | ||
### proof | ||
--- | ||
"Proof" an object where every item that exists in `_validators` exists in the object and every validation function returns a `true` value. This causes `_validators` to act like a spec. By default, `proof` returns true in case there are no defined validators. It is a convenient method that utilizes `Snitch Function: proof`; | ||
#### Syntax: | ||
```javascript | ||
currentClass.proof(obj); | ||
``` | ||
#### Arguments: | ||
1. obj - (Object) The object that will be tested against every validator in `_validators`. Every property in `_validators` just exist in obj and every function must pass in order for proof to return true. | ||
#### Returns: | ||
* (Boolean) Value of whether the object has passed validation and item existence. | ||
### Snitch Function: proof | ||
--- | ||
Generic method to proof an object with validators. | ||
#### Syntax: | ||
```javascript | ||
Snitch.proof(obj, validators); | ||
``` | ||
#### Arguments: | ||
1. obj - (Object) Object of key/value pairs that will be compared against`validators` | ||
2. validators - (Object) Object of key/function pairs that will be used to compare against `obj` where each key has to exist in the `obj` and the `obj` property value passes the validator function. | ||
#### Returns: | ||
* (Boolean) Value of whether the object has passed validation and item existence. |
@@ -6,19 +6,4 @@ var Model = require('../model/main').Model, | ||
var Signals = new Class( | ||
signalFactory( | ||
['empty', 'sort'], | ||
signalFactory( | ||
['add', 'remove'], | ||
function(name){ | ||
return function(model){ | ||
!this.isSilent() && this.fireEvent(name, [this, model]); | ||
return this; | ||
}; | ||
} | ||
) | ||
) | ||
); | ||
var Collection = new Class({ | ||
Implements: [Connector, Events, Options, Silence, Signals], | ||
Implements: [Connector, Events, Options, Silence], | ||
@@ -46,3 +31,3 @@ _models: [], | ||
this.setOptions(options); | ||
this.setup(models, options); | ||
@@ -259,2 +244,17 @@ }, | ||
Collection.implement( | ||
signalFactory( | ||
['empty', 'sort'], | ||
signalFactory( | ||
['add', 'remove'], | ||
function(name){ | ||
return function(model){ | ||
!this.isSilent() && this.fireEvent(name, [this, model]); | ||
return this; | ||
}; | ||
} | ||
) | ||
) | ||
); | ||
['forEach', 'each', 'invoke', 'every', 'filter', 'clean', 'indexOf', 'map', 'some', 'associate', 'link', 'contains', 'getLast', 'getRandom', 'flatten', 'pick'].each(function(method){ | ||
@@ -261,0 +261,0 @@ Collection.implement(method, function(){ |
@@ -1,3 +0,80 @@ | ||
var Collection = require('./collection').Collection; | ||
var Collection = require('./collection').Collection, | ||
Model = require('../model/main').Model, | ||
Snitch = require('../../mixins/snitch').Snitch; | ||
exports.Collection = Collection; | ||
var validateFnc = function(val, prop){ | ||
return this.parent(prop, val); | ||
}; | ||
Collection.implement(new Snitch); | ||
exports.Collection = new Class({ | ||
Extends: Collection, | ||
setup: function(models, options){ | ||
this.setupValidators(); | ||
this.parent(models, options); | ||
return this; | ||
}, | ||
_add: function(model, at){ | ||
/** | ||
* Validate data, not a model instance. | ||
*/ | ||
if (!this.validate( instanceOf(model, Model) ? model.getData() : model )) { | ||
this.signalError(model, at); | ||
} else { | ||
this.parent(model, at) | ||
} | ||
return this | ||
}, | ||
/** | ||
* Validate every property in a model | ||
* @param {Object | Model | Array} models An object, a model instance, or an array mix of both to be validated | ||
* @return {Boolean} True if all properties in the models validate | ||
*/ | ||
validate: function(models){ | ||
models = Array.from(models); | ||
return models.every(function(model){ | ||
return instanceOf(model, Model) | ||
? model.every(validateFnc, this) | ||
: Object.every(model, validateFnc, this); | ||
}, this); | ||
}, | ||
/** | ||
* Proof every property in the models. Every validator property needs to exist in the model | ||
* | ||
* @param {Object | Model | Array} models An object, a model instance, or an array mix of both to be proofed | ||
* @return {Boolean} True if all properties in the models proof, false otherwise. | ||
*/ | ||
proofModel: function(models){ | ||
models = Array.from(models); | ||
return models.every(function(model){ | ||
return Snitch.proof( | ||
instanceOf(model, Model) | ||
? model.getData() | ||
: model, | ||
this._validators, this | ||
); | ||
}, this); | ||
}, | ||
/** | ||
* Proof every model in the collection | ||
* @return {Boolean} True if all properties in the collection's models proof, false otherwise. | ||
*/ | ||
proof: function(){ | ||
return this.proofModel(this._models); | ||
}, | ||
signalError: function(model, at){ | ||
!this.isSilent() && this.fireEvent('error', [this, model, at]); | ||
} | ||
}); |
@@ -7,2 +7,12 @@ var Neuro = require('./Neuro'); | ||
Neuro.Is = require('neuro-is').Is; | ||
//Mixins | ||
Neuro.Mixins = { | ||
Butler: require('../mixins/butler').Butler, | ||
Connector: require('../mixins/connector').Connector, | ||
Silence: require('../mixins/silence').Silence, | ||
Snitch: require('../mixins/Snitch').Snitch | ||
}; | ||
exports = module.exports = Neuro; |
var Model = require('./model').Model, | ||
Butler = require('../../mixins/butler').Butler; | ||
Butler = require('../../mixins/butler').Butler, | ||
Snitch = require('../../mixins/snitch').Snitch, | ||
signalFactory = require('../../utils/signalFactory'); | ||
@@ -30,2 +32,13 @@ /** | ||
Model.implement(new Butler); | ||
Model.implement(new Snitch); | ||
Model.implement( | ||
signalFactory( | ||
['error'], | ||
{ | ||
signalErrorProperty: function(prop, val){ | ||
!this.isSilent() && this.fireEvent('error:' + prop, [this, prop, val]); | ||
} | ||
} | ||
) | ||
); | ||
@@ -35,5 +48,11 @@ exports.Model = new Class({ | ||
_errored: false, | ||
_erroredProperties: {}, | ||
setup: function(data, options){ | ||
this.setupAccessors(); | ||
this.setupValidators(); | ||
this.parent(data, options); | ||
@@ -59,5 +78,32 @@ | ||
/** | ||
* Validate the property value. validate method will | ||
* check for existence of a a validator | ||
*/ | ||
if (!this.validate(prop, val)) { | ||
this._errored = true; | ||
this._erroredProperties[prop] = val; | ||
return this; | ||
} | ||
return this.parent(prop, val); | ||
}.overloadSetter(), | ||
set: function(prop, val){ | ||
this.parent(prop, val); | ||
if (!this.isSetting() && this._errored) { | ||
// Signal any errored properties | ||
this._onErrorProperty(this._erroredProperties); | ||
// Signal error | ||
this.signalError(); | ||
// reset errored and errored properties | ||
this._resetErrored(); | ||
} | ||
return this; | ||
}, | ||
get: curryGetter('get'), | ||
@@ -67,2 +113,20 @@ | ||
_resetErrored: function(){ | ||
if (this._errored) { | ||
// reset the errored | ||
this._errored = false; | ||
// reset errored properties | ||
this._erroredProperties = {}; | ||
} | ||
return this; | ||
}, | ||
_onErrorProperty: function(prop, val){ | ||
this.signalErrorProperty(prop, val); | ||
return this; | ||
}.overloadSetter(), | ||
setAccessor: function(name, val){ | ||
@@ -88,3 +152,7 @@ if (name && val) { | ||
return this; | ||
}.overloadSetter() | ||
}.overloadSetter(), | ||
proof: function(){ | ||
return this.parent(this.getData()); | ||
} | ||
}); |
@@ -44,16 +44,4 @@ // (function(context){ | ||
var Signals = new Class( | ||
signalFactory( | ||
['change', 'destroy', 'reset'], | ||
{ | ||
signalChangeProperty: function(prop, newVal, oldVal){ | ||
!this.isSilent() && this.fireEvent('change:' + prop, [this, prop, newVal, oldVal]); | ||
return this; | ||
} | ||
} | ||
) | ||
); | ||
var Model = new Class({ | ||
Implements: [Connector, Butler, Events, Options, Silence, Signals], | ||
Implements: [Connector, Butler, Events, Options, Silence], | ||
@@ -169,8 +157,8 @@ primaryKey: undefined, | ||
if (!isSetting) { | ||
if (!isSetting && this._changed) { | ||
// Signal any changed properties | ||
this.changeProperty(this._changedProperties); | ||
this._onChangeProperty(this._changedProperties); | ||
// Signal change | ||
this.change(); | ||
this.signalChange(); | ||
@@ -273,15 +261,2 @@ // reset changed and changed properties | ||
/** | ||
* Signal to 'change' listener if model has changed | ||
* | ||
* @return {[type]} | ||
*/ | ||
change: function(){ | ||
if (this._changed) { | ||
this.signalChange(); | ||
} | ||
return this; | ||
}, | ||
/** | ||
* Signal to 'change:prop' listener if model property has changed | ||
@@ -291,3 +266,3 @@ * @param {String} prop Name of property | ||
*/ | ||
changeProperty: function(prop, val){ | ||
_onChangeProperty: function(prop, val){ | ||
if (this._changed) { | ||
@@ -344,2 +319,14 @@ this.signalChangeProperty(prop, val, this.getPrevious(prop)); | ||
Model.implement( | ||
signalFactory( | ||
['change', 'destroy', 'reset'], | ||
{ | ||
signalChangeProperty: function(prop, newVal, oldVal){ | ||
!this.isSilent() && this.fireEvent('change:' + prop, [this, prop, newVal, oldVal]); | ||
return this; | ||
} | ||
} | ||
) | ||
); | ||
['each', 'subset', 'map', 'filter', 'every', 'some', 'keys', 'values', 'getLength', 'keyOf', 'contains', 'toQueryString'].each(function(method){ | ||
@@ -346,0 +333,0 @@ Model.implement(method, function(){ |
var Neuro = { | ||
version: '0.2.1' | ||
version: '0.2.2' | ||
}; | ||
exports = module.exports = Neuro; |
@@ -12,2 +12,3 @@ var config = module.exports; | ||
// "test/*-test.js" | ||
"test/snitch-test.js", | ||
"test/model-test.js", | ||
@@ -14,0 +15,0 @@ "test/collection-test.js", |
@@ -193,2 +193,133 @@ buster.testCase('Neuro Collection', { | ||
'Snitch': { | ||
setUp: function(){ | ||
var collection = new Class({ | ||
Extends: Neuro.Collection, | ||
_validators: { | ||
a: Type.isString, | ||
b: Type.isNumber, | ||
c: Type.isArray | ||
} | ||
}); | ||
this.mockSnitchCollection = collection; | ||
}, | ||
'setupValidators should be run during instantiation': function(){ | ||
var collection = new this.mockSnitchCollection({}, { | ||
validators: { | ||
d: Type.isFunction | ||
} | ||
}); | ||
assert.equals(Object.getLength(collection._validators), 4); | ||
}, | ||
'validate an object against the collections _validators': function(){ | ||
var collection = new this.mockSnitchCollection(), | ||
obj = { | ||
a: 'str', b: '1' | ||
}; | ||
assert.equals(collection.validate(obj), false); | ||
obj.b = 1; | ||
assert.equals(collection.validate(obj), true); | ||
}, | ||
'trigger error event when an object or model is trying to be added to the collection and does not pass validation': function(){ | ||
var spy = this.spy(), | ||
collection = new this.mockSnitchCollection(), | ||
obj = { | ||
a: 'str', b: '1' | ||
}; | ||
collection.addEvent('error', spy); | ||
collection.add(obj); | ||
assert.equals(collection.hasModel(obj), false); | ||
obj.b = 1; | ||
collection.add(obj); | ||
assert.equals(Neuro.Is.Equal(obj, collection.get(0).getData()), true); | ||
assert.calledOnceWith(spy, collection, obj, undefined); | ||
}, | ||
'proofModel should return a boolean value when testing': { | ||
'an object or array of objects': function(){ | ||
var collection = new this.mockSnitchCollection(), | ||
model1 = {a: 'str', b: '1', c: []}, | ||
model2 = {a: 'str', b: '2', c: []}; | ||
assert.equals(collection.proofModel(model1), false); | ||
assert.equals(collection.proofModel([model1, model2]), false); | ||
model1.b = 1; | ||
assert.equals(collection.proofModel(model1), true); | ||
assert.equals(collection.proofModel([model1, model2]), false); | ||
model2.b = 2; | ||
assert.equals(collection.proofModel(model2), true); | ||
assert.equals(collection.proofModel([model1, model2]), true); | ||
}, | ||
'a model instance or an array of model instances': function(){ | ||
var collection = new this.mockSnitchCollection(), | ||
model1 = new Neuro.Model({a: 'str', b: '1', c: []}), | ||
model2 = new Neuro.Model({a: 'str', b: '2', c: []}); | ||
assert.equals(collection.proofModel(model1), false); | ||
assert.equals(collection.proofModel([model1, model2]), false); | ||
model1.set('b', 1); | ||
assert.equals(collection.proofModel(model1), true); | ||
assert.equals(collection.proofModel([model1, model2]), false); | ||
model2.set('b', 2); | ||
assert.equals(collection.proofModel(model2), true); | ||
assert.equals(collection.proofModel([model1, model2]), true); | ||
}, | ||
'an array of model instances and objects': function(){ | ||
var collection = new this.mockSnitchCollection(), | ||
model1 = new Neuro.Model({a: 'str', b: '1', c: []}), | ||
model2 = {a: 'str', b: '2', c: []}; | ||
assert.equals(collection.proofModel(model1), false); | ||
assert.equals(collection.proofModel([model1, model2]), false); | ||
model1.set('b', 1); | ||
assert.equals(collection.proofModel(model1), true); | ||
assert.equals(collection.proofModel([model1, model2]), false); | ||
model2.b = 2; | ||
assert.equals(collection.proofModel(model2), true); | ||
assert.equals(collection.proofModel([model1, model2]), true); | ||
} | ||
}, | ||
'proof should return a boolean value when proofing a collection': function(){ | ||
var collection = new this.mockSnitchCollection(), | ||
model1 = new Neuro.Model({a: 'str', b: 1}), | ||
model2 = new Neuro.Model({a: 'str', b: 1}); | ||
collection.add([model1, model2]); | ||
assert.equals(collection.proof(), false); | ||
model1.set('c', []); | ||
model2.set('c', []); | ||
assert.equals(collection.proof(), true); | ||
} | ||
}, | ||
'Array Methods': { | ||
@@ -195,0 +326,0 @@ 'Each should loop over each Model instance': function(){ |
@@ -594,2 +594,77 @@ buster.testCase('Neuro Model', { | ||
'Snitch': { | ||
'setUp': function(){ | ||
var model = new Class({ | ||
Extends: Neuro.Model, | ||
_validators: { | ||
a: Type.isString, | ||
b: Type.isNumber, | ||
c: Type.isArray | ||
} | ||
}); | ||
this.mockSnitchModel = model; | ||
}, | ||
'setupValidators should be run during instantiation': function(){ | ||
var model = new this.mockSnitchModel({}, { | ||
validators: { | ||
d: Type.isFunction | ||
} | ||
}); | ||
assert.equals(Object.getLength(model._validators), 4); | ||
}, | ||
'set should set a property when validation is': { | ||
'true': { | ||
'where a validator does not exist': function(){ | ||
var model = new this.mockSnitchModel(); | ||
// no validator automatically sets value | ||
model.set('d', true); | ||
assert.equals(model.get('d'), true); | ||
}, | ||
'where a validator exists and returns true': function(){ | ||
var model = new this.mockSnitchModel(); | ||
// check against Type.isString | ||
model.set('a', 'str'); | ||
assert.equals(model.get('a'), 'str'); | ||
} | ||
}, | ||
'false where a validator exists and returns false and trigger error and errorProperty events': function(){ | ||
var spyError = this.spy(), | ||
spyErrorProperty = this.spy(), | ||
model = new this.mockSnitchModel(); | ||
model.addEvent('error', spyError), | ||
model.addEvent('error:b', spyErrorProperty); | ||
// check against Type.isNumber | ||
model.set('b', '1'); | ||
refute.equals(model.get('b'), '1'); | ||
assert.calledWith(spyError, model); | ||
assert.calledWith(spyErrorProperty, model, 'b', '1'); | ||
} | ||
}, | ||
'proof should test the model data against every validator': function(){ | ||
var model = new this.mockSnitchModel({ | ||
a: 'str', | ||
b: 1, | ||
c: [] | ||
}); | ||
assert.equals(model.proof(), true); | ||
model.set('d', {}); | ||
model.setValidator('d', Type.isFunction); | ||
assert.equals(model.proof(), false); | ||
} | ||
}, | ||
'Object Methods': { | ||
@@ -596,0 +671,0 @@ setUp: function(){ |
508868
48
12874
1652