diff --git a/build/deft-debug.js b/build/deft-debug.js index 0e8c875..10bd5e3 100644 --- a/build/deft-debug.js +++ b/build/deft-debug.js @@ -1599,7 +1599,7 @@ Ext.define('Deft.mixin.Controllable', { Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org) Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License). -Promise.when(), all(), any(), map() and reduce() methods adapted from: +Promise.when(), all(), any(), some(), map() and reduce() methods adapted from: [when.js](https://github.com/cujojs/when) Copyright (c) B Cavalier & J Hann Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License). @@ -1706,58 +1706,90 @@ Ext.define('Deft.promise.Promise', { }); }, /** - * Returns a new {@link Deft.promise.Promise} that will only resolve once any one of the the specified `promisesOrValues` has resolved. - * The resolution value will be the resolution value of the triggering `promiseOrValue`. + * Initiates a competitive race, returning a new {@link Deft.promise.Promise} that will resolve when any one of the supplied `promisesOrValues` + * have resolved, or will reject when all `promisesOrValues` have rejected or cancelled. + * The resolution value will the first value of `promisesOrValues` to resolve. */ any: function(promisesOrValues) { + return this.some(promisesOrValues, 1).then({ + success: function(values) { + return values[0]; + } + }); + }, + /** + * Initiates a competitive race, returning a new {@link Deft.promise.Promise} that will resolve when `howMany` of the supplied `promisesOrValues` + * have resolved, or will reject when it becomes impossible for `howMany` to resolve. + * The resolution value will be an Array of the first `howMany` values of `promisesOrValues` to resolve. + */ + + some: function(promisesOrValues, howMany) { return this.when(promisesOrValues).then({ success: function(promisesOrValues) { - var cancelFunction, canceller, complete, deferred, failureFunction, index, progressFunction, promiseOrValue, rejecter, resolver, successFunction, updater, _i, _len; + var cancelFunction, canceller, complete, deferred, errorMessage, failureFunction, index, progressFunction, promiseOrValue, rejecter, remainingToReject, remainingToResolve, resolver, successFunction, updater, values, _i, _len; + values = []; + remainingToResolve = howMany; + remainingToReject = (promisesOrValues.length - remainingToResolve) + 1; deferred = Ext.create('Deft.promise.Deferred'); - updater = function(progress) { - deferred.update(progress); - return progress; - }; - resolver = function(value) { - complete(); - deferred.resolve(value); - return value; - }; - rejecter = function(error) { - complete(); - deferred.reject(error); - return error; - }; - canceller = function(reason) { - complete(); - deferred.cancel(reason); - return reason; - }; - complete = function() { - return updater = resolver = rejecter = canceller = Ext.emptyFn; - }; - successFunction = function(value) { - return resolver(value); - }; - failureFunction = function(value) { - return rejecter(value); - }; - progressFunction = function(value) { - return updater(value); - }; - cancelFunction = function(value) { - return canceller(value); - }; - for (index = _i = 0, _len = promisesOrValues.length; _i < _len; index = ++_i) { - promiseOrValue = promisesOrValues[index]; - if (index in promisesOrValues) { - this.when(promiseOrValue).then({ - success: successFunction, - failure: failureFunction, - progress: progressFunction, - cancel: cancelFunction - }); + if (promisesOrValues.length < howMany) { + deferred.reject(new Error('Too few Promises or values were supplied to obtain the requested number of resolved values.')); + } else { + errorMessage = howMany === 1 ? 'No Promises were resolved.' : 'Too few Promises were resolved.'; + updater = function(progress) { + deferred.update(progress); + return progress; + }; + resolver = function(value) { + values.push(value); + remainingToResolve--; + if (remainingToResolve === 0) { + complete(); + deferred.resolve(values); + } + return value; + }; + rejecter = function(error) { + remainingToReject--; + if (remainingToReject === 0) { + complete(); + deferred.reject(new Error(errorMessage)); + } + return error; + }; + canceller = function(reason) { + remainingToReject--; + if (remainingToReject === 0) { + complete(); + deferred.reject(new Error(errorMessage)); + } + return reason; + }; + complete = function() { + return updater = resolver = rejecter = canceller = Ext.emptyFn; + }; + successFunction = function(value) { + return resolver(value); + }; + failureFunction = function(value) { + return rejecter(value); + }; + progressFunction = function(value) { + return updater(value); + }; + cancelFunction = function(value) { + return canceller(value); + }; + for (index = _i = 0, _len = promisesOrValues.length; _i < _len; index = ++_i) { + promiseOrValue = promisesOrValues[index]; + if (index in promisesOrValues) { + this.when(promiseOrValue).then({ + success: successFunction, + failure: failureFunction, + progress: progressFunction, + cancel: cancelFunction + }); + } } } return deferred.getPromise(); diff --git a/build/deft.js b/build/deft.js index 59a6f72..17a8bb8 100644 --- a/build/deft.js +++ b/build/deft.js @@ -4,4 +4,4 @@ DeftJS 0.8.0pre Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org) Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License). */ -Ext.define("Deft.core.Class",{alternateClassName:["Deft.Class"],statics:{registerPreprocessor:function(b,d,a,c){if(Ext.getVersion("extjs")&&Ext.getVersion("core").isLessThan("4.1.0")){Ext.Class.registerPreprocessor(b,function(e,f,g){return d.call(this,e,f,f,g)}).setDefaultPreprocessorPosition(b,a,c)}else{Ext.Class.registerPreprocessor(b,function(f,g,e,h){return d.call(this,f,g,e,h)},[b],a,c)}},hookOnClassCreated:function(a,b){if(Ext.getVersion("extjs")&&Ext.getVersion("core").isLessThan("4.1.0")){Ext.Function.interceptBefore(a,"onClassCreated",b)}else{Ext.Function.interceptBefore(a,"onCreated",b)}},hookOnClassExtended:function(c,b){var a;if(Ext.getVersion("extjs")&&Ext.getVersion("core").isLessThan("4.1.0")){a=function(d,e){return b.call(this,d,e,e)}}else{a=b}if(c.onClassExtended!=null){Ext.Function.interceptBefore(c,"onClassExtended",a)}else{c.onClassExtended=a}},extendsClass:function(c,b){try{if(Ext.getClassName(b)===c){return true}if(b!=null?b.superclass:void 0){if(Ext.getClassName(b.superclass)===c){return true}else{return Deft.Class.extendsClass(c,Ext.getClass(b.superclass))}}else{return false}}catch(a){return false}}}});Ext.define("Deft.log.Logger",{alternateClassName:["Deft.Logger"],singleton:true,log:function(b,a){if(a==null){a="info"}},error:function(a){this.log(a,"error")},info:function(a){this.log(a,"info")},verbose:function(a){this.log(a,"verbose")},warn:function(a){this.log(a,"warn")},deprecate:function(a){this.log(a,"deprecate")}},function(){var a;if(Ext.getVersion("extjs")!=null){this.log=function(c,b){if(b==null){b="info"}if(b==="verbose"){b==="info"}if(b==="deprecate"){b="warn"}Ext.log({msg:c,level:b})}}else{if(Ext.isFunction((a=Ext.Logger)!=null?a.log:void 0)){this.log=Ext.bind(Ext.Logger.log,Ext.Logger)}}});Ext.define("Deft.util.Function",{alternateClassName:["Deft.Function"],statics:{spread:function(b,a){return function(c){if(!Ext.isArray(c)){Ext.Error.raise({msg:"Error spreading passed Array over target function arguments: passed a non-Array."})}return b.apply(a,c)}},memoize:function(d,c,a){var b;b={};return function(f){var e;e=Ext.isFunction(a)?a.apply(c,arguments):f;if(!(e in b)){b[e]=d.apply(c,arguments)}return b[e]}}}});Ext.define("Deft.event.LiveEventListener",{alternateClassName:["Deft.LiveEventListener"],requires:["Ext.ComponentQuery"],constructor:function(c){var b,d,e,a;Ext.apply(this,c);this.components=[];d=Ext.ComponentQuery.query(this.selector,this.container);for(e=0,a=d.length;e-1},locateReferences:function(c,d,a){var b,e;b=c;if(this.isPropertyChain(d)){e=this.parsePropertyChain(c,d);if(!e){return null}c=e.host;d=e.target}if(Ext.isFunction(a)){return{target:this.locateTarget(c,d),handler:a}}else{if(Ext.isFunction(b[a])){return{target:this.locateTarget(c,d),handler:b[a]}}else{return null}}},parsePropertyChain:function(a,b){var c;if(Ext.isString(b)){c=b.split(".")}else{if(Ext.isArray(b)){c=b}else{return null}}if(c.length>1&&(this.locateTarget(a,c[0])!=null)){return this.parsePropertyChain(this.locateTarget(a,c[0]),c.slice(1))}else{if(this.isTargetObservable(a,c[0])){return{host:a,target:c[0]}}else{return null}}},destroy:function(){var d,c,a,b;b=this.listeners;for(c=0,a=b.length;c0){this.createObservers()}return this},controlView:function(a){if(a instanceof Ext.ClassManager.get("Ext.Container")){this.setView(a);this.registeredComponentReferences={};this.registeredComponentSelectors={};if(Ext.getVersion("extjs")!=null){if(this.getView().rendered){this.onViewInitialize()}else{this.getView().on("afterrender",this.onViewInitialize,this,{single:true})}}else{if(this.getView().initialized){this.onViewInitialize()}else{this.getView().on("initialize",this.onViewInitialize,this,{single:true})}}}else{Ext.Error.raise({msg:"Error constructing ViewController: the configured 'view' is not an Ext.Container."})}},init:function(){},destroy:function(){var b,a;for(b in this.registeredComponentReferences){this.removeComponentReference(b)}for(a in this.registeredComponentSelectors){this.removeComponentSelector(a)}this.removeObservers();return true},onViewInitialize:function(){var d,h,e,f,c,a,b,g;if(Ext.getVersion("extjs")!=null){this.getView().on("beforedestroy",this.onViewBeforeDestroy,this)}else{b=this;c=this.getView().destroy;this.getView().destroy=function(){if(b.destroy()){c.call(this)}}}g=this.control;for(h in g){d=g[h];a=null;if(h!=="view"){if(Ext.isString(d)){a=d}else{if(d.selector!=null){a=d.selector}else{a="#"+h}}}e=null;if(Ext.isObject(d.listeners)){e=d.listeners}else{if(!((d.selector!=null)||(d.live!=null))){e=d}}f=(d.live!=null)&&d.live;this.addComponentReference(h,a,f);this.addComponentSelector(a,e,f)}this.init()},onViewBeforeDestroy:function(){if(this.destroy()){this.getView().un("beforedestroy",this.onBeforeDestroy,this);return true}return false},addComponentReference:function(e,a,c){var b,d;if(c==null){c=false}Deft.Logger.log("Adding '"+e+"' component reference for selector: '"+a+"'.");if(this.registeredComponentReferences[e]!=null){Ext.Error.raise({msg:"Error adding component reference: an existing component reference was already registered as '"+e+"'."})}if(e!=="view"){b="get"+Ext.String.capitalize(e);if(this[b]==null){if(c){this[b]=Ext.Function.pass(this.getViewComponent,[a],this)}else{d=this.getViewComponent(a);if(d==null){Ext.Error.raise({msg:"Error locating component: no component(s) found matching '"+a+"'."})}this[b]=function(){return d}}this[b].generated=true}}this.registeredComponentReferences[e]=true},removeComponentReference:function(b){var a;Deft.Logger.log("Removing '"+b+"' component reference.");if(this.registeredComponentReferences[b]==null){Ext.Error.raise({msg:"Error removing component reference: no component reference is registered as '"+b+"'."})}if(b!=="view"){a="get"+Ext.String.capitalize(b);if(this[a].generated){this[a]=null}}delete this.registeredComponentReferences[b]},getViewComponent:function(a){var b;if(a!=null){b=Ext.ComponentQuery.query(a,this.getView());if(b.length===0){return null}else{if(b.length===1){return b[0]}else{return b}}}else{return this.getView()}},addComponentSelector:function(a,b,c){var d,e;if(c==null){c=false}Deft.Logger.log("Adding component selector for: '"+a+"'.");e=this.getComponentSelector(a);if(e!=null){Ext.Error.raise({msg:"Error adding component selector: an existing component selector was already registered for '"+a+"'."})}d=Ext.create("Deft.mvc.ComponentSelector",{view:this.getView(),selector:a,listeners:b,scope:this,live:c});this.registeredComponentSelectors[a]=d},removeComponentSelector:function(a){var b;Deft.Logger.log("Removing component selector for '"+a+"'.");b=this.getComponentSelector(a);if(b==null){Ext.Error.raise({msg:"Error removing component selector: no component selector registered for '"+a+"'."})}b.destroy();delete this.registeredComponentSelectors[a]},getComponentSelector:function(a){return this.registeredComponentSelectors[a]},createObservers:function(){var a,c,b;this.registeredObservers={};b=this.observe;for(c in b){a=b[c];this.addObserver(c,a)}},addObserver:function(c,b){var a;a=Ext.create("Deft.mvc.Observer",{host:this,target:c,events:b});return this.registeredObservers[c]=a},removeObservers:function(){var a,c,b;b=this.registeredObservers;for(c in b){a=b[c];a.destroy();delete this.registeredObservers[c]}}},function(){return Deft.Class.registerPreprocessor("observe",function(b,c,a,d){Deft.Class.hookOnClassExtended(c,function(f,h,e){var g;if(f.superclass&&((g=f.superclass)!=null?g.observe:void 0)&&Deft.Class.extendsClass("Deft.mvc.ViewController",f)){h.observe=Deft.mvc.Observer.mergeObserve(f.superclass.observe,h.observe)}})},"before","extend")});Ext.define("Deft.mvc.Application",{alternateClassName:["Deft.Application"],initialized:false,constructor:function(a){if(a==null){a={}}this.initConfig(a);Ext.onReady(function(){this.init();this.initialized=true},this);return this},init:function(){}});Ext.define("Deft.mixin.Controllable",{requires:["Ext.Container","Deft.core.Class","Deft.log.Logger"],onClassMixedIn:function(a){Deft.Logger.deprecate("Deft.mixin.Controllable has been deprecated and can now be omitted - simply use the 'controller' class annotation on its own.")}},function(){var a;if(Ext.getVersion("extjs")&&Ext.getVersion("core").isLessThan("4.1.0")){a=function(){return function(d){var b;if(d==null){d={}}if(this instanceof Ext.ClassManager.get("Ext.Container")&&!this.$controlled){try{b=Ext.create(this.controller,d.controllerConfig||this.controllerConfig||{})}catch(c){Deft.Logger.warn("Error initializing view controller: an error occurred while creating an instance of the specified controller: '"+this.controller+"'.");throw c}if(this.getController===void 0){this.getController=function(){return b}}this.$controlled=true;this.callOverridden(arguments);b.controlView(this);return this}return this.callOverridden(arguments)}}}else{a=function(){return function(d){var b;if(d==null){d={}}if(this instanceof Ext.ClassManager.get("Ext.Container")&&!this.$controlled){try{b=Ext.create(this.controller,d.controllerConfig||this.controllerConfig||{})}catch(c){Deft.Logger.warn("Error initializing view controller: an error occurred while creating an instance of the specified controller: '"+this.controller+"'.");throw c}if(this.getController===void 0){this.getController=function(){return b}}this.$controlled=true;this.callParent(arguments);b.controlView(this);return this}return this.callParent(arguments)}}}Deft.Class.registerPreprocessor("controller",function(d,e,b,f){var c;Deft.Class.hookOnClassCreated(b,function(g){g.override({constructor:a()})});Deft.Class.hookOnClassExtended(e,function(h,i,g){Deft.Class.hookOnClassCreated(g,function(j){j.override({constructor:a()})})});c=this;Ext.require([e.controller],function(){if(f!=null){f.call(c,d,e,b)}});return false},"before","extend")});Ext.define("Deft.promise.Promise",{alternateClassName:["Deft.Promise"],statics:{when:function(a){var b;if(a instanceof Ext.ClassManager.get("Deft.promise.Promise")||a instanceof Ext.ClassManager.get("Deft.promise.Deferred")){return a.then()}else{if(Ext.isObject(a)&&Ext.isFunction(a.then)){b=Ext.create("Deft.promise.Deferred");a.then(function(c){b.resolve(c)},function(c){b.reject(c)});return b.then()}else{b=Ext.create("Deft.promise.Deferred");b.resolve(a);return b.then()}}},all:function(a){return this.when(a).then({success:function(n){var q,l,i,h,r,d,e,j,p,k,m,c,f,s,g,b,o;r=Ext.create("Deft.promise.Deferred");s=n.length;c=new Array(n);m=0;g=function(t){r.update(t);return t};f=function(t,u){c[t]=u;m++;if(m===s){i();r.resolve(c)}return u};k=function(t){i();r.reject(t);return t};l=function(t){i();r.cancel(t);return t};i=function(){return g=f=k=l=Ext.emptyFn};h=function(t){return function(u){return f(t,u)}};d=function(t){return k(t)};j=function(t){return g(t)};q=function(t){return l(t)};for(e=b=0,o=n.length;b>>0;e=arguments;if(e.length<=1){while(true){if(d in g){c=g[d++];break}if(++d>=f){throw new TypeError()}}}else{c=e[1]}while(d-1},locateReferences:function(c,d,a){var b,e;b=c;if(this.isPropertyChain(d)){e=this.parsePropertyChain(c,d);if(!e){return null}c=e.host;d=e.target}if(Ext.isFunction(a)){return{target:this.locateTarget(c,d),handler:a}}else{if(Ext.isFunction(b[a])){return{target:this.locateTarget(c,d),handler:b[a]}}else{return null}}},parsePropertyChain:function(a,b){var c;if(Ext.isString(b)){c=b.split(".")}else{if(Ext.isArray(b)){c=b}else{return null}}if(c.length>1&&(this.locateTarget(a,c[0])!=null)){return this.parsePropertyChain(this.locateTarget(a,c[0]),c.slice(1))}else{if(this.isTargetObservable(a,c[0])){return{host:a,target:c[0]}}else{return null}}},destroy:function(){var d,c,a,b;b=this.listeners;for(c=0,a=b.length;c0){this.createObservers()}return this},controlView:function(a){if(a instanceof Ext.ClassManager.get("Ext.Container")){this.setView(a);this.registeredComponentReferences={};this.registeredComponentSelectors={};if(Ext.getVersion("extjs")!=null){if(this.getView().rendered){this.onViewInitialize()}else{this.getView().on("afterrender",this.onViewInitialize,this,{single:true})}}else{if(this.getView().initialized){this.onViewInitialize()}else{this.getView().on("initialize",this.onViewInitialize,this,{single:true})}}}else{Ext.Error.raise({msg:"Error constructing ViewController: the configured 'view' is not an Ext.Container."})}},init:function(){},destroy:function(){var b,a;for(b in this.registeredComponentReferences){this.removeComponentReference(b)}for(a in this.registeredComponentSelectors){this.removeComponentSelector(a)}this.removeObservers();return true},onViewInitialize:function(){var d,h,e,f,c,a,b,g;if(Ext.getVersion("extjs")!=null){this.getView().on("beforedestroy",this.onViewBeforeDestroy,this)}else{b=this;c=this.getView().destroy;this.getView().destroy=function(){if(b.destroy()){c.call(this)}}}g=this.control;for(h in g){d=g[h];a=null;if(h!=="view"){if(Ext.isString(d)){a=d}else{if(d.selector!=null){a=d.selector}else{a="#"+h}}}e=null;if(Ext.isObject(d.listeners)){e=d.listeners}else{if(!((d.selector!=null)||(d.live!=null))){e=d}}f=(d.live!=null)&&d.live;this.addComponentReference(h,a,f);this.addComponentSelector(a,e,f)}this.init()},onViewBeforeDestroy:function(){if(this.destroy()){this.getView().un("beforedestroy",this.onBeforeDestroy,this);return true}return false},addComponentReference:function(e,a,c){var b,d;if(c==null){c=false}Deft.Logger.log("Adding '"+e+"' component reference for selector: '"+a+"'.");if(this.registeredComponentReferences[e]!=null){Ext.Error.raise({msg:"Error adding component reference: an existing component reference was already registered as '"+e+"'."})}if(e!=="view"){b="get"+Ext.String.capitalize(e);if(this[b]==null){if(c){this[b]=Ext.Function.pass(this.getViewComponent,[a],this)}else{d=this.getViewComponent(a);if(d==null){Ext.Error.raise({msg:"Error locating component: no component(s) found matching '"+a+"'."})}this[b]=function(){return d}}this[b].generated=true}}this.registeredComponentReferences[e]=true},removeComponentReference:function(b){var a;Deft.Logger.log("Removing '"+b+"' component reference.");if(this.registeredComponentReferences[b]==null){Ext.Error.raise({msg:"Error removing component reference: no component reference is registered as '"+b+"'."})}if(b!=="view"){a="get"+Ext.String.capitalize(b);if(this[a].generated){this[a]=null}}delete this.registeredComponentReferences[b]},getViewComponent:function(a){var b;if(a!=null){b=Ext.ComponentQuery.query(a,this.getView());if(b.length===0){return null}else{if(b.length===1){return b[0]}else{return b}}}else{return this.getView()}},addComponentSelector:function(a,b,c){var d,e;if(c==null){c=false}Deft.Logger.log("Adding component selector for: '"+a+"'.");e=this.getComponentSelector(a);if(e!=null){Ext.Error.raise({msg:"Error adding component selector: an existing component selector was already registered for '"+a+"'."})}d=Ext.create("Deft.mvc.ComponentSelector",{view:this.getView(),selector:a,listeners:b,scope:this,live:c});this.registeredComponentSelectors[a]=d},removeComponentSelector:function(a){var b;Deft.Logger.log("Removing component selector for '"+a+"'.");b=this.getComponentSelector(a);if(b==null){Ext.Error.raise({msg:"Error removing component selector: no component selector registered for '"+a+"'."})}b.destroy();delete this.registeredComponentSelectors[a]},getComponentSelector:function(a){return this.registeredComponentSelectors[a]},createObservers:function(){var a,c,b;this.registeredObservers={};b=this.observe;for(c in b){a=b[c];this.addObserver(c,a)}},addObserver:function(c,b){var a;a=Ext.create("Deft.mvc.Observer",{host:this,target:c,events:b});return this.registeredObservers[c]=a},removeObservers:function(){var a,c,b;b=this.registeredObservers;for(c in b){a=b[c];a.destroy();delete this.registeredObservers[c]}}},function(){return Deft.Class.registerPreprocessor("observe",function(b,c,a,d){Deft.Class.hookOnClassExtended(c,function(f,h,e){var g;if(f.superclass&&((g=f.superclass)!=null?g.observe:void 0)&&Deft.Class.extendsClass("Deft.mvc.ViewController",f)){h.observe=Deft.mvc.Observer.mergeObserve(f.superclass.observe,h.observe)}})},"before","extend")});Ext.define("Deft.mvc.Application",{alternateClassName:["Deft.Application"],initialized:false,constructor:function(a){if(a==null){a={}}this.initConfig(a);Ext.onReady(function(){this.init();this.initialized=true},this);return this},init:function(){}});Ext.define("Deft.mixin.Controllable",{requires:["Ext.Container","Deft.core.Class","Deft.log.Logger"],onClassMixedIn:function(a){Deft.Logger.deprecate("Deft.mixin.Controllable has been deprecated and can now be omitted - simply use the 'controller' class annotation on its own.")}},function(){var a;if(Ext.getVersion("extjs")&&Ext.getVersion("core").isLessThan("4.1.0")){a=function(){return function(d){var b;if(d==null){d={}}if(this instanceof Ext.ClassManager.get("Ext.Container")&&!this.$controlled){try{b=Ext.create(this.controller,d.controllerConfig||this.controllerConfig||{})}catch(c){Deft.Logger.warn("Error initializing view controller: an error occurred while creating an instance of the specified controller: '"+this.controller+"'.");throw c}if(this.getController===void 0){this.getController=function(){return b}}this.$controlled=true;this.callOverridden(arguments);b.controlView(this);return this}return this.callOverridden(arguments)}}}else{a=function(){return function(d){var b;if(d==null){d={}}if(this instanceof Ext.ClassManager.get("Ext.Container")&&!this.$controlled){try{b=Ext.create(this.controller,d.controllerConfig||this.controllerConfig||{})}catch(c){Deft.Logger.warn("Error initializing view controller: an error occurred while creating an instance of the specified controller: '"+this.controller+"'.");throw c}if(this.getController===void 0){this.getController=function(){return b}}this.$controlled=true;this.callParent(arguments);b.controlView(this);return this}return this.callParent(arguments)}}}Deft.Class.registerPreprocessor("controller",function(d,e,b,f){var c;Deft.Class.hookOnClassCreated(b,function(g){g.override({constructor:a()})});Deft.Class.hookOnClassExtended(e,function(h,i,g){Deft.Class.hookOnClassCreated(g,function(j){j.override({constructor:a()})})});c=this;Ext.require([e.controller],function(){if(f!=null){f.call(c,d,e,b)}});return false},"before","extend")});Ext.define("Deft.promise.Promise",{alternateClassName:["Deft.Promise"],statics:{when:function(a){var b;if(a instanceof Ext.ClassManager.get("Deft.promise.Promise")||a instanceof Ext.ClassManager.get("Deft.promise.Deferred")){return a.then()}else{if(Ext.isObject(a)&&Ext.isFunction(a.then)){b=Ext.create("Deft.promise.Deferred");a.then(function(c){b.resolve(c)},function(c){b.reject(c)});return b.then()}else{b=Ext.create("Deft.promise.Deferred");b.resolve(a);return b.then()}}},all:function(a){return this.when(a).then({success:function(n){var q,l,i,h,r,d,e,j,p,k,m,c,f,s,g,b,o;r=Ext.create("Deft.promise.Deferred");s=n.length;c=new Array(n);m=0;g=function(t){r.update(t);return t};f=function(t,u){c[t]=u;m++;if(m===s){i();r.resolve(c)}return u};k=function(t){i();r.reject(t);return t};l=function(t){i();r.cancel(t);return t};i=function(){return g=f=k=l=Ext.emptyFn};h=function(t){return function(u){return f(t,u)}};d=function(t){return k(t)};j=function(t){return g(t)};q=function(t){return l(t)};for(e=b=0,o=n.length;b>>0;e=arguments;if(e.length<=1){while(true){if(d in g){c=g[d++];break}if(++d>=f){throw new TypeError()}}}else{c=e[1]}while(d return @actual.getState() is 'resolved' and wasSpyCalledWith( successCallback, value ) and not wasSpyCalled( failureCallback ) and not wasSpyCalled( progressCallback ) and not wasSpyCalled( cancelCallback ) - toRejectWith: ( message ) -> + toRejectWith: ( error ) -> successCallback = jasmine.createSpy( 'success callback' ) failureCallback = jasmine.createSpy( 'failure callback' ) progressCallback = jasmine.createSpy( 'progress callback' ) @@ -93,7 +93,7 @@ describe( 'Deft.promise.Promise', -> cancel: cancelCallback ) - return @actual.getState() is 'rejected' and not wasSpyCalled( successCallback ) and wasSpyCalledWith( failureCallback, message ) and not wasSpyCalled( progressCallback ) and not wasSpyCalled( cancelCallback ) + return @actual.getState() is 'rejected' and not wasSpyCalled( successCallback ) and wasSpyCalledWith( failureCallback, error ) and not wasSpyCalled( progressCallback ) and not wasSpyCalled( cancelCallback ) toUpdateWith: ( progress ) -> successCallback = jasmine.createSpy( 'success callback' ) @@ -1070,8 +1070,13 @@ describe( 'Deft.promise.Promise', -> describe( 'with a variety of combinations of values, Deferreds and Promises specified', -> - it( 'should return a resolved Promise when an Array containing any combination of pending Deferreds and/or pending Promises and a value is specified', -> - parameters = [ Ext.create( 'Deft.promise.Deferred' ), Ext.create( 'Deft.promise.Deferred' ).getPromise() ] + it( 'should return a resolved Promise when an Array containing any combination of pending, rejected and/or cancelled Deferreds and/or Promises, and a value is specified', -> + pendingDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred.reject( 'error message' ) + cancelledDeferred = Ext.create( 'Deft.promise.Deferred' ) + cancelledDeferred.cancel( 'reason' ) + parameters = [ pendingDeferred, pendingDeferred.getPromise(), rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise() ] for combination in generateCombinations( parameters ).concat( [] ) for permutation in generatePermutations( combination.concat( 'expected result' ) ) @@ -1090,8 +1095,13 @@ describe( 'Deft.promise.Promise', -> return ) - it( 'should return a resolved Promise when an Array containing any combination of pending Deferreds and/or pending Promises and a resolved Deferred or Promise is specified', -> - parameters = [ Ext.create( 'Deft.promise.Deferred' ), Ext.create( 'Deft.promise.Deferred' ).getPromise() ] + it( 'should return a resolved Promise when an Array containing any combination of pending, rejected and/or cancelled Deferreds and/or Promises, and a resolved Deferred or Promise is specified', -> + pendingDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred.reject( 'error message' ) + cancelledDeferred = Ext.create( 'Deft.promise.Deferred' ) + cancelledDeferred.cancel( 'reason' ) + parameters = [ pendingDeferred, pendingDeferred.getPromise(), rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise() ] resolvedDeferred = Ext.create( 'Deft.promise.Deferred' ) resolvedDeferred.resolve( 'expected result' ) @@ -1112,28 +1122,35 @@ describe( 'Deft.promise.Promise', -> return ) - it( 'should return a rejected Promise when an Array containing any combination of pending Deferreds, and/or pending Promises, and a rejected Deferred or Promise is specified', -> - parameters = [ Ext.create( 'Deft.promise.Deferred' ), Ext.create( 'Deft.promise.Deferred' ).getPromise() ] + it( 'should return a rejected Promise when an Array containing any combination of rejected and/or cancelled Deferreds and/or Promises is specified', -> rejectedDeferred = Ext.create( 'Deft.promise.Deferred' ) rejectedDeferred.reject( 'error message' ) + cancelledDeferred = Ext.create( 'Deft.promise.Deferred' ) + cancelledDeferred.cancel( 'reason' ) + parameters = [ rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise() ] - for combination in generateCombinations( parameters ).concat( [] ) - for permutation in generatePermutations( combination.concat( rejectedDeferred ) ) + for combination in generateCombinations( parameters ) + for permutation in generatePermutations( combination ) promise = Deft.promise.Promise.any( permutation ) expect( promise ).toBeInstanceOf( 'Deft.promise.Promise' ) - expect( promise ).toRejectWith( 'error message' ) + expect( promise ).toRejectWith( new Error( 'No Promises were resolved.' ) ) - for combination in generateCombinations( parameters ).concat( [] ) - for permutation in generatePermutations( combination.concat( rejectedDeferred.getPromise() ) ) + for combination in generateCombinations( parameters ) + for permutation in generatePermutations( combination ) promise = Deft.promise.Promise.any( permutation ) expect( promise ).toBeInstanceOf( 'Deft.promise.Promise' ) - expect( promise ).toRejectWith( 'error message' ) + expect( promise ).toRejectWith( new Error( 'No Promises were resolved.' ) ) ) - it( 'should return a pending (and immediately updated) Promise when an Array containing any combination of pending Deferreds, and/or pending Promises, and pending (and updated) Deferred or Promise is specified', -> - parameters = [ Ext.create( 'Deft.promise.Deferred' ), Ext.create( 'Deft.promise.Deferred' ).getPromise() ] + it( 'should return a pending (and immediately updated) Promise when an Array containing any combination of pending, rejected and/or cancelled Deferreds and/or Promises, and a pending (and updated) Deferred or Promise is specified', -> + pendingDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred.reject( 'error message' ) + cancelledDeferred = Ext.create( 'Deft.promise.Deferred' ) + cancelledDeferred.cancel( 'reason' ) + parameters = [ pendingDeferred, pendingDeferred.getPromise(), rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise() ] updatedDeferred = Ext.create( 'Deft.promise.Deferred' ) updatedDeferred.update( 'progress' ) @@ -1152,28 +1169,13 @@ describe( 'Deft.promise.Promise', -> expect( promise ).toUpdateWith( 'progress' ) ) - it( 'should return a cancelled Promise when an Array containing any combination of pending Deferreds, and/or pending Promises, and a cancelled Deferred or Promise is specified', -> - parameters = [ Ext.create( 'Deft.promise.Deferred' ), Ext.create( 'Deft.promise.Deferred' ).getPromise() ] + it( 'should return a resolved Promise when an Array containing any combination of pending, rejected and/or cancelled Deferreds and/or Promises, and a pending Deferred or Promise is specified that is later resolved', -> + pendingDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred.reject( 'error message' ) cancelledDeferred = Ext.create( 'Deft.promise.Deferred' ) cancelledDeferred.cancel( 'reason' ) - - for combination in generateCombinations( parameters ).concat( [] ) - for permutation in generatePermutations( combination.concat( cancelledDeferred ) ) - promise = Deft.promise.Promise.any( permutation ) - - expect( promise ).toBeInstanceOf( 'Deft.promise.Promise' ) - expect( promise ).toCancelWith( 'reason' ) - - for combination in generateCombinations( parameters ).concat( [] ) - for permutation in generatePermutations( combination.concat( cancelledDeferred.getPromise() ) ) - promise = Deft.promise.Promise.any( permutation ) - - expect( promise ).toBeInstanceOf( 'Deft.promise.Promise' ) - expect( promise ).toCancelWith( 'reason' ) - ) - - it( 'should return a resolved Promise when an Array containing any combination of pending Deferreds and/or pending Promises, and a pending Deferred or Promise is specified that is later resolved', -> - parameters = [ Ext.create( 'Deft.promise.Deferred' ), Ext.create( 'Deft.promise.Deferred' ).getPromise() ] + parameters = [ pendingDeferred, pendingDeferred.getPromise(), rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise() ] placeholder = {} for combination in generateCombinations( parameters ).concat( [] ) @@ -1209,8 +1211,12 @@ describe( 'Deft.promise.Promise', -> return ) - it( 'should return a rejected Promise when an Array containing any combination of pending Deferreds and/or pending Promises, and a pending Deferred or Promise is specified that is later rejected', -> - parameters = [ Ext.create( 'Deft.promise.Deferred' ), Ext.create( 'Deft.promise.Deferred' ).getPromise() ] + it( 'should return a rejected Promise when an Array containing any combination of rejected and/or cancelled Deferreds and/or Promises, and a pending Deferred or Promise is specified that is later rejected', -> + rejectedDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred.reject( 'error message' ) + cancelledDeferred = Ext.create( 'Deft.promise.Deferred' ) + cancelledDeferred.cancel( 'reason' ) + parameters = [ rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise() ] placeholder = {} for combination in generateCombinations( parameters ).concat( [] ) @@ -1226,7 +1232,7 @@ describe( 'Deft.promise.Promise', -> pendingDeferred.reject( 'error message' ) - expect( promise ).toRejectWith( 'error message' ) + expect( promise ).toRejectWith( new Error( 'No Promises were resolved.' ) ) for combination in generateCombinations( parameters ).concat( [] ) for permutation in generatePermutations( combination.concat( placeholder ) ) @@ -1241,13 +1247,18 @@ describe( 'Deft.promise.Promise', -> pendingDeferred.reject( 'error message' ) - expect( promise ).toRejectWith( 'error message' ) + expect( promise ).toRejectWith( new Error( 'No Promises were resolved.' ) ) return ) - it( 'should return a pending (and later updated) when an Array containing any combination of pending Deferreds and/or pending Promises, and a pending Deferred or Promise is specified that is later updated', -> - parameters = [ Ext.create( 'Deft.promise.Deferred' ), Ext.create( 'Deft.promise.Deferred' ).getPromise() ] + it( 'should return a pending (and later updated) when an Array containing any combination of pending, rejected and/or Deferreds and/or Promises, and a pending Deferred or Promise is specified that is later updated', -> + pendingDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred.reject( 'error message' ) + cancelledDeferred = Ext.create( 'Deft.promise.Deferred' ) + cancelledDeferred.cancel( 'reason' ) + parameters = [ pendingDeferred, pendingDeferred.getPromise(), rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise() ] placeholder = {} for combination in generateCombinations( parameters ).concat( [] ) @@ -1283,8 +1294,12 @@ describe( 'Deft.promise.Promise', -> return ) - it( 'should return a cancelled Promise when an Array containing any combination of pending Deferreds and/or pending Promises, and a pending Deferred or Promise is specified that is later cancelled', -> - parameters = [ Ext.create( 'Deft.promise.Deferred' ), Ext.create( 'Deft.promise.Deferred' ).getPromise() ] + it( 'should return a rejected Promise when an Array containing any combination of rejected and/or cancelled Deferreds and/or Promises, and a pending Deferred or Promise is specified that is later cancelled', -> + rejectedDeferred = Ext.create( 'Deft.promise.Deferred' ) + rejectedDeferred.reject( 'error message' ) + cancelledDeferred = Ext.create( 'Deft.promise.Deferred' ) + cancelledDeferred.cancel( 'reason' ) + parameters = [ rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise() ] placeholder = {} for combination in generateCombinations( parameters ).concat( [] ) @@ -1300,7 +1315,7 @@ describe( 'Deft.promise.Promise', -> pendingDeferred.cancel( 'reason' ) - expect( promise ).toCancelWith( 'reason' ) + expect( promise ).toRejectWith( new Error( 'No Promises were resolved.' ) ) for combination in generateCombinations( parameters ).concat( [] ) for permutation in generatePermutations( combination.concat( placeholder ) ) @@ -1315,7 +1330,7 @@ describe( 'Deft.promise.Promise', -> pendingDeferred.cancel( 'reason' ) - expect( promise ).toCancelWith( 'reason' ) + expect( promise ).toRejectWith( new Error( 'No Promises were resolved.' ) ) return ) diff --git a/spec/js/Deft/promise/Promise.js b/spec/js/Deft/promise/Promise.js index f51ee5d..80da334 100644 --- a/spec/js/Deft/promise/Promise.js +++ b/spec/js/Deft/promise/Promise.js @@ -86,7 +86,7 @@ describe('Deft.promise.Promise', function() { }); return this.actual.getState() === 'resolved' && wasSpyCalledWith(successCallback, value) && !wasSpyCalled(failureCallback) && !wasSpyCalled(progressCallback) && !wasSpyCalled(cancelCallback); }, - toRejectWith: function(message) { + toRejectWith: function(error) { var cancelCallback, failureCallback, progressCallback, successCallback; successCallback = jasmine.createSpy('success callback'); failureCallback = jasmine.createSpy('failure callback'); @@ -98,7 +98,7 @@ describe('Deft.promise.Promise', function() { progress: progressCallback, cancel: cancelCallback }); - return this.actual.getState() === 'rejected' && !wasSpyCalled(successCallback) && wasSpyCalledWith(failureCallback, message) && !wasSpyCalled(progressCallback) && !wasSpyCalled(cancelCallback); + return this.actual.getState() === 'rejected' && !wasSpyCalled(successCallback) && wasSpyCalledWith(failureCallback, error) && !wasSpyCalled(progressCallback) && !wasSpyCalled(cancelCallback); }, toUpdateWith: function(progress) { var cancelCallback, failureCallback, progressCallback, successCallback; @@ -936,9 +936,14 @@ describe('Deft.promise.Promise', function() { } }); describe('with a variety of combinations of values, Deferreds and Promises specified', function() { - it('should return a resolved Promise when an Array containing any combination of pending Deferreds and/or pending Promises and a value is specified', function() { - var combination, parameters, permutation, promise, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; - parameters = [Ext.create('Deft.promise.Deferred'), Ext.create('Deft.promise.Deferred').getPromise()]; + it('should return a resolved Promise when an Array containing any combination of pending, rejected and/or cancelled Deferreds and/or Promises, and a value is specified', function() { + var cancelledDeferred, combination, parameters, pendingDeferred, permutation, promise, rejectedDeferred, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; + pendingDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred.reject('error message'); + cancelledDeferred = Ext.create('Deft.promise.Deferred'); + cancelledDeferred.cancel('reason'); + parameters = [pendingDeferred, pendingDeferred.getPromise(), rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise()]; _ref = generateCombinations(parameters).concat([]); for (_i = 0, _len = _ref.length; _i < _len; _i++) { combination = _ref[_i]; @@ -962,9 +967,14 @@ describe('Deft.promise.Promise', function() { } } }); - it('should return a resolved Promise when an Array containing any combination of pending Deferreds and/or pending Promises and a resolved Deferred or Promise is specified', function() { - var combination, parameters, permutation, promise, resolvedDeferred, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; - parameters = [Ext.create('Deft.promise.Deferred'), Ext.create('Deft.promise.Deferred').getPromise()]; + it('should return a resolved Promise when an Array containing any combination of pending, rejected and/or cancelled Deferreds and/or Promises, and a resolved Deferred or Promise is specified', function() { + var cancelledDeferred, combination, parameters, pendingDeferred, permutation, promise, rejectedDeferred, resolvedDeferred, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; + pendingDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred.reject('error message'); + cancelledDeferred = Ext.create('Deft.promise.Deferred'); + cancelledDeferred.cancel('reason'); + parameters = [pendingDeferred, pendingDeferred.getPromise(), rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise()]; resolvedDeferred = Ext.create('Deft.promise.Deferred'); resolvedDeferred.resolve('expected result'); _ref = generateCombinations(parameters).concat([]); @@ -990,44 +1000,51 @@ describe('Deft.promise.Promise', function() { } } }); - it('should return a rejected Promise when an Array containing any combination of pending Deferreds, and/or pending Promises, and a rejected Deferred or Promise is specified', function() { - var combination, parameters, permutation, promise, rejectedDeferred, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results; - parameters = [Ext.create('Deft.promise.Deferred'), Ext.create('Deft.promise.Deferred').getPromise()]; + it('should return a rejected Promise when an Array containing any combination of rejected and/or cancelled Deferreds and/or Promises is specified', function() { + var cancelledDeferred, combination, parameters, permutation, promise, rejectedDeferred, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results; rejectedDeferred = Ext.create('Deft.promise.Deferred'); rejectedDeferred.reject('error message'); - _ref = generateCombinations(parameters).concat([]); + cancelledDeferred = Ext.create('Deft.promise.Deferred'); + cancelledDeferred.cancel('reason'); + parameters = [rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise()]; + _ref = generateCombinations(parameters); for (_i = 0, _len = _ref.length; _i < _len; _i++) { combination = _ref[_i]; - _ref1 = generatePermutations(combination.concat(rejectedDeferred)); + _ref1 = generatePermutations(combination); for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { permutation = _ref1[_j]; promise = Deft.promise.Promise.any(permutation); expect(promise).toBeInstanceOf('Deft.promise.Promise'); - expect(promise).toRejectWith('error message'); + expect(promise).toRejectWith(new Error('No Promises were resolved.')); } } - _ref2 = generateCombinations(parameters).concat([]); + _ref2 = generateCombinations(parameters); _results = []; for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { combination = _ref2[_k]; _results.push((function() { var _l, _len3, _ref3, _results1; - _ref3 = generatePermutations(combination.concat(rejectedDeferred.getPromise())); + _ref3 = generatePermutations(combination); _results1 = []; for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { permutation = _ref3[_l]; promise = Deft.promise.Promise.any(permutation); expect(promise).toBeInstanceOf('Deft.promise.Promise'); - _results1.push(expect(promise).toRejectWith('error message')); + _results1.push(expect(promise).toRejectWith(new Error('No Promises were resolved.'))); } return _results1; })()); } return _results; }); - it('should return a pending (and immediately updated) Promise when an Array containing any combination of pending Deferreds, and/or pending Promises, and pending (and updated) Deferred or Promise is specified', function() { - var combination, parameters, permutation, promise, updatedDeferred, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results; - parameters = [Ext.create('Deft.promise.Deferred'), Ext.create('Deft.promise.Deferred').getPromise()]; + it('should return a pending (and immediately updated) Promise when an Array containing any combination of pending, rejected and/or cancelled Deferreds and/or Promises, and a pending (and updated) Deferred or Promise is specified', function() { + var cancelledDeferred, combination, parameters, pendingDeferred, permutation, promise, rejectedDeferred, updatedDeferred, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results; + pendingDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred.reject('error message'); + cancelledDeferred = Ext.create('Deft.promise.Deferred'); + cancelledDeferred.cancel('reason'); + parameters = [pendingDeferred, pendingDeferred.getPromise(), rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise()]; updatedDeferred = Ext.create('Deft.promise.Deferred'); updatedDeferred.update('progress'); _ref = generateCombinations(parameters).concat([]); @@ -1060,44 +1077,14 @@ describe('Deft.promise.Promise', function() { } return _results; }); - it('should return a cancelled Promise when an Array containing any combination of pending Deferreds, and/or pending Promises, and a cancelled Deferred or Promise is specified', function() { - var cancelledDeferred, combination, parameters, permutation, promise, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _results; - parameters = [Ext.create('Deft.promise.Deferred'), Ext.create('Deft.promise.Deferred').getPromise()]; + it('should return a resolved Promise when an Array containing any combination of pending, rejected and/or cancelled Deferreds and/or Promises, and a pending Deferred or Promise is specified that is later resolved', function() { + var cancelledDeferred, combination, parameters, pendingDeferred, permutation, placeholder, promise, rejectedDeferred, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; + pendingDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred.reject('error message'); cancelledDeferred = Ext.create('Deft.promise.Deferred'); cancelledDeferred.cancel('reason'); - _ref = generateCombinations(parameters).concat([]); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - combination = _ref[_i]; - _ref1 = generatePermutations(combination.concat(cancelledDeferred)); - for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { - permutation = _ref1[_j]; - promise = Deft.promise.Promise.any(permutation); - expect(promise).toBeInstanceOf('Deft.promise.Promise'); - expect(promise).toCancelWith('reason'); - } - } - _ref2 = generateCombinations(parameters).concat([]); - _results = []; - for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) { - combination = _ref2[_k]; - _results.push((function() { - var _l, _len3, _ref3, _results1; - _ref3 = generatePermutations(combination.concat(cancelledDeferred.getPromise())); - _results1 = []; - for (_l = 0, _len3 = _ref3.length; _l < _len3; _l++) { - permutation = _ref3[_l]; - promise = Deft.promise.Promise.any(permutation); - expect(promise).toBeInstanceOf('Deft.promise.Promise'); - _results1.push(expect(promise).toCancelWith('reason')); - } - return _results1; - })()); - } - return _results; - }); - it('should return a resolved Promise when an Array containing any combination of pending Deferreds and/or pending Promises, and a pending Deferred or Promise is specified that is later resolved', function() { - var combination, parameters, pendingDeferred, permutation, placeholder, promise, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; - parameters = [Ext.create('Deft.promise.Deferred'), Ext.create('Deft.promise.Deferred').getPromise()]; + parameters = [pendingDeferred, pendingDeferred.getPromise(), rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise()]; placeholder = {}; _ref = generateCombinations(parameters).concat([]); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -1130,9 +1117,13 @@ describe('Deft.promise.Promise', function() { } } }); - it('should return a rejected Promise when an Array containing any combination of pending Deferreds and/or pending Promises, and a pending Deferred or Promise is specified that is later rejected', function() { - var combination, parameters, pendingDeferred, permutation, placeholder, promise, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; - parameters = [Ext.create('Deft.promise.Deferred'), Ext.create('Deft.promise.Deferred').getPromise()]; + it('should return a rejected Promise when an Array containing any combination of rejected and/or cancelled Deferreds and/or Promises, and a pending Deferred or Promise is specified that is later rejected', function() { + var cancelledDeferred, combination, parameters, pendingDeferred, permutation, placeholder, promise, rejectedDeferred, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; + rejectedDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred.reject('error message'); + cancelledDeferred = Ext.create('Deft.promise.Deferred'); + cancelledDeferred.cancel('reason'); + parameters = [rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise()]; placeholder = {}; _ref = generateCombinations(parameters).concat([]); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -1146,7 +1137,7 @@ describe('Deft.promise.Promise', function() { expect(promise).toBeInstanceOf('Deft.promise.Promise'); expect(promise.getState()).toBe('pending'); pendingDeferred.reject('error message'); - expect(promise).toRejectWith('error message'); + expect(promise).toRejectWith(new Error('No Promises were resolved.')); } } _ref2 = generateCombinations(parameters).concat([]); @@ -1161,13 +1152,18 @@ describe('Deft.promise.Promise', function() { expect(promise).toBeInstanceOf('Deft.promise.Promise'); expect(promise.getState()).toBe('pending'); pendingDeferred.reject('error message'); - expect(promise).toRejectWith('error message'); + expect(promise).toRejectWith(new Error('No Promises were resolved.')); } } }); - it('should return a pending (and later updated) when an Array containing any combination of pending Deferreds and/or pending Promises, and a pending Deferred or Promise is specified that is later updated', function() { - var combination, parameters, pendingDeferred, permutation, placeholder, promise, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; - parameters = [Ext.create('Deft.promise.Deferred'), Ext.create('Deft.promise.Deferred').getPromise()]; + it('should return a pending (and later updated) when an Array containing any combination of pending, rejected and/or Deferreds and/or Promises, and a pending Deferred or Promise is specified that is later updated', function() { + var cancelledDeferred, combination, parameters, pendingDeferred, permutation, placeholder, promise, rejectedDeferred, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; + pendingDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred.reject('error message'); + cancelledDeferred = Ext.create('Deft.promise.Deferred'); + cancelledDeferred.cancel('reason'); + parameters = [pendingDeferred, pendingDeferred.getPromise(), rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise()]; placeholder = {}; _ref = generateCombinations(parameters).concat([]); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -1200,9 +1196,13 @@ describe('Deft.promise.Promise', function() { } } }); - it('should return a cancelled Promise when an Array containing any combination of pending Deferreds and/or pending Promises, and a pending Deferred or Promise is specified that is later cancelled', function() { - var combination, parameters, pendingDeferred, permutation, placeholder, promise, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; - parameters = [Ext.create('Deft.promise.Deferred'), Ext.create('Deft.promise.Deferred').getPromise()]; + it('should return a rejected Promise when an Array containing any combination of rejected and/or cancelled Deferreds and/or Promises, and a pending Deferred or Promise is specified that is later cancelled', function() { + var cancelledDeferred, combination, parameters, pendingDeferred, permutation, placeholder, promise, rejectedDeferred, _i, _j, _k, _l, _len, _len1, _len2, _len3, _ref, _ref1, _ref2, _ref3; + rejectedDeferred = Ext.create('Deft.promise.Deferred'); + rejectedDeferred.reject('error message'); + cancelledDeferred = Ext.create('Deft.promise.Deferred'); + cancelledDeferred.cancel('reason'); + parameters = [rejectedDeferred, rejectedDeferred.getPromise(), cancelledDeferred, cancelledDeferred.getPromise()]; placeholder = {}; _ref = generateCombinations(parameters).concat([]); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -1216,7 +1216,7 @@ describe('Deft.promise.Promise', function() { expect(promise).toBeInstanceOf('Deft.promise.Promise'); expect(promise.getState()).toBe('pending'); pendingDeferred.cancel('reason'); - expect(promise).toCancelWith('reason'); + expect(promise).toRejectWith(new Error('No Promises were resolved.')); } } _ref2 = generateCombinations(parameters).concat([]); @@ -1231,7 +1231,7 @@ describe('Deft.promise.Promise', function() { expect(promise).toBeInstanceOf('Deft.promise.Promise'); expect(promise.getState()).toBe('pending'); pendingDeferred.cancel('reason'); - expect(promise).toCancelWith('reason'); + expect(promise).toRejectWith(new Error('No Promises were resolved.')); } } }); diff --git a/src/coffee/Deft/promise/Promise.coffee b/src/coffee/Deft/promise/Promise.coffee index a53d2e0..4dfe1f9 100644 --- a/src/coffee/Deft/promise/Promise.coffee +++ b/src/coffee/Deft/promise/Promise.coffee @@ -2,7 +2,7 @@ Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org) Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License). -Promise.when(), all(), any(), map() and reduce() methods adapted from: +Promise.when(), all(), any(), some(), map() and reduce() methods adapted from: [when.js](https://github.com/cujojs/when) Copyright (c) B Cavalier & J Hann Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License). @@ -97,47 +97,72 @@ Ext.define( 'Deft.promise.Promise', ###* - * Returns a new {@link Deft.promise.Promise} that will only resolve once any one of the the specified `promisesOrValues` has resolved. - * The resolution value will be the resolution value of the triggering `promiseOrValue`. + * Initiates a competitive race, returning a new {@link Deft.promise.Promise} that will resolve when any one of the supplied `promisesOrValues` + * have resolved, or will reject when all `promisesOrValues` have rejected or cancelled. + * The resolution value will the first value of `promisesOrValues` to resolve. ### any: ( promisesOrValues ) -> - return @when( promisesOrValues ).then( + return @some( promisesOrValues, 1 ).then( success: ( values ) -> return values[ 0 ] ) + + ###* + * Initiates a competitive race, returning a new {@link Deft.promise.Promise} that will resolve when `howMany` of the supplied `promisesOrValues` + * have resolved, or will reject when it becomes impossible for `howMany` to resolve. + * The resolution value will be an Array of the first `howMany` values of `promisesOrValues` to resolve. + ### + some: ( promisesOrValues, howMany ) -> + return @when( promisesOrValues ).then( success: ( promisesOrValues ) -> - deferred = Ext.create( 'Deft.promise.Deferred' ) + values = [] + remainingToResolve = howMany + remainingToReject = ( promisesOrValues.length - remainingToResolve ) + 1 - updater = ( progress ) -> - deferred.update( progress ) - return progress - resolver = ( value ) -> - complete() - deferred.resolve( value ) - return value - rejecter = ( error ) -> - complete() - deferred.reject( error ) - return error - canceller = ( reason ) -> - complete() - deferred.cancel( reason ) - return reason - - complete = -> - updater = resolver = rejecter = canceller = Ext.emptyFn - - successFunction = ( value ) -> resolver( value ) - failureFunction = ( value ) -> rejecter( value ) - progressFunction = ( value ) -> updater( value ) - cancelFunction = ( value ) -> canceller( value ) + deferred = Ext.create( 'Deft.promise.Deferred' ) - for promiseOrValue, index in promisesOrValues - if index of promisesOrValues - @when( promiseOrValue ) - .then( - success: successFunction - failure: failureFunction - progress: progressFunction - cancel: cancelFunction - ) + if promisesOrValues.length < howMany + deferred.reject( new Error( 'Too few Promises or values were supplied to obtain the requested number of resolved values.' ) ) + else + errorMessage = if howMany is 1 then 'No Promises were resolved.' else 'Too few Promises were resolved.' + + updater = ( progress ) -> + deferred.update( progress ) + return progress + resolver = ( value ) -> + values.push( value ) + remainingToResolve-- + if remainingToResolve is 0 + complete() + deferred.resolve( values ) + return value + rejecter = ( error ) -> + remainingToReject-- + if remainingToReject is 0 + complete() + deferred.reject( new Error( errorMessage ) ) + return error + canceller = ( reason ) -> + remainingToReject-- + if remainingToReject is 0 + complete() + deferred.reject( new Error( errorMessage ) ) + return reason + + complete = -> + updater = resolver = rejecter = canceller = Ext.emptyFn + + successFunction = ( value ) -> resolver( value ) + failureFunction = ( value ) -> rejecter( value ) + progressFunction = ( value ) -> updater( value ) + cancelFunction = ( value ) -> canceller( value ) + + for promiseOrValue, index in promisesOrValues + if index of promisesOrValues + @when( promiseOrValue ) + .then( + success: successFunction + failure: failureFunction + progress: progressFunction + cancel: cancelFunction + ) return deferred.getPromise() scope: @ diff --git a/src/js/Deft/promise/Promise.js b/src/js/Deft/promise/Promise.js index 19ff88a..02f5269 100644 --- a/src/js/Deft/promise/Promise.js +++ b/src/js/Deft/promise/Promise.js @@ -3,7 +3,7 @@ Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org) Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License). -Promise.when(), all(), any(), map() and reduce() methods adapted from: +Promise.when(), all(), any(), some(), map() and reduce() methods adapted from: [when.js](https://github.com/cujojs/when) Copyright (c) B Cavalier & J Hann Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License). @@ -110,58 +110,90 @@ Ext.define('Deft.promise.Promise', { }); }, /** - * Returns a new {@link Deft.promise.Promise} that will only resolve once any one of the the specified `promisesOrValues` has resolved. - * The resolution value will be the resolution value of the triggering `promiseOrValue`. + * Initiates a competitive race, returning a new {@link Deft.promise.Promise} that will resolve when any one of the supplied `promisesOrValues` + * have resolved, or will reject when all `promisesOrValues` have rejected or cancelled. + * The resolution value will the first value of `promisesOrValues` to resolve. */ any: function(promisesOrValues) { + return this.some(promisesOrValues, 1).then({ + success: function(values) { + return values[0]; + } + }); + }, + /** + * Initiates a competitive race, returning a new {@link Deft.promise.Promise} that will resolve when `howMany` of the supplied `promisesOrValues` + * have resolved, or will reject when it becomes impossible for `howMany` to resolve. + * The resolution value will be an Array of the first `howMany` values of `promisesOrValues` to resolve. + */ + + some: function(promisesOrValues, howMany) { return this.when(promisesOrValues).then({ success: function(promisesOrValues) { - var cancelFunction, canceller, complete, deferred, failureFunction, index, progressFunction, promiseOrValue, rejecter, resolver, successFunction, updater, _i, _len; + var cancelFunction, canceller, complete, deferred, errorMessage, failureFunction, index, progressFunction, promiseOrValue, rejecter, remainingToReject, remainingToResolve, resolver, successFunction, updater, values, _i, _len; + values = []; + remainingToResolve = howMany; + remainingToReject = (promisesOrValues.length - remainingToResolve) + 1; deferred = Ext.create('Deft.promise.Deferred'); - updater = function(progress) { - deferred.update(progress); - return progress; - }; - resolver = function(value) { - complete(); - deferred.resolve(value); - return value; - }; - rejecter = function(error) { - complete(); - deferred.reject(error); - return error; - }; - canceller = function(reason) { - complete(); - deferred.cancel(reason); - return reason; - }; - complete = function() { - return updater = resolver = rejecter = canceller = Ext.emptyFn; - }; - successFunction = function(value) { - return resolver(value); - }; - failureFunction = function(value) { - return rejecter(value); - }; - progressFunction = function(value) { - return updater(value); - }; - cancelFunction = function(value) { - return canceller(value); - }; - for (index = _i = 0, _len = promisesOrValues.length; _i < _len; index = ++_i) { - promiseOrValue = promisesOrValues[index]; - if (index in promisesOrValues) { - this.when(promiseOrValue).then({ - success: successFunction, - failure: failureFunction, - progress: progressFunction, - cancel: cancelFunction - }); + if (promisesOrValues.length < howMany) { + deferred.reject(new Error('Too few Promises or values were supplied to obtain the requested number of resolved values.')); + } else { + errorMessage = howMany === 1 ? 'No Promises were resolved.' : 'Too few Promises were resolved.'; + updater = function(progress) { + deferred.update(progress); + return progress; + }; + resolver = function(value) { + values.push(value); + remainingToResolve--; + if (remainingToResolve === 0) { + complete(); + deferred.resolve(values); + } + return value; + }; + rejecter = function(error) { + remainingToReject--; + if (remainingToReject === 0) { + complete(); + deferred.reject(new Error(errorMessage)); + } + return error; + }; + canceller = function(reason) { + remainingToReject--; + if (remainingToReject === 0) { + complete(); + deferred.reject(new Error(errorMessage)); + } + return reason; + }; + complete = function() { + return updater = resolver = rejecter = canceller = Ext.emptyFn; + }; + successFunction = function(value) { + return resolver(value); + }; + failureFunction = function(value) { + return rejecter(value); + }; + progressFunction = function(value) { + return updater(value); + }; + cancelFunction = function(value) { + return canceller(value); + }; + for (index = _i = 0, _len = promisesOrValues.length; _i < _len; index = ++_i) { + promiseOrValue = promisesOrValues[index]; + if (index in promisesOrValues) { + this.when(promiseOrValue).then({ + success: successFunction, + failure: failureFunction, + progress: progressFunction, + cancel: cancelFunction + }); + } } } return deferred.getPromise();