summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlo Zancanaro <carlo@zancanaro.id.au>2014-09-29 18:09:17 +1000
committerCarlo Zancanaro <carlo@zancanaro.id.au>2014-09-29 18:09:17 +1000
commita66f4025c81d428d0668465c8c7e54e7dd2f3219 (patch)
tree43293ed4a1e83552857b8797ce9f9244bb9316ea
parent1062e09e0359019509728f132539f4604efe5bf8 (diff)
Improve errors reporting for distant objects, fix requestor (special __requestor__ dep), error out when jQuery can't be found, handle object registration formHEADmaster
-rw-r--r--scorpion.js93
-rw-r--r--scorpion.min.js2
2 files changed, 64 insertions, 31 deletions
diff --git a/scorpion.js b/scorpion.js
index 6d7051c..af15dda 100644
--- a/scorpion.js
+++ b/scorpion.js
@@ -4,7 +4,7 @@ var Scorpion = (function() {
var Deferred = (function() {
var defer = function(fn, value) {setTimeout(function() {fn(value);});};
- var runFn = function(fn, deferred, action) {
+ var runFn = function(fn, deferred) {
return function(value) {
try {
var result = fn(value);
@@ -121,6 +121,13 @@ var Scorpion = (function() {
return deferred.promise;
};
+ Deferred.collapseErrorObject = function(obj) {
+ var errors = [];
+ for (var key in obj.errors)
+ errors = errors.concat(obj.errors[key]);
+ throw errors;
+ };
+
return Deferred;
})();
@@ -202,12 +209,23 @@ var Scorpion = (function() {
};
Scorpion.prototype.register = function(name, value) {
- for (var i = 0, l = this.plugins.length; i < l; ++i) {
- if (this.plugins[i].register(this, name, value))
- return this;
+ if (typeof(name) == "function" || name instanceof Function) {
+ value = name;
+ name = value.name;
+ }
+ if (typeof(name) == "string" || name instanceof String) {
+ for (var i = 0, l = this.plugins.length; i < l; ++i) {
+ if (this.plugins[i].register(this, name, value))
+ return this;
+ }
+ throw this.error("No plugin handled registration of: " + name);
+ return this;
+ } else {
+ for (var key in name) {
+ this.register(key, name[key]);
+ }
+ return this;
}
- throw this.error("No plugin handled registration of: " + name);
- return this;
};
Scorpion.prototype.invoke = function(spec) {
@@ -221,13 +239,13 @@ var Scorpion = (function() {
var depPromise = this.waitForAll(depPromises);
var result = depPromise.then(function(results) {
return fn.apply(injector, results);
- });
+ }, Deferred.collapseErrorObject);
result.destroy = function() {
return Scorpion.waitForAll(depPromises.map(function(promise) {
return promise.destroy();
})).then(function() {
return true;
- });
+ }, Deferred.collapseErrorObject);
};
return result;
};
@@ -300,13 +318,19 @@ var Scorpion = (function() {
DOMPlugin.prototype.get = function(injector, name, stack) {
var deferred = injector.defer();
- var interval = setInterval(function() {
- var obj = $(this.aliases[name] || name);
- if (obj.length) {
- clearInterval(interval);
- deferred.resolve(obj);
- }
- }.bind(this), 100);
+ if (typeof($) !== "undefined" && $) {
+ var intervalFn = function() {
+ var obj = $(this.aliases[name] || name);
+ if (obj.length) {
+ clearInterval(interval);
+ deferred.resolve(obj);
+ }
+ }.bind(this);
+ var interval = setInterval(intervalFn, 100);
+ intervalFn();
+ } else {
+ deferred.reject(new Error("jQuery was not found " + stack.join(" <- ")));
+ }
return deferred.promise;
};
@@ -325,13 +349,17 @@ var Scorpion = (function() {
HTTPPlugin.prototype.get = function(injector, name, stack) {
var deferred = injector.defer();
- $.ajax(this.aliases[name] || name).then(function(result) {
- deferred.resolve(result);
- // deferred.resolve.bind(deferred);
- }, deferred.reject.bind(deferred));
- deferred.promise.destroy = function() {
- return Scorpion.resolved(true);
- };
+ if (typeof($) !== "undefined" && $) {
+ $.ajax(this.aliases[name] || name).then(function(result) {
+ deferred.resolve(result);
+ // deferred.resolve.bind(deferred);
+ }, deferred.reject.bind(deferred));
+ deferred.promise.destroy = function() {
+ return Scorpion.resolved(true);
+ };
+ } else {
+ deferred.reject(new Error("jQuery was not found " + stack.join(" <- ")));
+ }
return deferred.promise;
};
@@ -358,21 +386,22 @@ var Scorpion = (function() {
var parsed = injector.parseSpec(spec);
var constructor = parsed[0];
var dependencies = parsed[1];
+ var readRequestor = false;
var depPromises = dependencies.map(function(dep) {
- return injector.get(dep, [name].concat(stack));
+ if (dep == "__requestor__") {
+ readRequestor = true;
+ return injector.resolved(stack[1]);
+ } else {
+ return injector.get(dep, stack);
+ }
});
var depPromise = injector.waitForAll(depPromises);
var onDestroy = null;
- var readRequestor = false;
var deferred = injector.defer();
var result = deferred.promise;
depPromise.then(function(results) {
var wrappedScorpion = Object.create(injector);
- wrappedScorpion.requestor = function() {
- readRequestor = true;
- return stack[1];
- };
try {
deferred.resolve(constructor.apply(wrappedScorpion, results));
} catch (e) {
@@ -383,7 +412,11 @@ var Scorpion = (function() {
onDestroy();
}
}, function(e) {
- deferred.reject(injector.error("Error constructing " + name));
+ try {
+ Deferred.collapseErrorObject(e);
+ } catch (ex) {
+ deferred.reject(ex);
+ }
});
result.references = 1;
@@ -400,7 +433,7 @@ var Scorpion = (function() {
return promise.destroy();
})).then(function() {
return true;
- });
+ }, Deferred.collapseErrorObject);
} else {
return injector.resolved(true);
}
diff --git a/scorpion.min.js b/scorpion.min.js
index 5524044..bd06026 100644
--- a/scorpion.min.js
+++ b/scorpion.min.js
@@ -1 +1 @@
-/*! scorpion 0.1.0 */var Scorpion=function(){var a=function(){var a=function(a,b){setTimeout(function(){a(b)})},b=function(a,b){return function(c){try{var d=a(c);d&&d.then?d.then(function(a){b.resolve(a)},function(a){b.reject(a)}):b.resolve(d)}catch(e){b.reject(e)}}},c=function(){this.resolved=!1,this.rejected=!1,this.onSuccess=[],this.onError=[]};c.prototype.then=function(c,e){c=c||function(a){return a},e=e||function(a){throw a};var f=new d,g=b(c,f),h=b(e,f);return this.resolved?a(g,this.value):this.rejected?a(h,this.value):(null!=this.onSuccess&&this.onSuccess.push(g),null!=this.onError&&this.onError.push(h)),f.promise};var d=function(){this.promise=new c};return d.prototype.resolve=function(a){if(this.promise.resolved)throw new Error("Cannot re-resolve already resolved promise");if(this.promise.rejected)throw new Error("Cannot resolve a rejected promise");this.promise.resolved=!0,this.promise.value=a;var b=this.promise.onSuccess;this.promise.onSuccess=null,this.promise.onError=null,setTimeout(function(){b.forEach(function(b){b(a)})})},d.prototype.reject=function(a){if(this.promise.resolved)throw new Error("Cannot reject an already resolved promise");if(this.promise.rejected)throw new Error("Cannot re-reject a rejected promise");this.promise.rejected=!0,this.promise.value=a;var b=this.promise.onError;this.promise.onSuccess=null,this.promise.onError=null,setTimeout(function(){b.forEach(function(b){b(a)})})},d.waitForAll=function(a){var b=new d,c=0,e=0,f={},g={},h=a.length;a.forEach(function(a,b){a.then(function(a){g[b]=a,c++,i()},function(a){f[b]=a,e++,i()})});var i=function(){if(c==h){for(var a=[],d=0,i=h;i>d;++d)a.push(g[d]);b.resolve(a)}else c+e==h&&b.reject({errors:f,values:g})};return i(),b.promise},d}(),b=function(){var a=/^function[^(]*\(([^)]*)\)/,b=function(b){var c=a.exec(b.toString().replace(/\s+/g,""));if(null==c)throw new Error("Unable to parse fn definition");return c[1]?c[1].split(/,/):[]},c=function(a){var c,d;return"function"==typeof a||a instanceof Function?(d=b(a),c=a):(c=a[a.length-1],d=a.slice(0,a.length-1)),[c,d]},d=function(a){var b=a.split("!");if(0==b.length)throw new Error("Invalid dependency: "+a);return 1==b.length?{prefix:"",name:b[0]}:{prefix:b[0],name:b.slice(1).join("!")}};return{spec:c,dep:d}}(),c=function(a,b){var c=function(a){this.plugins=a};c.rejected=function(a,b){var c=this.defer();return c.reject(this.error(a,b)),c.promise},c.prototype.rejected=c.rejected,c.resolved=function(a){var b=this.defer();return b.resolve(a),b.promise},c.prototype.resolved=c.resolved,c.prototype.get=function(a,b){if(b=[a].concat(b||[]),b&&0!=b.lastIndexOf(a))return this.rejected("Cyclic dependency: "+b.join(" <- "));for(var d=0,e=this.plugins.length;e>d;++d){var f=this.plugins[d].get(this,a,b);if(f)return f.destroy||(f.destroy=function(){return c.resolved(!0)}),f}return this.rejected("Unknown dependency: "+b.join(" <- "))},c.prototype.register=function(a,b){for(var c=0,d=this.plugins.length;d>c;++c)if(this.plugins[c].register(this,a,b))return this;throw this.error("No plugin handled registration of: "+a)},c.prototype.invoke=function(a){var b=this,d=this.parseSpec(a),e=d[0],f=d[1],g=f.map(function(a){return b.get(a,[])}),h=this.waitForAll(g),i=h.then(function(a){return e.apply(b,a)});return i.destroy=function(){return c.waitForAll(g.map(function(a){return a.destroy()})).then(function(){return!0})},i},c.error=function(a,b){return new d(a,b)},c.prototype.error=c.error,c.defer=function(){return new a},c.prototype.defer=c.defer,c.parseSpec=b.spec,c.prototype.parseSpec=b.spec,c.waitForAll=a.waitForAll,c.prototype.waitForAll=a.waitForAll;var d=function(a,b){this.name="InjectorError",this.message=a,this.cause=b};return d.prototype=new Error,d.prototype.constructor=d,d.prototype.toString=function(){return"InjectorError: "+this.message+(this.cause?" [caused by "+this.cause+"]":"")},c}(a,b);return c.prefixPlugin=function(a,b){return{register:function(c,d,e){return 0==d.indexOf(a)?b.register(c,d.substr(a.length),e):!1},get:function(c,d,e){return 0==d.indexOf(a)?b.get(c,d.substr(a.length),e):null}}},c.DOMPlugin=function(){var a=function(){this.aliases={}};return a.prototype.register=function(a,b,c){return this.aliases[b]=c,!0},a.prototype.get=function(a,b){var c=a.defer(),d=setInterval(function(){var a=$(this.aliases[b]||b);a.length&&(clearInterval(d),c.resolve(a))}.bind(this),100);return c.promise},a}(),c.HTTPPlugin=function(){var a=function(){this.aliases={}};return a.prototype.register=function(a,b,c){return this.aliases[b]=c,!0},a.prototype.get=function(a,b){var d=a.defer();return $.ajax(this.aliases[b]||b).then(function(a){d.resolve(a)},d.reject.bind(d)),d.promise.destroy=function(){return c.resolved(!0)},d.promise},a}(),c.ValuePlugin=function(){var a=function(){this.specs={},this.values={}};return a.prototype.register=function(a,b,c){return this.specs[b]=c,!0},a.prototype.get=function(a,b,c){if(b in this.values)return this.values[b].references++,this.values[b];if(b in this.specs){var d=this.specs[b],e=a.parseSpec(d),f=e[0],g=e[1],h=g.map(function(d){return a.get(d,[b].concat(c))}),i=a.waitForAll(h),j=null,k=!1,l=a.defer(),m=l.promise;i.then(function(b){var d=Object.create(a);d.requestor=function(){return k=!0,c[1]};try{l.resolve(f.apply(d,b))}catch(e){l.reject(e)}finally{j=d.onDestroy,m.references<=0&&j&&j()}},function(){l.reject(a.error("Error constructing "+b))}),m.references=1;var n=this.values;return m.destroy=function(){return this.references--,this.references<=0?(j&&j(),delete n[b],m.resolved||m.rejected||l.reject(a.error("Promise destroyed before value completed construction")),a.waitForAll(h.map(function(a){return a.destroy()})).then(function(){return!0})):a.resolved(!0)},k?m:this.values[b]=m}return null},a}(),c}();"undefined"!=typeof module&&(module.exports=Scorpion); \ No newline at end of file
+/*! scorpion 0.1.0 */var Scorpion=function(){var a=function(){var a=function(a,b){setTimeout(function(){a(b)})},b=function(a,b){return function(c){try{var d=a(c);d&&d.then?d.then(function(a){b.resolve(a)},function(a){b.reject(a)}):b.resolve(d)}catch(e){b.reject(e)}}},c=function(){this.resolved=!1,this.rejected=!1,this.onSuccess=[],this.onError=[]};c.prototype.then=function(c,e){c=c||function(a){return a},e=e||function(a){throw a};var f=new d,g=b(c,f),h=b(e,f);return this.resolved?a(g,this.value):this.rejected?a(h,this.value):(null!=this.onSuccess&&this.onSuccess.push(g),null!=this.onError&&this.onError.push(h)),f.promise};var d=function(){this.promise=new c};return d.prototype.resolve=function(a){if(this.promise.resolved)throw new Error("Cannot re-resolve already resolved promise");if(this.promise.rejected)throw new Error("Cannot resolve a rejected promise");this.promise.resolved=!0,this.promise.value=a;var b=this.promise.onSuccess;this.promise.onSuccess=null,this.promise.onError=null,setTimeout(function(){b.forEach(function(b){b(a)})})},d.prototype.reject=function(a){if(this.promise.resolved)throw new Error("Cannot reject an already resolved promise");if(this.promise.rejected)throw new Error("Cannot re-reject a rejected promise");this.promise.rejected=!0,this.promise.value=a;var b=this.promise.onError;this.promise.onSuccess=null,this.promise.onError=null,setTimeout(function(){b.forEach(function(b){b(a)})})},d.waitForAll=function(a){var b=new d,c=0,e=0,f={},g={},h=a.length;a.forEach(function(a,b){a.then(function(a){g[b]=a,c++,i()},function(a){f[b]=a,e++,i()})});var i=function(){if(c==h){for(var a=[],d=0,i=h;i>d;++d)a.push(g[d]);b.resolve(a)}else c+e==h&&b.reject({errors:f,values:g})};return i(),b.promise},d.collapseErrorObject=function(a){var b=[];for(var c in a.errors)b=b.concat(a.errors[c]);throw b},d}(),b=function(){var a=/^function[^(]*\(([^)]*)\)/,b=function(b){var c=a.exec(b.toString().replace(/\s+/g,""));if(null==c)throw new Error("Unable to parse fn definition");return c[1]?c[1].split(/,/):[]},c=function(a){var c,d;return"function"==typeof a||a instanceof Function?(d=b(a),c=a):(c=a[a.length-1],d=a.slice(0,a.length-1)),[c,d]},d=function(a){var b=a.split("!");if(0==b.length)throw new Error("Invalid dependency: "+a);return 1==b.length?{prefix:"",name:b[0]}:{prefix:b[0],name:b.slice(1).join("!")}};return{spec:c,dep:d}}(),c=function(a,b){var c=function(a){this.plugins=a};c.rejected=function(a,b){var c=this.defer();return c.reject(this.error(a,b)),c.promise},c.prototype.rejected=c.rejected,c.resolved=function(a){var b=this.defer();return b.resolve(a),b.promise},c.prototype.resolved=c.resolved,c.prototype.get=function(a,b){if(b=[a].concat(b||[]),b&&0!=b.lastIndexOf(a))return this.rejected("Cyclic dependency: "+b.join(" <- "));for(var d=0,e=this.plugins.length;e>d;++d){var f=this.plugins[d].get(this,a,b);if(f)return f.destroy||(f.destroy=function(){return c.resolved(!0)}),f}return this.rejected("Unknown dependency: "+b.join(" <- "))},c.prototype.register=function(a,b){if(("function"==typeof a||a instanceof Function)&&(b=a,a=b.name),"string"==typeof a||a instanceof String){for(var c=0,d=this.plugins.length;d>c;++c)if(this.plugins[c].register(this,a,b))return this;throw this.error("No plugin handled registration of: "+a)}for(var e in a)this.register(e,a[e]);return this},c.prototype.invoke=function(b){var d=this,e=this.parseSpec(b),f=e[0],g=e[1],h=g.map(function(a){return d.get(a,[])}),i=this.waitForAll(h),j=i.then(function(a){return f.apply(d,a)},a.collapseErrorObject);return j.destroy=function(){return c.waitForAll(h.map(function(a){return a.destroy()})).then(function(){return!0},a.collapseErrorObject)},j},c.error=function(a,b){return new d(a,b)},c.prototype.error=c.error,c.defer=function(){return new a},c.prototype.defer=c.defer,c.parseSpec=b.spec,c.prototype.parseSpec=b.spec,c.waitForAll=a.waitForAll,c.prototype.waitForAll=a.waitForAll;var d=function(a,b){this.name="ScorpionError",this.message=a,this.cause=b};return d.prototype=new Error,d.prototype.constructor=d,d.prototype.toString=function(){return"ScorpionError: "+this.message+(this.cause?" [caused by "+this.cause+"]":"")},c}(a,b);return c.prefixPlugin=function(a,b){return{register:function(c,d,e){return 0==d.indexOf(a)?b.register(c,d.substr(a.length),e):!1},get:function(c,d,e){return 0==d.indexOf(a)?b.get(c,d.substr(a.length),e):null}}},c.DOMPlugin=function(){var a=function(){this.aliases={}};return a.prototype.register=function(a,b,c){return this.aliases[b]=c,!0},a.prototype.get=function(a,b,c){var d=a.defer();if("undefined"!=typeof $&&$){var e=function(){var a=$(this.aliases[b]||b);a.length&&(clearInterval(f),d.resolve(a))}.bind(this),f=setInterval(e,100);e()}else d.reject(new Error("jQuery was not found "+c.join(" <- ")));return d.promise},a}(),c.HTTPPlugin=function(){var a=function(){this.aliases={}};return a.prototype.register=function(a,b,c){return this.aliases[b]=c,!0},a.prototype.get=function(a,b,d){var e=a.defer();return"undefined"!=typeof $&&$?($.ajax(this.aliases[b]||b).then(function(a){e.resolve(a)},e.reject.bind(e)),e.promise.destroy=function(){return c.resolved(!0)}):e.reject(new Error("jQuery was not found "+d.join(" <- "))),e.promise},a}(),c.ValuePlugin=function(){var b=function(){this.specs={},this.values={}};return b.prototype.register=function(a,b,c){return this.specs[b]=c,!0},b.prototype.get=function(b,c,d){if(c in this.values)return this.values[c].references++,this.values[c];if(c in this.specs){var e=this.specs[c],f=b.parseSpec(e),g=f[0],h=f[1],i=!1,j=h.map(function(a){return"__requestor__"==a?(i=!0,b.resolved(d[1])):b.get(a,d)}),k=b.waitForAll(j),l=null,m=b.defer(),n=m.promise;k.then(function(a){var c=Object.create(b);try{m.resolve(g.apply(c,a))}catch(d){m.reject(d)}finally{l=c.onDestroy,n.references<=0&&l&&l()}},function(b){try{a.collapseErrorObject(b)}catch(c){m.reject(c)}}),n.references=1;var o=this.values;return n.destroy=function(){return this.references--,this.references<=0?(l&&l(),delete o[c],n.resolved||n.rejected||m.reject(b.error("Promise destroyed before value completed construction")),b.waitForAll(j.map(function(a){return a.destroy()})).then(function(){return!0},a.collapseErrorObject)):b.resolved(!0)},i?n:this.values[c]=n}return null},b}(),c}();"undefined"!=typeof module&&(module.exports=Scorpion); \ No newline at end of file