Permalink
Browse files

finish implementation and specs of event emitter

  • Loading branch information...
1 parent 3947c6f commit b5ebdbf3d34008b844148707e5a5707a2d21fbb7 @semmypurewal committed Aug 13, 2012
Showing with 228 additions and 39 deletions.
  1. +1 −1 build.properties
  2. +1 −1 build/jermaine-min.js
  3. +106 −0 build/jermaine.js
  4. +1 −0 spec/build.html
  5. +88 −26 spec/util/event_emitter.js
  6. +31 −11 src/util/event_emitter.js
View
2 build.properties
@@ -17,4 +17,4 @@ yuicompressor = ${lib.dir}/yuicompressor/build/yuicompressor-2.4.7.jar
yuicompressor.options =
lib.dependencies = shim/index_of.js
-concatenate.order = util/namespace.js, core/validator.js
+concatenate.order = util/namespace.js, util/event_emitter.js, core/validator.js
View
2 build/jermaine-min.js
@@ -1 +1 @@
-if(!Array.prototype.indexOf){Array.prototype.indexOf=function(c){if(this==null){throw new TypeError()}var d=Object(this);var a=d.length>>>0;if(a===0){return -1}var e=0;if(arguments.length>0){e=Number(arguments[1]);if(e!=e){e=0}else{if(e!=0&&e!=Infinity&&e!=-Infinity){e=(e>0||-1)*Math.floor(Math.abs(e))}}}if(e>=a){return -1}var b=e>=0?e:Math.max(a-Math.abs(e),0);for(;b<a;b++){if(b in d&&d[b]===c){return b}}return -1}}(function(b){var a=function(f,c,h){var j=/^([a-zA-Z]+)(\.[a-zA-Z]*)*$/,g,e,d;if(f.match(j)===null||f==="window"){throw new Error("namespace: "+f+" is a malformed namespace string")}if(c!==undefined&&h===undefined){if(typeof(c)==="function"){h=c;c=undefined}else{if(typeof(c)==="object"){throw new Error("namespace: if second argument exists, final function argument must exist")}else{if(typeof(c)!=="object"){throw new Error("namespace: second argument must be an object of aliased local namespaces")}}}}else{if(typeof(c)!=="object"&&typeof(h)==="function"){throw new Error("namespace: second argument must be an object of aliased local namespaces")}}g=f.split(".");if(g[0]==="window"){e=window}else{e=(window[g[0]]===undefined)?window[g[0]]={}:window[g[0]]}if(h!==undefined&&typeof(h)!=="function"){throw new Error("namespace: last parameter must be a function that accepts a namespace parameter")}for(d=1;d<g.length;d=d+1){if(e[g[d]]===undefined){e[g[d]]={}}e=e[g[d]]}if(c===undefined&&h){h(e)}else{if(h){for(d in c){if(c.hasOwnProperty(d)){c[d]=a(c[d])}}h.call(c,e)}}return e};return a(b,function(c){c.namespace=a})}("window.jermaine.util"));window.jermaine.util.namespace("window.jermaine",function(c){var d=this,b,a={};b=function(e){var f=function(h){var g,j={},i;g=e.call(j,h);if(!g){i=j.message||"validator failed with parameter "+h;throw new Error(i)}return g};return f};b.addValidator=function(f,e){if(f===undefined||typeof(f)!=="string"){throw new Error("addValidator requires a name to be specified as the first parameter")}if(e===undefined||typeof(e)!=="function"){throw new Error("addValidator requires a function as the second parameter")}if(a[f]===undefined){a[f]=function(g){return new b(function(j){var i={actual:j,param:j},h=e.call(i,g);this.message=i.message;return h})}}else{throw new Error("Validator '"+f+"' already defined")}};b.getValidator=function(f){var e;if(f===undefined){throw new Error("Validator: getValidator method requires a string parameter")}else{if(typeof(f)!=="string"){throw new Error("Validator: parameter to getValidator method must be a string")}}e=a[f];if(e===undefined){throw new Error("Validator: '"+f+"' does not exist")}return e};b.validators=function(){var f,e=[];for(f in a){if(a.hasOwnProperty(f)){e.push(f)}}return e};b.addValidator("isGreaterThan",function(e){this.message=this.param+" should be greater than "+e;return this.param>e});b.addValidator("isLessThan",function(e){this.message=this.param+" should be less than "+e;return this.param<e});b.addValidator("isA",function(f){var e=["string","number","boolean","function","object"];if(typeof(f)==="string"&&e.indexOf(f)>-1){this.message=this.param+" should be a "+f;return typeof(this.param)===f}else{if(f==="integer"){if(this.param.toString!==undefined){this.message=this.param.toString()+" should be an integer"}else{this.message="parameter should be an integer"}return(typeof(this.param)==="number")&&(parseInt(this.param,10)===this.param)}else{if(typeof(f)==="string"){throw new Error("Validator: isA accepts a string which is one of "+e)}else{throw new Error("Validator: isA only accepts a string for a primitive types for the time being")}}}});b.addValidator("isOneOf",function(e){this.message=this.param+" should be one of the set: "+e;return e.indexOf(this.param)>-1});c.Validator=b});window.jermaine.util.namespace("window.jermaine",function(b){var a={};var c=function(g){var j=[],n=this,o="invalid setter call for "+g,k,l,m,f,d,p=false,e,q=window.jermaine.AttrList,h=window.jermaine.Validator;e=function(i){for(m=0;m<j.length;++m){j[m](i)}return true};l=function(){return(typeof(k)==="function")?k():k};if(g===undefined||typeof(g)!=="string"){throw new Error("Attr: constructor requires a name parameter which must be a string")}this.validatesWith=function(i){if(typeof(i)==="function"){j.push(new h(i));return this}else{throw new Error("Attr: validator must be a function")}};this.defaultsTo=function(i){k=i;return this};this.isImmutable=function(){p=true;return this};this.isMutable=function(){p=false;return this};this.clone=function(){var r=(this instanceof q)?new q(g):new c(g),s;for(s=0;s<j.length;++s){r.validatesWith(j[s])}r.defaultsTo(k);if(p){r.isImmutable()}return r};this.and=this;this.which=this;this.eachOfWhich=this;this.validator=function(){return e};this.addTo=function(s){var r,i;if(!s||typeof(s)!=="object"){throw new Error("Attr: addAttr method requires an object parameter")}i=l();if(i!==undefined&&e(i)){r=i}else{if(i!==undefined&&!e(i)){throw new Error("Attr: Default value of "+i+" does not pass validation for "+g)}}s[g]=function(t){if(t!==undefined){if(p&&r!==undefined){throw new Error("cannot set the immutable property "+g+" after it has been set")}else{if(!e(t)){throw new Error(o)}else{r=t}}return s}else{return r}}};d=function(i){n[i]=function(r){j.push(h.getValidator(i)(r));return n}};for(m=0;m<h.validators().length;++m){d(h.validators()[m])}};b.Attr=c});window.jermaine.util.namespace("window.jermaine",function(a){function b(c){var e=this;a.Attr.call(this,c);var d=function(g,f){return function(){return g[f].apply(g,arguments)}};this.validateWith=this.validatesWith;this.defaultsTo=function(){};this.isImmutable=function(){};this.isMutable=function(){};this.addTo=function(h){var i,f=[],g={};if(!h||typeof(h)!=="object"){throw new Error("AttrList: addTo method requires an object parameter")}else{g.pop=d(f,"pop");g.add=function(j){if((e.validator())(j)){f.push(j);return this}else{throw new Error(e.errorMessage())}};g.at=function(j){if(j<0||j>=this.size()){throw new Error("AttrList: Index out of bounds")}return f[j]};g.get=g.at;g.size=function(){return f.length};h[c]=function(){return g}}}}b.prototype=new window.jermaine.Attr(name);a.AttrList=b});window.jermaine.util.namespace("window.jermaine",function(a){var b=function(c,d){if(!c||typeof(c)!=="string"){throw new Error("Method: constructor requires a name parameter which must be a string")}else{if(!d||typeof(d)!=="function"){throw new Error("Method: second parameter must be a function")}}this.addTo=function(e){if(!e||typeof(e)!=="object"){throw new Error("Method: addTo method requires an object parameter")}e[c]=d}};a.Method=b});window.jermaine.util.namespace("window.jermaine",function(a){function b(u){var h=this,q={},i={},p,f=true,d=[],n=[],r=[],c=a.Method,s=a.Attr,l=a.AttrList,g,v,k,j,t=function(){},o=function(){},e=function(){if(f){k()}return o.apply(this,arguments)};if(arguments.length>1){u=arguments[arguments.length-1]}if(u&&typeof(u)==="function"){e=new b();u.call(e);return e}else{if(u){throw new Error("Model: specification parameter must be a function")}}var m=function(y,x){var A=y==="Attr"?s:l,w=y==="Attr"?"hasA":"hasMany",z;f=true;if(typeof(x)==="string"){z=new A(x);i[x]=z;return z}else{throw new Error("Model: "+w+" parameter must be a string")}};g=function(y,x){var w;if(typeof(x)!=="string"){throw new Error("Model: expected string argument to "+y+" method, but recieved "+x)}w=y==="attribute"?i[x]:q[x];if(w===undefined){throw new Error("Model: "+y+" "+x+" does not exist!")}return w};v=function(y){var x,z=[],w=y==="attributes"?i:q;for(x in w){if(w.hasOwnProperty(x)){z.push(x)}}return z};k=function(w){var z=this,x,y;e.validate();o=function(){var B,A;if(!(this instanceof e)){throw new Error("Model: instances must be created using the new operator")}A=function(F,E){var D=E==="attributes"?i:q,C;for(C in D){if(D.hasOwnProperty(C)){if(D===i&&j){D[C].isImmutable()}D[C].addTo(F)}}};A(this,"attributes");A(this,"methods");this.toString=p;if(arguments.length>0){if(arguments.length<d.length){y="Constructor requires ";for(B=0;B<d.length;++B){y+=d[B];y+=B===d.length-1?"":", "}y+=" to be specified";throw new Error(y)}else{for(B=0;B<arguments.length;++B){if(B<d.length){this[d[B]](arguments[B])}else{this[n[B-d.length]](arguments[B])}}}}t.call(this)};return o};e.hasA=function(w){return m("Attr",w)};e.hasAn=e.hasA;e.hasMany=function(w){return m("AttrList",w)};e.isA=function(y){var x,w,A,z;f=true;z=function(C){var B,D=new b();for(B in D){if(D.hasOwnProperty(B)&&typeof(C[B])!==typeof(D[B])){return false}}return true};if(typeof(y)!=="function"||!z(y)){throw new Error("Model: parameter sent to isA function must be a Model")}if(r.length===0){r.push(y)}else{throw new Error("Model: Model only supports single inheritance at this time")}w=r[0].attributes();for(x=0;x<w.length;++x){if(i[w[x]]===undefined){i[w[x]]=r[0].attribute(w[x]).clone();i[w[x]].isMutable()}}A=r[0].methods();for(x=0;x<A.length;++x){if(q[A[x]]===undefined){q[A[x]]=r[0].method(A[x])}}for(x=0;x<r.length;x++){e.prototype=new r[x]()}};e.isAn=e.isA;e.parent=function(){return r[0].apply(this,arguments)};e.attribute=function(w){return g("attribute",w)};e.attributes=function(){return v("attributes")};e.method=function(w){return g("method",w)};e.methods=function(){return v("methods")};e.isBuiltWith=function(){var w=false,x;f=true;d=[];n=[];for(x=0;x<arguments.length;++x){if(typeof(arguments[x])==="string"&&arguments[x].charAt(0)!=="%"){if(w){throw new Error("Model: isBuiltWith requires parameters preceded with a % to be the final parameters before the optional function")}else{d.push(arguments[x])}}else{if(typeof(arguments[x])==="string"&&arguments[x].charAt(0)==="%"){w=true;n.push(arguments[x].slice(1))}else{if(typeof(arguments[x])==="function"&&x===arguments.length-1){t=arguments[x]}else{throw new Error("Model: isBuiltWith parameters must be strings except for a function as the optional final parameter")}}}}};e.isImmutable=function(){j=true};e.looksLike=function(w){f=true;p=w};e.respondsTo=function(x,y){var w=new c(x,y);f=true;q[x]=w};e.validate=function(){var y,x=this.attributes(),w=this.methods();for(y=0;y<d.length;++y){try{this.attribute(d[y])}catch(z){throw new Error(d[y]+", specified in the isBuiltWith method, is not an attribute")}}for(y=0;y<n.length;++y){try{this.attribute(n[y])}catch(z){throw new Error(n[y]+", specified in the isBuiltWith method, is not an attribute")}}for(y=0;y<x.length;y++){if(w.indexOf(x[y])>-1){throw new Error("Model: invalid model specification to "+x[y]+" being both an attribute and method")}}if(j){for(y=0;y<x.length;y++){if(d.indexOf(x[y])<0){throw new Error("immutable objects must have all attributes required in a call to isBuiltWith")}}}f=false};return e}a.Model=b});
+if(!Array.prototype.indexOf){Array.prototype.indexOf=function(c){if(this==null){throw new TypeError()}var d=Object(this);var a=d.length>>>0;if(a===0){return -1}var e=0;if(arguments.length>0){e=Number(arguments[1]);if(e!=e){e=0}else{if(e!=0&&e!=Infinity&&e!=-Infinity){e=(e>0||-1)*Math.floor(Math.abs(e))}}}if(e>=a){return -1}var b=e>=0?e:Math.max(a-Math.abs(e),0);for(;b<a;b++){if(b in d&&d[b]===c){return b}}return -1}}(function(b){var a=function(f,c,h){var j=/^([a-zA-Z]+)(\.[a-zA-Z]*)*$/,g,e,d;if(f.match(j)===null||f==="window"){throw new Error("namespace: "+f+" is a malformed namespace string")}if(c!==undefined&&h===undefined){if(typeof(c)==="function"){h=c;c=undefined}else{if(typeof(c)==="object"){throw new Error("namespace: if second argument exists, final function argument must exist")}else{if(typeof(c)!=="object"){throw new Error("namespace: second argument must be an object of aliased local namespaces")}}}}else{if(typeof(c)!=="object"&&typeof(h)==="function"){throw new Error("namespace: second argument must be an object of aliased local namespaces")}}g=f.split(".");if(g[0]==="window"){e=window}else{e=(window[g[0]]===undefined)?window[g[0]]={}:window[g[0]]}if(h!==undefined&&typeof(h)!=="function"){throw new Error("namespace: last parameter must be a function that accepts a namespace parameter")}for(d=1;d<g.length;d=d+1){if(e[g[d]]===undefined){e[g[d]]={}}e=e[g[d]]}if(c===undefined&&h){h(e)}else{if(h){for(d in c){if(c.hasOwnProperty(d)){c[d]=a(c[d])}}h.call(c,e)}}return e};return a(b,function(c){c.namespace=a})}("window.jermaine.util"));window.jermaine.util.namespace("window.jermaine.util",function(a){var b=function(){var d=this,c={};this.on=function(e,f){if(typeof(e)!=="string"){throw new Error("EventEmitter: first argument to 'on' should be a string")}if(typeof(f)!=="function"){throw new Error("EventEmitter: second argument to 'on' should be a function")}if(!c[e]){c[e]=[]}c[e].push(f);return d};this.addListener=this.on;this.once=function(e,h){var g=function(){h(arguments);d.removeListener(e,g)};d.on(e,g);return d};this.removeListener=function(f,g){var e;if(typeof(f)!=="string"){throw new Error("EventEmitter: first parameter to removeListener method must be a string representing an event")}if(typeof(g)!=="function"){throw new Error("EventEmitter: second parameter must be a function to remove as an event listener")}e=c[f].indexOf(g);if(e!==-1){c[f].splice(e,1)}return d};this.removeAllListeners=function(e){if(typeof(e)!=="string"){throw new Error("EventEmitter: parameter to removeAllListeners should be a string representing an event")}if(c[e]!==undefined){c[e]=[]}return d};this.setMaxListeners=function(e){return d};this.listeners=function(e){if(typeof(e)!=="string"){throw new Error("EventEmitter: listeners method must be called with the name of an event")}else{if(c[e]===undefined){throw new Error("EventEmitter: event '"+e+"' has not yet been registered")}}return c[e]};this.emit=function(f,g){var e,h;if(arguments.length>1){h=[]}for(e=1;e<arguments.length;++e){h.push(arguments[e])}if(c[f]!==undefined){for(e=0;e<c[f].length;e=e+1){c[f][e].apply(this,h)}}};return d};a.EventEmitter=b});window.jermaine.util.namespace("window.jermaine",function(c){var d=this,b,a={};b=function(e){var f=function(h){var g,j={},i;g=e.call(j,h);if(!g){i=j.message||"validator failed with parameter "+h;throw new Error(i)}return g};return f};b.addValidator=function(f,e){if(f===undefined||typeof(f)!=="string"){throw new Error("addValidator requires a name to be specified as the first parameter")}if(e===undefined||typeof(e)!=="function"){throw new Error("addValidator requires a function as the second parameter")}if(a[f]===undefined){a[f]=function(g){return new b(function(j){var i={actual:j,param:j},h=e.call(i,g);this.message=i.message;return h})}}else{throw new Error("Validator '"+f+"' already defined")}};b.getValidator=function(f){var e;if(f===undefined){throw new Error("Validator: getValidator method requires a string parameter")}else{if(typeof(f)!=="string"){throw new Error("Validator: parameter to getValidator method must be a string")}}e=a[f];if(e===undefined){throw new Error("Validator: '"+f+"' does not exist")}return e};b.validators=function(){var f,e=[];for(f in a){if(a.hasOwnProperty(f)){e.push(f)}}return e};b.addValidator("isGreaterThan",function(e){this.message=this.param+" should be greater than "+e;return this.param>e});b.addValidator("isLessThan",function(e){this.message=this.param+" should be less than "+e;return this.param<e});b.addValidator("isA",function(f){var e=["string","number","boolean","function","object"];if(typeof(f)==="string"&&e.indexOf(f)>-1){this.message=this.param+" should be a "+f;return typeof(this.param)===f}else{if(f==="integer"){if(this.param.toString!==undefined){this.message=this.param.toString()+" should be an integer"}else{this.message="parameter should be an integer"}return(typeof(this.param)==="number")&&(parseInt(this.param,10)===this.param)}else{if(typeof(f)==="string"){throw new Error("Validator: isA accepts a string which is one of "+e)}else{throw new Error("Validator: isA only accepts a string for a primitive types for the time being")}}}});b.addValidator("isOneOf",function(e){this.message=this.param+" should be one of the set: "+e;return e.indexOf(this.param)>-1});c.Validator=b});window.jermaine.util.namespace("window.jermaine",function(b){var a={};var c=function(g){var j=[],n=this,o="invalid setter call for "+g,k,l,m,f,d,p=false,e,q=window.jermaine.AttrList,h=window.jermaine.Validator;e=function(i){for(m=0;m<j.length;++m){j[m](i)}return true};l=function(){return(typeof(k)==="function")?k():k};if(g===undefined||typeof(g)!=="string"){throw new Error("Attr: constructor requires a name parameter which must be a string")}this.validatesWith=function(i){if(typeof(i)==="function"){j.push(new h(i));return this}else{throw new Error("Attr: validator must be a function")}};this.defaultsTo=function(i){k=i;return this};this.isImmutable=function(){p=true;return this};this.isMutable=function(){p=false;return this};this.clone=function(){var r=(this instanceof q)?new q(g):new c(g),s;for(s=0;s<j.length;++s){r.validatesWith(j[s])}r.defaultsTo(k);if(p){r.isImmutable()}return r};this.and=this;this.which=this;this.eachOfWhich=this;this.validator=function(){return e};this.addTo=function(s){var r,i;if(!s||typeof(s)!=="object"){throw new Error("Attr: addAttr method requires an object parameter")}i=l();if(i!==undefined&&e(i)){r=i}else{if(i!==undefined&&!e(i)){throw new Error("Attr: Default value of "+i+" does not pass validation for "+g)}}s[g]=function(t){if(t!==undefined){if(p&&r!==undefined){throw new Error("cannot set the immutable property "+g+" after it has been set")}else{if(!e(t)){throw new Error(o)}else{r=t}}return s}else{return r}}};d=function(i){n[i]=function(r){j.push(h.getValidator(i)(r));return n}};for(m=0;m<h.validators().length;++m){d(h.validators()[m])}};b.Attr=c});window.jermaine.util.namespace("window.jermaine",function(a){function b(c){var e=this;a.Attr.call(this,c);var d=function(g,f){return function(){return g[f].apply(g,arguments)}};this.validateWith=this.validatesWith;this.defaultsTo=function(){};this.isImmutable=function(){};this.isMutable=function(){};this.addTo=function(h){var i,f=[],g={};if(!h||typeof(h)!=="object"){throw new Error("AttrList: addTo method requires an object parameter")}else{g.pop=d(f,"pop");g.add=function(j){if((e.validator())(j)){f.push(j);return this}else{throw new Error(e.errorMessage())}};g.at=function(j){if(j<0||j>=this.size()){throw new Error("AttrList: Index out of bounds")}return f[j]};g.get=g.at;g.size=function(){return f.length};h[c]=function(){return g}}}}b.prototype=new window.jermaine.Attr(name);a.AttrList=b});window.jermaine.util.namespace("window.jermaine",function(a){var b=function(c,d){if(!c||typeof(c)!=="string"){throw new Error("Method: constructor requires a name parameter which must be a string")}else{if(!d||typeof(d)!=="function"){throw new Error("Method: second parameter must be a function")}}this.addTo=function(e){if(!e||typeof(e)!=="object"){throw new Error("Method: addTo method requires an object parameter")}e[c]=d}};a.Method=b});window.jermaine.util.namespace("window.jermaine",function(a){function b(u){var h=this,q={},i={},p,f=true,d=[],n=[],r=[],c=a.Method,s=a.Attr,l=a.AttrList,g,v,k,j,t=function(){},o=function(){},e=function(){if(f){k()}return o.apply(this,arguments)};if(arguments.length>1){u=arguments[arguments.length-1]}if(u&&typeof(u)==="function"){e=new b();u.call(e);return e}else{if(u){throw new Error("Model: specification parameter must be a function")}}var m=function(y,x){var A=y==="Attr"?s:l,w=y==="Attr"?"hasA":"hasMany",z;f=true;if(typeof(x)==="string"){z=new A(x);i[x]=z;return z}else{throw new Error("Model: "+w+" parameter must be a string")}};g=function(y,x){var w;if(typeof(x)!=="string"){throw new Error("Model: expected string argument to "+y+" method, but recieved "+x)}w=y==="attribute"?i[x]:q[x];if(w===undefined){throw new Error("Model: "+y+" "+x+" does not exist!")}return w};v=function(y){var x,z=[],w=y==="attributes"?i:q;for(x in w){if(w.hasOwnProperty(x)){z.push(x)}}return z};k=function(w){var z=this,x,y;e.validate();o=function(){var B,A;if(!(this instanceof e)){throw new Error("Model: instances must be created using the new operator")}A=function(F,E){var D=E==="attributes"?i:q,C;for(C in D){if(D.hasOwnProperty(C)){if(D===i&&j){D[C].isImmutable()}D[C].addTo(F)}}};A(this,"attributes");A(this,"methods");this.toString=p;if(arguments.length>0){if(arguments.length<d.length){y="Constructor requires ";for(B=0;B<d.length;++B){y+=d[B];y+=B===d.length-1?"":", "}y+=" to be specified";throw new Error(y)}else{for(B=0;B<arguments.length;++B){if(B<d.length){this[d[B]](arguments[B])}else{this[n[B-d.length]](arguments[B])}}}}t.call(this)};return o};e.hasA=function(w){return m("Attr",w)};e.hasAn=e.hasA;e.hasMany=function(w){return m("AttrList",w)};e.isA=function(y){var x,w,A,z;f=true;z=function(C){var B,D=new b();for(B in D){if(D.hasOwnProperty(B)&&typeof(C[B])!==typeof(D[B])){return false}}return true};if(typeof(y)!=="function"||!z(y)){throw new Error("Model: parameter sent to isA function must be a Model")}if(r.length===0){r.push(y)}else{throw new Error("Model: Model only supports single inheritance at this time")}w=r[0].attributes();for(x=0;x<w.length;++x){if(i[w[x]]===undefined){i[w[x]]=r[0].attribute(w[x]).clone();i[w[x]].isMutable()}}A=r[0].methods();for(x=0;x<A.length;++x){if(q[A[x]]===undefined){q[A[x]]=r[0].method(A[x])}}for(x=0;x<r.length;x++){e.prototype=new r[x]()}};e.isAn=e.isA;e.parent=function(){return r[0].apply(this,arguments)};e.attribute=function(w){return g("attribute",w)};e.attributes=function(){return v("attributes")};e.method=function(w){return g("method",w)};e.methods=function(){return v("methods")};e.isBuiltWith=function(){var w=false,x;f=true;d=[];n=[];for(x=0;x<arguments.length;++x){if(typeof(arguments[x])==="string"&&arguments[x].charAt(0)!=="%"){if(w){throw new Error("Model: isBuiltWith requires parameters preceded with a % to be the final parameters before the optional function")}else{d.push(arguments[x])}}else{if(typeof(arguments[x])==="string"&&arguments[x].charAt(0)==="%"){w=true;n.push(arguments[x].slice(1))}else{if(typeof(arguments[x])==="function"&&x===arguments.length-1){t=arguments[x]}else{throw new Error("Model: isBuiltWith parameters must be strings except for a function as the optional final parameter")}}}}};e.isImmutable=function(){j=true};e.looksLike=function(w){f=true;p=w};e.respondsTo=function(x,y){var w=new c(x,y);f=true;q[x]=w};e.validate=function(){var y,x=this.attributes(),w=this.methods();for(y=0;y<d.length;++y){try{this.attribute(d[y])}catch(z){throw new Error(d[y]+", specified in the isBuiltWith method, is not an attribute")}}for(y=0;y<n.length;++y){try{this.attribute(n[y])}catch(z){throw new Error(n[y]+", specified in the isBuiltWith method, is not an attribute")}}for(y=0;y<x.length;y++){if(w.indexOf(x[y])>-1){throw new Error("Model: invalid model specification to "+x[y]+" being both an attribute and method")}}if(j){for(y=0;y<x.length;y++){if(d.indexOf(x[y])<0){throw new Error("immutable objects must have all attributes required in a call to isBuiltWith")}}}f=false};return e}a.Model=b});
View
106 build/jermaine.js
@@ -106,6 +106,112 @@ if (!Array.prototype.indexOf) {
exports.namespace = namespace;
});
}("window.jermaine.util"));
+window.jermaine.util.namespace("window.jermaine.util", function (ns) {
+ "use strict";
+ var EventEmitter = function () {
+ var that = this,
+ listeners = {};
+
+ //an registers event and a listener
+ this.on = function (event, listener) {
+ if (typeof(event) !== "string") {
+ throw new Error("EventEmitter: first argument to 'on' should be a string");
+ }
+ if (typeof(listener) !== "function") {
+ throw new Error("EventEmitter: second argument to 'on' should be a function");
+ }
+ if (!listeners[event]) {
+ listeners[event] = [];
+ }
+ listeners[event].push(listener);
+ return that;
+ };
+
+ //alias addListener
+ this.addListener = this.on;
+
+ this.once = function (event, listener) {
+ var f = function () {
+ listener(arguments);
+ that.removeListener(event, f);
+ };
+
+ that.on(event, f);
+ return that;
+ };
+
+ this.removeListener = function (event, listener) {
+ var index;
+
+ if (typeof(event) !== "string") {
+ throw new Error("EventEmitter: first parameter to removeListener method must be a string representing an event");
+ }
+ if (typeof(listener) !== "function") {
+ throw new Error("EventEmitter: second parameter must be a function to remove as an event listener");
+ }
+
+ index = listeners[event].indexOf(listener);
+
+ if (index !== -1) {
+ //remove it from the list
+ listeners[event].splice(index,1);
+ }
+
+ return that;
+ };
+
+ this.removeAllListeners = function (event) {
+ if (typeof(event) !== "string") {
+ throw new Error("EventEmitter: parameter to removeAllListeners should be a string representing an event");
+ }
+
+ if (listeners[event] !== undefined) {
+ listeners[event] = [];
+ }
+
+ return that;
+ };
+
+ this.setMaxListeners = function (number) {
+ return that;
+ };
+
+ //get the listeners for an event
+ this.listeners = function (event) {
+ if (typeof(event) !== 'string') {
+ throw new Error("EventEmitter: listeners method must be called with the name of an event");
+ } else if (listeners[event] === undefined) {
+ throw new Error("EventEmitter: event '" + event + "' has not yet been registered");
+ }
+ return listeners[event];
+ };
+
+ //execute each of the listeners in order with the specified arguments
+ this.emit = function (event, data) {
+ var i,
+ params;
+
+
+ if (arguments.length > 1) {
+ params = [];
+ }
+
+ for (i = 1; i < arguments.length; ++i) {
+ params.push(arguments[i]);
+ }
+
+ if (listeners[event] !== undefined) {
+ for (i = 0; i < listeners[event].length; i=i+1) {
+ listeners[event][i].apply(this, params);
+ }
+ }
+ };
+
+ return that;
+ }; //end EventEmitter
+
+ ns.EventEmitter = EventEmitter;
+});
window.jermaine.util.namespace("window.jermaine", function (ns) {
"use strict";
var that = this,
View
1 spec/build.html
@@ -15,6 +15,7 @@
<!-- include specs here -->
<script type="text/javascript" src="util/namespace.js"></script>
+ <script type="text/javascript" src="util/event_emitter.js"></script>
<script type="text/javascript" src="core/validator.js"></script>
<script type="text/javascript" src="core/attr.js"></script>
View
114 spec/util/event_emitter.js
@@ -27,53 +27,53 @@ describe("event emitter", function () {
});
- describe("on method", function() {
- it("should register a callback on an event", function() {
- e.on("event", function() {});
+ describe("on method", function () {
+ it("should register a callback on an event", function () {
+ e.on("event", function () {});
expect(e.listeners("event").length).toBe(1);
});
- it("should register multiple callbacks for a single event", function() {
- e.on("event", function() {
+ it("should register multiple callbacks for a single event", function () {
+ e.on("event", function () {
console.log("function 1");
});
- e.on("event", function() {
+ e.on("event", function () {
console.log("function 2");
});
expect(e.listeners("event").length).toBe(2);
});
- it("should register callbacks for multiple events", function() {
- e.on("event1", function() { });
- e.on("event2", function() { });
+ it("should register callbacks for multiple events", function () {
+ e.on("event1", function () { });
+ e.on("event2", function () { });
expect(e.listeners("event1").length).toBe(1);
expect(e.listeners("event2").length).toBe(1);
});
- it("should return an instance of EventEmitter so the call can be chained", function() {
- expect(e.on("event", function() {}) instanceof EventEmitter).toBeTruthy();
+ it("should return an instance of EventEmitter so the call can be chained", function () {
+ expect(e.on("event", function () {}) instanceof EventEmitter).toBeTruthy();
});
- it("should register callbacks to be registered in a chain", function() {
- e.on("event1", function() { })
- .on("event2", function() { });
+ it("should register callbacks to be registered in a chain", function () {
+ e.on("event1", function () { })
+ .on("event2", function () { });
expect(e.listeners("event1").length).toBe(1);
expect(e.listeners("event2").length).toBe(1);
});
- it("should register multiple callbacks for a single event in a chain", function() {
- e.on("event", function() { console.log("function 1");}).on("event", function() { console.log("function 2");});
+ it("should register multiple callbacks for a single event in a chain", function () {
+ e.on("event", function () { console.log("function 1");}).on("event", function () { console.log("function 2");});
expect(e.listeners("event").length).toBe(2);
});
- it("should throw an error if the event is not a string", function() {
- expect(function() {
- e.on(1, function() { });
+ it("should throw an error if the event is not a string", function () {
+ expect(function () {
+ e.on(1, function () { });
}).toThrow(new Error("EventEmitter: first argument to 'on' should be a string"));
});
- it("should throw an error if the listener is not a function", function() {
- expect(function() {
+ it("should throw an error if the listener is not a function", function () {
+ expect(function () {
e.on("event", 1);
}).toThrow(new Error("EventEmitter: second argument to 'on' should be a function"));
});
@@ -140,24 +140,86 @@ describe("event emitter", function () {
});
describe("listeners method", function () {
- it("should return the listeners for a given event", function() {
- var listener1 = function() {
+ it("should return the listeners for a given event", function () {
+ var listener1 = function () {
};
- var listener2 = function() {
+ var listener2 = function () {
};
e.on("event", listener1).on("event", listener2);
expect(e.listeners("event").length).toBe(2);
expect(e.listeners("event")).toEqual([listener1, listener2]);
});
- it('should throw an error if the method is called without a string', function() {
- expect(function() { e.listeners(); }).toThrow(new Error('EventEmitter: listeners method must be called with the name of an event'));
+ it("should throw an error if the method is called without a string", function () {
+ expect(function () { e.listeners(); }).toThrow(new Error("EventEmitter: listeners method must be called with the name of an event"));
+ });
+ });
+
+ describe("once method", function () {
+ var stubA;
+
+ beforeEach(function () {
+ stubA = jasmine.createSpy("stubA");
+ });
+
+ it("should call the listener when the event is emitted", function () {
+ e.on("event1", stubA);
+ e.emit("event1");
+ expect(stubA).toHaveBeenCalled();
});
+
+ it("should remove the listener after the event is called", function () {
+ e.once("event1", stubA);
+ e.emit("event1");
+ expect(stubA).toHaveBeenCalled();
+ expect(e.listeners("event1").length).toBe(0);
+ });
+
});
describe("emit method", function () {
+ var stubA;
+ var stubB;
+ beforeEach(function () {
+ stubA = jasmine.createSpy("stubA");
+ stubB = jasmine.createSpy("stubB");
+ });
+
+ it("should respond with a correct listener and data when an event is emitted", function () {
+ e.on("event1", stubA);
+ e.emit("event1");
+ expect(stubA).toHaveBeenCalled();
+ e.emit("event1",5);
+ expect(stubA).toHaveBeenCalledWith(5);
+ });
+
+ it("should not respond with incorrect listener when an event is emitted", function () {
+ e.on("event1", stubA);
+ e.on("event2", stubB);
+ e.emit("event1");
+ expect(stubA).toHaveBeenCalled();
+ expect(stubB).not.toHaveBeenCalled();
+ });
+
+ it("should respond with all listeners when an event is emitted", function () {
+ e.on("event1", stubA);
+ e.on("event1", stubB);
+ e.emit("event1", 5);
+ expect(stubA).toHaveBeenCalledWith(5);
+ expect(stubB).toHaveBeenCalledWith(5);
+ });
+
+ it("should be able to call listeners with multiple parameters", function () {
+ e.on("event1", stubA);
+ e.emit("event1", 5, "hello", 10);
+ expect(stubA).toHaveBeenCalledWith(5, "hello", 10);
+ });
+
+ xit("should throw an error if the first parameter is not a string", function () {
+
+ });
});
});
View
42 src/util/event_emitter.js
@@ -1,9 +1,10 @@
window.jermaine.util.namespace("window.jermaine.util", function (ns) {
"use strict";
var EventEmitter = function () {
- var listeners = {};
+ var that = this,
+ listeners = {};
- //registers an event and a listener
+ //an registers event and a listener
this.on = function (event, listener) {
if (typeof(event) !== "string") {
throw new Error("EventEmitter: first argument to 'on' should be a string");
@@ -15,16 +16,20 @@ window.jermaine.util.namespace("window.jermaine.util", function (ns) {
listeners[event] = [];
}
listeners[event].push(listener);
- return this;
+ return that;
};
//alias addListener
this.addListener = this.on;
this.once = function (event, listener) {
+ var f = function () {
+ listener(arguments);
+ that.removeListener(event, f);
+ };
-
- return this;
+ that.on(event, f);
+ return that;
};
this.removeListener = function (event, listener) {
@@ -36,15 +41,15 @@ window.jermaine.util.namespace("window.jermaine.util", function (ns) {
if (typeof(listener) !== "function") {
throw new Error("EventEmitter: second parameter must be a function to remove as an event listener");
}
-
+
index = listeners[event].indexOf(listener);
if (index !== -1) {
//remove it from the list
listeners[event].splice(index,1);
}
- return this;
+ return that;
};
this.removeAllListeners = function (event) {
@@ -55,10 +60,12 @@ window.jermaine.util.namespace("window.jermaine.util", function (ns) {
if (listeners[event] !== undefined) {
listeners[event] = [];
}
+
+ return that;
};
this.setMaxListeners = function (number) {
- return this;
+ return that;
};
//get the listeners for an event
@@ -73,13 +80,26 @@ window.jermaine.util.namespace("window.jermaine.util", function (ns) {
//execute each of the listeners in order with the specified arguments
this.emit = function (event, data) {
- var i;
+ var i,
+ params;
+
+
+ if (arguments.length > 1) {
+ params = [];
+ }
+
+ for (i = 1; i < arguments.length; ++i) {
+ params.push(arguments[i]);
+ }
+
if (listeners[event] !== undefined) {
- for(i = 0; i < listeners[event].length; i=i+1) {
- listeners[event][i](data);
+ for (i = 0; i < listeners[event].length; i=i+1) {
+ listeners[event][i].apply(this, params);
}
}
};
+
+ return that;
}; //end EventEmitter
ns.EventEmitter = EventEmitter;

0 comments on commit b5ebdbf

Please sign in to comment.