Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 13 commits
  • 32 files changed
  • 0 commit comments
  • 2 contributors
Commits on May 14, 2012
@johnyanarella johnyanarella Enhanced IoC container to support classes defined as singletons using…
… the Sencha class system.

Modified Deft.ioc.DependencyProvider to properly resolve and detect error conditions when a class is specified that was defined as a singleton using the Sencha class system.
Added associated Jasmine tests for configuring and injecting classes defined as singletons using the Sencha class system.
Updated version history in README.md.

Fixes #11
85e7cf3
Commits on May 16, 2012
@joshnesbitt joshnesbitt Updated Jasmine to 1.2.0. 24e2c17
@joshnesbitt joshnesbitt Merge branch 'feature_update_jasmine' 51b31bf
@joshnesbitt joshnesbitt Re-throw error if a controller class is missing in order to propagate…
… Ext load errors as normal.
a21ce34
Commits on May 20, 2012
@johnyanarella johnyanarella Controllable mixin should automatically Ext.require() referenced View…
… Controller classes

Modified `Deft.mixin.Controllable` to automatically `Ext.require()` the referenced view controller class(es).
Updated generated JavaScript output via CoffeeScript 1.3.3.

Fixes #17
449ec7f
@johnyanarella johnyanarella Merge remote-tracking branch 'joshnesbitt/master' into develop/0.6.6
Fixes #14
Fixes #15
d101a2a
@johnyanarella johnyanarella Tweaked Injectable Jasmine unit test.
Removed unnecessary `return`.
5c5e77a
@johnyanarella johnyanarella Controllable mixin should automatically Ext.require() referenced View…
… Controller classes

Introduced a new Class pre-processor for the `controller` annotation which conditionally calls `Ext.require()` for required classes and applies Controllable behavior whenever it detects the target class is includes the`Deft.mixin.Controllable` mix-in.
Now relying on Ext.Loader() to report some errors that were previously handled internally.
Removed `Deft.mixin.Controllable` test cases that are no longer applicable.
Refactored previous fix for #14 and #15 to align with the new Class pre-processor oriented architecture.

Fixes #17
e3f96d4
Commits on May 22, 2012
@johnyanarella johnyanarella Fixed HTML formatting. 193a841
@johnyanarella johnyanarella Tweaked logging message in Controllable.
Minor revision to previous fix.

Fixes #14
Fixes #15
7a67d91
@johnyanarella johnyanarella Injector throws a more useful error when unable to resolve an nonexis…
…tent or not yet `Ext.require()`-ed class.

Improved error handling and reporting associated with configuring the Injector with classes that have either not yet been `Ext.require()`-ed or do not exist.
Added logic similar to `Ext.ClassManager::instantiate()` for warning and synchronously loading classes that were not `Ext.require()`-ed before configuring `Deft.Injector`.

Fixes #16
49d026e
@johnyanarella johnyanarella Updated README.md
Revised version history to reflect v0.6.6 release.
9a351fe
@johnyanarella johnyanarella Fixed bug in Ext JS 4.0.7 compatibility logic in Controllable auto-Ex…
…t.require() enhancement.

Bitten by a JavaScript quirk: altering a function parameter also modifies `arguments`, so clone it to a true Array first.

Fixes #17
7dbd36f
Showing with 1,618 additions and 712 deletions.
  1. +2 −0  README.md
  2. +73 −26 build/deft-debug.js
  3. +26 −23 build/deft.js
  4. +10 −15 spec/SpecRunner.html
  5. +235 −0 spec/coffee/Deft/ioc/Injector.coffee
  6. +19 −23 spec/coffee/Deft/mixin/Controllable.coffee
  7. +2 −0  spec/coffee/Deft/mixin/Injectable.coffee
  8. +150 −2 spec/js/Deft/ioc/Injector.js
  9. +16 −22 spec/js/Deft/mixin/Controllable.js
  10. +2 −2 spec/js/Deft/mixin/Injectable.js
  11. +1 −1  spec/js/Deft/mvc/ViewController.js
  12. +1 −1  spec/js/Deft/promise/Deferred.js
  13. +1 −1  spec/js/Deft/promise/Promise.js
  14. +1 −1  spec/js/Deft/util/Function.js
  15. +0 −190 spec/lib/jasmine-1.1.0/jasmine-html.js
  16. +0 −166 spec/lib/jasmine-1.1.0/jasmine.css
  17. BIN  spec/lib/jasmine-1.1.0/jasmine_favicon.png
  18. 0  spec/lib/{jasmine-1.1.0 → jasmine-1.2.0}/MIT.LICENSE
  19. +616 −0 spec/lib/jasmine-1.2.0/jasmine-html.js
  20. +81 −0 spec/lib/jasmine-1.2.0/jasmine.css
  21. +245 −192 spec/lib/{jasmine-1.1.0 → jasmine-1.2.0}/jasmine.js
  22. +27 −5 src/coffee/Deft/ioc/DependencyProvider.coffee
  23. +34 −13 src/coffee/Deft/mixin/Controllable.coffee
  24. +38 −4 src/js/Deft/ioc/DependencyProvider.js
  25. +1 −1  src/js/Deft/ioc/Injector.js
  26. +1 −1  src/js/Deft/log/Logger.js
  27. +31 −18 src/js/Deft/mixin/Controllable.js
  28. +1 −1  src/js/Deft/mixin/Injectable.js
  29. +1 −1  src/js/Deft/mvc/ViewController.js
  30. +1 −1  src/js/Deft/promise/Deferred.js
  31. +1 −1  src/js/Deft/promise/Promise.js
  32. +1 −1  src/js/Deft/util/Function.js
View
2  README.md
@@ -479,6 +479,8 @@ Provided the specified `controller` extends `Deft.mvc.ViewController`, the contr
# Version History
+* 0.6.6 - Fixes to improve error handling and reporting; especially those associated with nonexistent classes and classes that were not Ext.require()-ed.
+* 0.6.5 - Enhanced IoC container to support classes defined as singletons using the Sencha class system.
* 0.6.4 - Hotfix for Sencha Touch Logger issue.
* 0.6.3 - Added memoization feature. Fixed reported Sencha Touch issues.
* 0.6.2 - Added support for View Controller event listener options. Ext JS 4.1rc3 compatibility fixes.
View
99 build/deft-debug.js
@@ -1,5 +1,5 @@
/*
-DeftJS 0.6.4
+DeftJS 0.6.6
Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org)
Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
@@ -84,6 +84,7 @@ Ext.define('Deft.util.Function', {
Used by {@link Deft.ioc.Injector}.
*/
+
Ext.define('Deft.ioc.DependencyProvider', {
requires: ['Deft.log.Logger'],
config: {
@@ -124,6 +125,7 @@ Ext.define('Deft.ioc.DependencyProvider', {
eager: false
},
constructor: function(config) {
+ var classDefinition;
this.initConfig(config);
if ((config.value != null) && config.value.constructor === Object) {
this.setValue(config.value);
@@ -140,12 +142,40 @@ Ext.define('Deft.ioc.DependencyProvider', {
});
}
}
+ if (this.getClassName() != null) {
+ classDefinition = Ext.ClassManager.get(this.getClassName());
+ if (!(classDefinition != null)) {
+ Deft.Logger.warn("Synchronously loading '" + (this.getClassName()) + "'; consider adding Ext.require('" + (this.getClassName()) + "') above Ext.onReady.");
+ Ext.syncRequire(this.getClassName());
+ classDefinition = Ext.ClassManager.get(this.getClassName());
+ }
+ if (!(classDefinition != null)) {
+ Ext.Error.raise({
+ msg: "Error while configuring rule for '" + (this.getIdentifier()) + "': unrecognized class name or alias: '" + (this.getClassName()) + "'"
+ });
+ }
+ }
if (!this.getSingleton()) {
+ if (this.getClassName() != null) {
+ if (Ext.ClassManager.get(this.getClassName()).singleton) {
+ Ext.Error.raise({
+ msg: "Error while configuring rule for '" + (this.getIdentifier()) + "': singleton classes cannot be configured for injection as a prototype. Consider removing 'singleton: true' from the class definition."
+ });
+ }
+ }
if (this.getValue() != null) {
Ext.Error.raise({
msg: "Error while configuring '" + (this.getIdentifier()) + "': a 'value' can only be configured as a singleton."
});
}
+ } else {
+ if ((this.getClassName() != null) && (this.getParameters() != null)) {
+ if (Ext.ClassManager.get(this.getClassName()).singleton) {
+ Ext.Error.raise({
+ msg: "Error while configuring rule for '" + (this.getIdentifier()) + "': parameters cannot be applied to singleton classes. Consider removing 'singleton: true' from the class definition."
+ });
+ }
+ }
}
return this;
},
@@ -164,9 +194,14 @@ Ext.define('Deft.ioc.DependencyProvider', {
Deft.Logger.log("Executing factory function.");
instance = this.getFn().call(null, targetInstance);
} else if (this.getClassName() != null) {
- Deft.Logger.log("Creating instance of '" + (this.getClassName()) + "'.");
- parameters = this.getParameters() != null ? [this.getClassName()].concat(this.getParameters()) : [this.getClassName()];
- instance = Ext.create.apply(this, parameters);
+ if (Ext.ClassManager.get(this.getClassName()).singleton) {
+ Deft.Logger.log("Using existing singleton instance of '" + (this.getClassName()) + "'.");
+ instance = Ext.ClassManager.get(this.getClassName());
+ } else {
+ Deft.Logger.log("Creating instance of '" + (this.getClassName()) + "'.");
+ parameters = this.getParameters() != null ? [this.getClassName()].concat(this.getParameters()) : [this.getClassName()];
+ instance = Ext.create.apply(this, parameters);
+ }
} else {
Ext.Error.raise({
msg: "Error while configuring rule for '" + (this.getIdentifier()) + "': no 'value', 'fn', or 'className' was specified."
@@ -184,11 +219,6 @@ A lightweight IoC container for dependency injection.
Used in conjunction with {@link Deft.mixin.Injectable}.
*/
-/**
-A lightweight IoC container for dependency injection.
-
-Used in conjunction with {@link Deft.mixin.Injectable}.
-*/
Ext.define('Deft.ioc.Injector', {
alternateClassName: ['Deft.Injector'],
@@ -303,6 +333,7 @@ A mixin that marks a class as participating in dependency injection.
Used in conjunction with {@link Deft.ioc.Injector}.
*/
+
Ext.define('Deft.mixin.Injectable', {
requires: ['Deft.ioc.Injector'],
/**
@@ -321,6 +352,7 @@ A lightweight MVC view controller.
Used in conjunction with {@link Deft.mixin.Controllable}.
*/
+
Ext.define('Deft.mvc.ViewController', {
alternateClassName: ['Deft.ViewController'],
requires: ['Deft.log.Logger'],
@@ -588,21 +620,25 @@ A mixin that creates and attaches the specified view controller(s) to the target
Used in conjunction with {@link Deft.mvc.ViewController}.
*/
-Ext.define('Deft.mixin.Controllable', {
- requires: ['Deft.mvc.ViewController'],
- /**
- @private
- */
- onClassMixedIn: function(targetClass) {
- targetClass.prototype.constructor = Ext.Function.createSequence(targetClass.prototype.constructor, function() {
- var controllerClass, controllers, _i, _len;
- if (!(this.controller != null)) {
- Ext.Error.raise({
- msg: 'Error initializing Controllable instance: \`controller\` was not specified.'
- });
- }
- controllers = Ext.isArray(this.controller) ? this.controller : [this.controller];
+Ext.define('Deft.mixin.Controllable', {});
+
+Ext.Class.registerPreprocessor('controller', function(Class, data, hooks, callback) {
+ var controller, controllers, parameters, self;
+ if (arguments.length === 3) {
+ parameters = Ext.toArray(arguments);
+ hooks = parameters[1];
+ callback = parameters[2];
+ }
+ if ((data.mixins != null) && Ext.Array.contains(data.mixins, Ext.ClassManager.get('Deft.mixin.Controllable'))) {
+ controller = data.controller;
+ delete data.controller;
+ controllers = [];
+ if (controller != null) {
+ controllers = Ext.isArray(controller) ? controller : [controller];
+ }
+ Class.prototype.constructor = Ext.Function.createSequence(Class.prototype.constructor, function() {
+ var controllerClass, _i, _len;
for (_i = 0, _len = controllers.length; _i < _len; _i++) {
controllerClass = controllers[_i];
try {
@@ -610,15 +646,25 @@ Ext.define('Deft.mixin.Controllable', {
view: this
});
} catch (error) {
- Ext.Error.raise({
- msg: "Error initializing Controllable instance: an error occurred while creating an instance of the specified controller: '" + this.controller + "'."
- });
+ Deft.Logger.warn("Error initializing Controllable instance: an error occurred while creating an instance of the specified controller: '" + controllerClass + "'.");
+ throw error;
}
}
});
+ if (controllers.length > 0) {
+ self = this;
+ Ext.require(controllers, function() {
+ if (callback != null) {
+ callback.call(self, Class, data, hooks);
+ }
+ });
+ return false;
+ }
}
});
+Ext.Class.setDefaultPreprocessorPosition('controller', 'before', 'mixins');
+
Ext.define('Deft.promise.Deferred', {
alternateClassName: ['Deft.Deferred'],
constructor: function() {
@@ -818,6 +864,7 @@ Promise.when(), all(), any(), map() and reduce() methods adapted from:
Copyright (c) B Cavalier & J Hann
Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
*/
+
Ext.define('Deft.promise.Promise', {
alternateClassName: ['Deft.Promise'],
statics: {
View
49 build/deft.js
@@ -1,34 +1,37 @@
/*
-DeftJS 0.6.4
+DeftJS 0.6.6
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.log.Logger",{alternateClassName:["Deft.Logger"],singleton:!0,log:function(){},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;Ext.isFunction(null!=(a=Ext.Logger)?a.log:void 0)?this.log=Ext.bind(Ext.Logger.log,Ext.Logger):Ext.isFunction(Ext.log)&&(this.log=function(a,b){null==b&&(b="info");"deprecate"===b&&(b="warn");
-Ext.log({msg:a,level:b})})});Ext.define("Deft.util.Function",{alternateClassName:["Deft.Function"],statics:{spread:function(a,c){return function(b){Ext.isArray(b)||Ext.Error.raise({msg:"Error spreading passed Array over target function arguments: passed a non-Array."});return a.apply(c,b)}},memoize:function(a,c,b){var d;d={};return function(e){var g;g=Ext.isFunction(b)?b.apply(c,arguments):e;g in d||(d[g]=a.apply(c,arguments));return d[g]}}}});
+Ext.log({msg:a,level:b})})});Ext.define("Deft.util.Function",{alternateClassName:["Deft.Function"],statics:{spread:function(a,c){return function(b){Ext.isArray(b)||Ext.Error.raise({msg:"Error spreading passed Array over target function arguments: passed a non-Array."});return a.apply(c,b)}},memoize:function(a,c,b){var e;e={};return function(d){var f;f=Ext.isFunction(b)?b.apply(c,arguments):d;f in e||(e[f]=a.apply(c,arguments));return e[f]}}}});
Ext.define("Deft.ioc.DependencyProvider",{requires:["Deft.log.Logger"],config:{identifier:null,className:null,parameters:null,fn:null,value:null,singleton:!0,eager:!1},constructor:function(a){this.initConfig(a);null!=a.value&&a.value.constructor===Object&&this.setValue(a.value);this.getEager()&&(null!=this.getValue()&&Ext.Error.raise({msg:"Error while configuring '"+this.getIdentifier()+"': a 'value' cannot be created eagerly."}),this.getSingleton()||Ext.Error.raise({msg:"Error while configuring '"+
-this.getIdentifier()+"': only singletons can be created eagerly."}));this.getSingleton()||null!=this.getValue()&&Ext.Error.raise({msg:"Error while configuring '"+this.getIdentifier()+"': a 'value' can only be configured as a singleton."});return this},resolve:function(a){var c;Deft.Logger.log("Resolving '"+this.getIdentifier()+"'.");if(null!=this.getValue())return this.getValue();c=null;null!=this.getFn()?(Deft.Logger.log("Executing factory function."),c=this.getFn().call(null,a)):null!=this.getClassName()?
-(Deft.Logger.log("Creating instance of '"+this.getClassName()+"'."),a=null!=this.getParameters()?[this.getClassName()].concat(this.getParameters()):[this.getClassName()],c=Ext.create.apply(this,a)):Ext.Error.raise({msg:"Error while configuring rule for '"+this.getIdentifier()+"': no 'value', 'fn', or 'className' was specified."});this.getSingleton()&&this.setValue(c);return c}});
-Ext.define("Deft.ioc.Injector",{alternateClassName:["Deft.Injector"],requires:["Deft.log.Logger","Deft.ioc.DependencyProvider"],singleton:!0,constructor:function(){this.providers={};return this},configure:function(a){Deft.Logger.log("Configuring injector.");Ext.Object.each(a,function(a,b){var d;Deft.Logger.log("Configuring dependency provider for '"+a+"'.");d=Ext.isString(b)?Ext.create("Deft.ioc.DependencyProvider",{identifier:a,className:b}):Ext.create("Deft.ioc.DependencyProvider",Ext.apply({identifier:a},
-b));this.providers[a]=d},this);Ext.Object.each(this.providers,function(a,b){b.getEager()&&(Deft.Logger.log("Eagerly creating '"+b.getIdentifier()+"'."),b.resolve())},this)},canResolve:function(a){return null!=this.providers[a]},resolve:function(a,c){var b;b=this.providers[a];if(null!=b)return b.resolve(c);Ext.Error.raise({msg:"Error while resolving value to inject: no dependency provider found for '"+a+"'."})},inject:function(a,c,b){var d,e,g,f;null==b&&(b=!0);d={};Ext.isString(a)&&(a=[a]);Ext.Object.each(a,
-function(b,e){var g,f;f=Ext.isArray(a)?e:b;g=this.resolve(e,c);f in c.config?(Deft.Logger.log("Injecting '"+e+"' into '"+f+"' config."),d[f]=g):(Deft.Logger.log("Injecting '"+e+"' into '"+f+"' property."),c[f]=g)},this);if(b)for(e in d)f=d[e],b="set"+Ext.String.capitalize(e),c[b].call(c,f);else Ext.isFunction(c.initConfig)&&(g=c.initConfig,c.initConfig=function(a){return g.call(this,Ext.Object.merge({},a||{},d))});return c}});
+this.getIdentifier()+"': only singletons can be created eagerly."}));null!=this.getClassName()&&(a=Ext.ClassManager.get(this.getClassName()),null==a&&(Deft.Logger.warn("Synchronously loading '"+this.getClassName()+"'; consider adding Ext.require('"+this.getClassName()+"') above Ext.onReady."),Ext.syncRequire(this.getClassName()),a=Ext.ClassManager.get(this.getClassName())),null==a&&Ext.Error.raise({msg:"Error while configuring rule for '"+this.getIdentifier()+"': unrecognized class name or alias: '"+
+this.getClassName()+"'"}));this.getSingleton()?null!=this.getClassName()&&null!=this.getParameters()&&Ext.ClassManager.get(this.getClassName()).singleton&&Ext.Error.raise({msg:"Error while configuring rule for '"+this.getIdentifier()+"': parameters cannot be applied to singleton classes. Consider removing 'singleton: true' from the class definition."}):(null!=this.getClassName()&&Ext.ClassManager.get(this.getClassName()).singleton&&Ext.Error.raise({msg:"Error while configuring rule for '"+this.getIdentifier()+
+"': singleton classes cannot be configured for injection as a prototype. Consider removing 'singleton: true' from the class definition."}),null!=this.getValue()&&Ext.Error.raise({msg:"Error while configuring '"+this.getIdentifier()+"': a 'value' can only be configured as a singleton."}));return this},resolve:function(a){var c;Deft.Logger.log("Resolving '"+this.getIdentifier()+"'.");if(null!=this.getValue())return this.getValue();c=null;null!=this.getFn()?(Deft.Logger.log("Executing factory function."),
+c=this.getFn().call(null,a)):null!=this.getClassName()?Ext.ClassManager.get(this.getClassName()).singleton?(Deft.Logger.log("Using existing singleton instance of '"+this.getClassName()+"'."),c=Ext.ClassManager.get(this.getClassName())):(Deft.Logger.log("Creating instance of '"+this.getClassName()+"'."),a=null!=this.getParameters()?[this.getClassName()].concat(this.getParameters()):[this.getClassName()],c=Ext.create.apply(this,a)):Ext.Error.raise({msg:"Error while configuring rule for '"+this.getIdentifier()+
+"': no 'value', 'fn', or 'className' was specified."});this.getSingleton()&&this.setValue(c);return c}});
+Ext.define("Deft.ioc.Injector",{alternateClassName:["Deft.Injector"],requires:["Deft.log.Logger","Deft.ioc.DependencyProvider"],singleton:!0,constructor:function(){this.providers={};return this},configure:function(a){Deft.Logger.log("Configuring injector.");Ext.Object.each(a,function(a,b){var e;Deft.Logger.log("Configuring dependency provider for '"+a+"'.");e=Ext.isString(b)?Ext.create("Deft.ioc.DependencyProvider",{identifier:a,className:b}):Ext.create("Deft.ioc.DependencyProvider",Ext.apply({identifier:a},
+b));this.providers[a]=e},this);Ext.Object.each(this.providers,function(a,b){b.getEager()&&(Deft.Logger.log("Eagerly creating '"+b.getIdentifier()+"'."),b.resolve())},this)},canResolve:function(a){return null!=this.providers[a]},resolve:function(a,c){var b;b=this.providers[a];if(null!=b)return b.resolve(c);Ext.Error.raise({msg:"Error while resolving value to inject: no dependency provider found for '"+a+"'."})},inject:function(a,c,b){var e,d,f,g;null==b&&(b=!0);e={};Ext.isString(a)&&(a=[a]);Ext.Object.each(a,
+function(b,d){var f,g;g=Ext.isArray(a)?d:b;f=this.resolve(d,c);g in c.config?(Deft.Logger.log("Injecting '"+d+"' into '"+g+"' config."),e[g]=f):(Deft.Logger.log("Injecting '"+d+"' into '"+g+"' property."),c[g]=f)},this);if(b)for(d in e)g=e[d],b="set"+Ext.String.capitalize(d),c[b].call(c,g);else Ext.isFunction(c.initConfig)&&(f=c.initConfig,c.initConfig=function(a){return f.call(this,Ext.Object.merge({},a||{},e))});return c}});
Ext.define("Deft.mixin.Injectable",{requires:["Deft.ioc.Injector"],onClassMixedIn:function(a){a.prototype.constructor=Ext.Function.createInterceptor(a.prototype.constructor,function(){return Deft.Injector.inject(this.inject,this,!1)})}});
Ext.define("Deft.mvc.ViewController",{alternateClassName:["Deft.ViewController"],requires:["Deft.log.Logger"],config:{view:null},constructor:function(a){this.initConfig(a);if(this.getView()instanceof Ext.ClassManager.get("Ext.Component"))if(this.registeredComponents={},this.isExtJS=null!=this.getView().events,this.isSenchaTouch=!this.isExtJS,this.isExtJS)if(this.getView().rendered)this.onViewInitialize();else this.getView().on("afterrender",this.onViewInitialize,this,{single:!0});else if(this.getView().initialized)this.onViewInitialize();
-else this.getView().on("initialize",this.onViewInitialize,this,{single:!0});else Ext.Error.raise({msg:"Error constructing ViewController: the configured 'view' is not an Ext.Component."});return this},init:function(){},destroy:function(){return!0},onViewInitialize:function(){var a,c,b,d,e,g;this.isExtJS?(this.getView().on("beforedestroy",this.onViewBeforeDestroy,this),this.getView().on("destroy",this.onViewDestroy,this,{single:!0})):(e=this,d=this.getView().destroy,this.getView().destroy=function(){e.destroy()&&
-d.call(this)});g=this.control;for(b in g)c=g[b],a=this.locateComponent(b,c),c=Ext.isObject(c.listeners)?c.listeners:null==c.selector?c:void 0,this.registerComponent(b,a,c);this.init()},onViewBeforeDestroy:function(){return this.destroy()?(this.getView().un("beforedestroy",this.onBeforeDestroy,this),!0):!1},onViewDestroy:function(){for(var a in this.registeredComponents)this.unregisterComponent(a)},getComponent:function(a){var c;return null!=(c=this.registeredComponents[a])?c.component:void 0},registerComponent:function(a,
-c,b){var d,e,g,f,h;Deft.Logger.log("Registering '"+a+"' component.");null!=this.getComponent(a)&&Ext.Error.raise({msg:"Error registering component: an existing component already registered as '"+a+"'."});this.registeredComponents[a]={component:c,listeners:b};"view"!==a&&(e="get"+Ext.String.capitalize(a),this[e]||(this[e]=Ext.Function.pass(this.getComponent,[a],this)));if(Ext.isObject(b))for(d in b){e=g=b[d];h=this;f=null;if(Ext.isObject(g)&&(f=Ext.apply({},g),null!=f.fn&&(e=f.fn,delete f.fn),null!=
-f.scope))h=f.scope,delete f.scope;Deft.Logger.log("Adding '"+d+"' listener to '"+a+"'.");if(Ext.isFunction(e))c.on(d,e,h,f);else if(Ext.isFunction(this[e]))c.on(d,this[e],h,f);else Ext.Error.raise({msg:"Error adding '"+d+"' listener: the specified handler '"+e+"' is not a Function or does not exist."})}},unregisterComponent:function(a){var c,b,d,e,g,f;Deft.Logger.log("Unregistering '"+a+"' component.");null==this.getComponent(a)&&Ext.Error.raise({msg:"Error unregistering component: no component is registered as '"+
-a+"'."});d=this.registeredComponents[a];c=d.component;g=d.listeners;if(Ext.isObject(g))for(b in g){d=e=g[b];f=this;if(Ext.isObject(e)&&(null!=e.fn&&(d=e.fn),null!=e.scope))f=e.scope;Deft.Logger.log("Removing '"+b+"' listener from '"+a+"'.");Ext.isFunction(d)?c.un(b,d,f):Ext.isFunction(this[d])?c.un(b,this[d],f):Ext.Error.raise({msg:"Error removing '"+b+"' listener: the specified handler '"+d+"' is not a Function or does not exist."})}"view"!==a&&(c="get"+Ext.String.capitalize(a),this[c]=null);this.registeredComponents[a]=
+else this.getView().on("initialize",this.onViewInitialize,this,{single:!0});else Ext.Error.raise({msg:"Error constructing ViewController: the configured 'view' is not an Ext.Component."});return this},init:function(){},destroy:function(){return!0},onViewInitialize:function(){var a,c,b,e,d,f;this.isExtJS?(this.getView().on("beforedestroy",this.onViewBeforeDestroy,this),this.getView().on("destroy",this.onViewDestroy,this,{single:!0})):(d=this,e=this.getView().destroy,this.getView().destroy=function(){d.destroy()&&
+e.call(this)});f=this.control;for(b in f)c=f[b],a=this.locateComponent(b,c),c=Ext.isObject(c.listeners)?c.listeners:null==c.selector?c:void 0,this.registerComponent(b,a,c);this.init()},onViewBeforeDestroy:function(){return this.destroy()?(this.getView().un("beforedestroy",this.onBeforeDestroy,this),!0):!1},onViewDestroy:function(){for(var a in this.registeredComponents)this.unregisterComponent(a)},getComponent:function(a){var c;return null!=(c=this.registeredComponents[a])?c.component:void 0},registerComponent:function(a,
+c,b){var e,d,f,g,h;Deft.Logger.log("Registering '"+a+"' component.");null!=this.getComponent(a)&&Ext.Error.raise({msg:"Error registering component: an existing component already registered as '"+a+"'."});this.registeredComponents[a]={component:c,listeners:b};"view"!==a&&(d="get"+Ext.String.capitalize(a),this[d]||(this[d]=Ext.Function.pass(this.getComponent,[a],this)));if(Ext.isObject(b))for(e in b){d=f=b[e];h=this;g=null;if(Ext.isObject(f)&&(g=Ext.apply({},f),null!=g.fn&&(d=g.fn,delete g.fn),null!=
+g.scope))h=g.scope,delete g.scope;Deft.Logger.log("Adding '"+e+"' listener to '"+a+"'.");if(Ext.isFunction(d))c.on(e,d,h,g);else if(Ext.isFunction(this[d]))c.on(e,this[d],h,g);else Ext.Error.raise({msg:"Error adding '"+e+"' listener: the specified handler '"+d+"' is not a Function or does not exist."})}},unregisterComponent:function(a){var c,b,e,d,f,g;Deft.Logger.log("Unregistering '"+a+"' component.");null==this.getComponent(a)&&Ext.Error.raise({msg:"Error unregistering component: no component is registered as '"+
+a+"'."});e=this.registeredComponents[a];c=e.component;f=e.listeners;if(Ext.isObject(f))for(b in f){e=d=f[b];g=this;if(Ext.isObject(d)&&(null!=d.fn&&(e=d.fn),null!=d.scope))g=d.scope;Deft.Logger.log("Removing '"+b+"' listener from '"+a+"'.");Ext.isFunction(e)?c.un(b,e,g):Ext.isFunction(this[e])?c.un(b,this[e],g):Ext.Error.raise({msg:"Error removing '"+b+"' listener: the specified handler '"+e+"' is not a Function or does not exist."})}"view"!==a&&(c="get"+Ext.String.capitalize(a),this[c]=null);this.registeredComponents[a]=
null},locateComponent:function(a,c){var b;b=this.getView();if("view"===a)return b;Ext.isString(c)?(b=b.query(c),0===b.length&&Ext.Error.raise({msg:"Error locating component: no component found matching '"+c+"'."}),1<b.length&&Ext.Error.raise({msg:"Error locating component: multiple components found matching '"+c+"'."})):Ext.isString(c.selector)?(b=b.query(c.selector),0===b.length&&Ext.Error.raise({msg:"Error locating component: no component found matching '"+c.selector+"'."}),1<b.length&&Ext.Error.raise({msg:"Error locating component: multiple components found matching '"+
-c.selector+"'."})):(b=b.query("#"+a),0===b.length&&Ext.Error.raise({msg:"Error locating component: no component found with an itemId of '"+a+"'."}),1<b.length&&Ext.Error.raise({msg:"Error locating component: multiple components found with an itemId of '"+a+"'."}));return b[0]}});
-Ext.define("Deft.mixin.Controllable",{requires:["Deft.mvc.ViewController"],onClassMixedIn:function(a){a.prototype.constructor=Ext.Function.createSequence(a.prototype.constructor,function(){var a,b,d,e;null==this.controller&&Ext.Error.raise({msg:"Error initializing Controllable instance: `controller` was not specified."});b=Ext.isArray(this.controller)?this.controller:[this.controller];d=0;for(e=b.length;d<e;d++){a=b[d];try{Ext.create(a,{view:this})}catch(g){Ext.Error.raise({msg:"Error initializing Controllable instance: an error occurred while creating an instance of the specified controller: '"+
-this.controller+"'."})}}})}});
-Ext.define("Deft.promise.Deferred",{alternateClassName:["Deft.Deferred"],constructor:function(){this.state="pending";this.value=this.progress=void 0;this.progressCallbacks=[];this.successCallbacks=[];this.failureCallbacks=[];this.cancelCallbacks=[];this.promise=Ext.create("Deft.Promise",this);return this},then:function(a,c,b,d){var e,g,f,h,i;Ext.isObject(a)?(g=a.success,c=a.failure,b=a.progress,a=a.cancel):(g=a,a=d);i=[g,c,b,a];f=0;for(h=i.length;f<h;f++)d=i[f],!Ext.isFunction(d)&&!(null===d||void 0===
-d)&&Ext.Error.raise({msg:"Error while configuring callback: a non-function specified."});e=Ext.create("Deft.promise.Deferred");d=function(a,b){return function(c){var d;if(Ext.isFunction(a))try{d=a(c);if(d===void 0)e[b](c);else d instanceof Ext.ClassManager.get("Deft.promise.Promise")||d instanceof Ext.ClassManager.get("Deft.promise.Deferred")?d.then(Ext.bind(e.resolve,e),Ext.bind(e.reject,e),Ext.bind(e.update,e),Ext.bind(e.cancel,e)):e.resolve(d)}catch(f){e.reject(f)}else e[b](c)}};this.register(d(g,
-"resolve"),this.successCallbacks,"resolved",this.value);this.register(d(c,"reject"),this.failureCallbacks,"rejected",this.value);this.register(d(a,"cancel"),this.cancelCallbacks,"cancelled",this.value);this.register(function(a){return function(b){var c;if(Ext.isFunction(a)){c=a(b);c===void 0?e.update(b):e.update(c)}else e.update(b)}}(b),this.progressCallbacks,"pending",this.progress);return e.getPromise()},always:function(a){return this.then({success:a,failure:a,cancel:a})},update:function(a){"pending"===
-this.state?(this.progress=a,this.notify(this.progressCallbacks,a)):Ext.Error.raise({msg:"Error: this Deferred has already been completed and cannot be modified."})},resolve:function(a){this.complete("resolved",a,this.successCallbacks)},reject:function(a){this.complete("rejected",a,this.failureCallbacks)},cancel:function(a){this.complete("cancelled",a,this.cancelCallbacks)},getPromise:function(){return this.promise},getState:function(){return this.state},register:function(a,c,b,d){Ext.isFunction(a)&&
-("pending"===this.state&&c.push(a),this.state===b&&void 0!==d&&this.notify([a],d))},complete:function(a,c,b){"pending"===this.state?(this.state=a,this.value=c,this.notify(b,c),this.releaseCallbacks()):Ext.Error.raise({msg:"Error: this Deferred has already been completed and cannot be modified."})},notify:function(a,c){var b,d,e;d=0;for(e=a.length;d<e;d++)b=a[d],b(c)},releaseCallbacks:function(){this.cancelCallbacks=this.failureCallbacks=this.successCallbacks=this.progressCallbacks=null}});
-Ext.define("Deft.promise.Promise",{alternateClassName:["Deft.Promise"],statics:{when:function(a,c){var b;if(a instanceof Ext.ClassManager.get("Deft.promise.Promise")||a instanceof Ext.ClassManager.get("Deft.promise.Deferred"))return a.then(c);b=Ext.create("Deft.promise.Deferred");b.resolve(a);return b.then(c)},all:function(a,c){return this.when(this.reduce(a,this.reduceIntoArray,Array(a.length)),c)},any:function(a,c){var b,d,e,g,f,h,i,j,k,l,m;d=Ext.create("Deft.promise.Deferred");k=function(a){d.update(a)};
-j=function(a){b();d.resolve(a)};b=function(){return k=j=function(){}};i=function(a){return j(a)};h=function(a){return rejector(a)};g=function(a){return k(a)};e=l=0;for(m=a.length;l<m;e=++l)f=a[e],e in a&&this.when(f,i,h,g);return d.then(c)},memoize:function(a,c,b){return this.all(Ext.Array.toArray(arguments)).then(Deft.util.Function.spread(function(){return Deft.util.memoize(arguments,c,b)},c))},map:function(a,c){var b,d,e,g,f;e=Array(a.length);b=g=0;for(f=a.length;g<f;b=++g)d=a[b],b in a&&(e[b]=
-this.when(d,c));return this.reduce(e,this.reduceIntoArray,e)},reduce:function(a,c,b){var d,e;e=this.when;d=[function(b,d,h){return e(b,function(b){return e(d,function(d){return c(b,d,h,a)})})}];3===arguments.length&&d.push(b);return this.when(this.reduceArray.apply(a,d))},reduceArray:function(a,c){var b,d,e,g,f;e=0;d=Object(this);g=d.length>>>0;b=arguments;if(1>=b.length)for(;;){if(e in d){f=d[e++];break}if(++e>=g)throw new TypeError;}else f=b[1];for(;e<g;)e in d&&(f=a(f,d[e],e,d)),e++;return f},
+c.selector+"'."})):(b=b.query("#"+a),0===b.length&&Ext.Error.raise({msg:"Error locating component: no component found with an itemId of '"+a+"'."}),1<b.length&&Ext.Error.raise({msg:"Error locating component: multiple components found with an itemId of '"+a+"'."}));return b[0]}});Ext.define("Deft.mixin.Controllable",{});
+Ext.Class.registerPreprocessor("controller",function(a,c,b,e){var d,f,g;3===arguments.length&&(d=Ext.toArray(arguments),b=d[1],e=d[2]);if(null!=c.mixins&&Ext.Array.contains(c.mixins,Ext.ClassManager.get("Deft.mixin.Controllable"))&&(d=c.controller,delete c.controller,f=[],null!=d&&(f=Ext.isArray(d)?d:[d]),a.prototype.constructor=Ext.Function.createSequence(a.prototype.constructor,function(){var a,b,c;b=0;for(c=f.length;b<c;b++){a=f[b];try{Ext.create(a,{view:this})}catch(d){Deft.Logger.warn("Error initializing Controllable instance: an error occurred while creating an instance of the specified controller: '"+
+a+"'.");throw d;}}}),0<f.length))return g=this,Ext.require(f,function(){e!=null&&e.call(g,a,c,b)}),!1});Ext.Class.setDefaultPreprocessorPosition("controller","before","mixins");
+Ext.define("Deft.promise.Deferred",{alternateClassName:["Deft.Deferred"],constructor:function(){this.state="pending";this.value=this.progress=void 0;this.progressCallbacks=[];this.successCallbacks=[];this.failureCallbacks=[];this.cancelCallbacks=[];this.promise=Ext.create("Deft.Promise",this);return this},then:function(a,c,b,e){var d,f,g,h,i;Ext.isObject(a)?(f=a.success,c=a.failure,b=a.progress,a=a.cancel):(f=a,a=e);i=[f,c,b,a];g=0;for(h=i.length;g<h;g++)e=i[g],!Ext.isFunction(e)&&!(null===e||void 0===
+e)&&Ext.Error.raise({msg:"Error while configuring callback: a non-function specified."});d=Ext.create("Deft.promise.Deferred");e=function(a,b){return function(c){var e;if(Ext.isFunction(a))try{e=a(c);if(e===void 0)d[b](c);else e instanceof Ext.ClassManager.get("Deft.promise.Promise")||e instanceof Ext.ClassManager.get("Deft.promise.Deferred")?e.then(Ext.bind(d.resolve,d),Ext.bind(d.reject,d),Ext.bind(d.update,d),Ext.bind(d.cancel,d)):d.resolve(e)}catch(f){d.reject(f)}else d[b](c)}};this.register(e(f,
+"resolve"),this.successCallbacks,"resolved",this.value);this.register(e(c,"reject"),this.failureCallbacks,"rejected",this.value);this.register(e(a,"cancel"),this.cancelCallbacks,"cancelled",this.value);this.register(function(a){return function(b){var c;if(Ext.isFunction(a)){c=a(b);c===void 0?d.update(b):d.update(c)}else d.update(b)}}(b),this.progressCallbacks,"pending",this.progress);return d.getPromise()},always:function(a){return this.then({success:a,failure:a,cancel:a})},update:function(a){"pending"===
+this.state?(this.progress=a,this.notify(this.progressCallbacks,a)):Ext.Error.raise({msg:"Error: this Deferred has already been completed and cannot be modified."})},resolve:function(a){this.complete("resolved",a,this.successCallbacks)},reject:function(a){this.complete("rejected",a,this.failureCallbacks)},cancel:function(a){this.complete("cancelled",a,this.cancelCallbacks)},getPromise:function(){return this.promise},getState:function(){return this.state},register:function(a,c,b,e){Ext.isFunction(a)&&
+("pending"===this.state&&c.push(a),this.state===b&&void 0!==e&&this.notify([a],e))},complete:function(a,c,b){"pending"===this.state?(this.state=a,this.value=c,this.notify(b,c),this.releaseCallbacks()):Ext.Error.raise({msg:"Error: this Deferred has already been completed and cannot be modified."})},notify:function(a,c){var b,e,d;e=0;for(d=a.length;e<d;e++)b=a[e],b(c)},releaseCallbacks:function(){this.cancelCallbacks=this.failureCallbacks=this.successCallbacks=this.progressCallbacks=null}});
+Ext.define("Deft.promise.Promise",{alternateClassName:["Deft.Promise"],statics:{when:function(a,c){var b;if(a instanceof Ext.ClassManager.get("Deft.promise.Promise")||a instanceof Ext.ClassManager.get("Deft.promise.Deferred"))return a.then(c);b=Ext.create("Deft.promise.Deferred");b.resolve(a);return b.then(c)},all:function(a,c){return this.when(this.reduce(a,this.reduceIntoArray,Array(a.length)),c)},any:function(a,c){var b,e,d,f,g,h,i,j,k,l,m;e=Ext.create("Deft.promise.Deferred");k=function(a){e.update(a)};
+j=function(a){b();e.resolve(a)};b=function(){return k=j=function(){}};i=function(a){return j(a)};h=function(a){return rejector(a)};f=function(a){return k(a)};d=l=0;for(m=a.length;l<m;d=++l)g=a[d],d in a&&this.when(g,i,h,f);return e.then(c)},memoize:function(a,c,b){return this.all(Ext.Array.toArray(arguments)).then(Deft.util.Function.spread(function(){return Deft.util.memoize(arguments,c,b)},c))},map:function(a,c){var b,e,d,f,g;d=Array(a.length);b=f=0;for(g=a.length;f<g;b=++f)e=a[b],b in a&&(d[b]=
+this.when(e,c));return this.reduce(d,this.reduceIntoArray,d)},reduce:function(a,c,b){var e,d;d=this.when;e=[function(b,e,h){return d(b,function(b){return d(e,function(d){return c(b,d,h,a)})})}];3===arguments.length&&e.push(b);return this.when(this.reduceArray.apply(a,e))},reduceArray:function(a,c){var b,e,d,f,g;d=0;e=Object(this);f=e.length>>>0;b=arguments;if(1>=b.length)for(;;){if(d in e){g=e[d++];break}if(++d>=f)throw new TypeError;}else g=b[1];for(;d<f;)d in e&&(g=a(g,e[d],d,e)),d++;return g},
reduceIntoArray:function(a,c,b){a[b]=c;return a}},constructor:function(a){this.deferred=a;return this},then:function(a){return this.deferred.then.apply(this.deferred,arguments)},always:function(a){return this.deferred.always(a)},cancel:function(a){return this.deferred.cancel(a)},getState:function(){return this.deferred.getState()}},function(){null!=Array.prototype.reduce&&(this.reduceArray=Array.prototype.reduce)});
View
25 spec/SpecRunner.html
@@ -2,24 +2,22 @@
<html>
<head>
<title>Jasmine Spec Runner</title>
-
- <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.1.0/jasmine_favicon.png">
- <link rel="stylesheet" type="text/css" href="lib/jasmine-1.1.0/jasmine.css">
-
+
<!-- Jasmine -->
- <script type="text/javascript" src="lib/jasmine-1.1.0/jasmine.js"></script>
- <script type="text/javascript" src="lib/jasmine-1.1.0/jasmine-html.js"></script>
-
+ <link rel="stylesheet" type="text/css" href="lib/jasmine-1.2.0/jasmine.css">
+ <script type="text/javascript" src="lib/jasmine-1.2.0/jasmine.js"></script>
+ <script type="text/javascript" src="lib/jasmine-1.2.0/jasmine-html.js"></script>
+
<!-- Ext JS -->
<!-- <script type="text/javascript" src="http://cdn.sencha.io/ext-4.0.7-gpl/ext-all.js"></script> -->
<script type="text/javascript" src="http://cdn.sencha.io/ext-4.1.0-gpl/ext-all.js"></script>
-
+
<!-- Sencha Touch -->
<!-- <script type="text/javascript" src="../lib/sencha-touch-2.0.1-rc/sencha-touch-all.js"></script> -->
-
+
<!-- DeftJS -->
<script type="text/javascript" src="../build/deft-debug.js"></script>
-
+
<!-- DeftJS specs -->
<script type="text/javascript" src="js/Deft/ioc/Injector.js"></script>
<script type="text/javascript" src="js/Deft/mixin/Injectable.js"></script>
@@ -27,9 +25,7 @@
<script type="text/javascript" src="js/Deft/mixin/Controllable.js"></script>
<script type="text/javascript" src="js/Deft/promise/Deferred.js"></script>
<script type="text/javascript" src="js/Deft/util/Function.js"></script>
-
</head>
-
<body>
<script type="text/javascript">
Ext.Loader.setConfig({
@@ -37,10 +33,9 @@
});
Ext.onReady( function () {
- jasmine.getEnv().addReporter( new jasmine.TrivialReporter() );
+ jasmine.getEnv().addReporter(new jasmine.HtmlReporter());
jasmine.getEnv().execute();
});
</script>
</body>
-
-</html>
+</html>
View
235 spec/coffee/Deft/ioc/Injector.coffee
@@ -16,6 +16,14 @@ describe( 'Deft.ioc.Injector', ->
@initConfig( config )
return @
)
+
+ Ext.define( 'ExampleSingletonClass',
+ singleton: true
+
+ constructor: ( config ) ->
+ @initConfig( config )
+ return @
+ )
beforeEach( ->
@addMatchers(
@@ -701,6 +709,221 @@ describe( 'Deft.ioc.Injector', ->
return
)
+
+ describe( 'Configuration with a class name for a singleton class', ->
+
+ it( 'should be configurable with a class name for a singleton class', ->
+ Deft.Injector.configure(
+ classNameForSingletonClass:
+ className: 'ExampleSingletonClass'
+ )
+
+ expect(
+ Deft.Injector.canResolve( 'classNameForSingletonClass' )
+ ).toBe( true )
+
+ return
+ )
+
+ it( 'should not be configurable with a class name for a singleton class and constructor parameters', ->
+ expect( ->
+ Deft.Injector.configure(
+ classNameForSingletonClassWithParameters:
+ className: 'ExampleSingletonClass'
+ parameters: [ { parameter: 'expected value' } ]
+ )
+ ).toThrow( new Error( "Error while configuring rule for 'classNameForSingletonClassWithParameters': parameters cannot be applied to singleton classes. Consider removing 'singleton: true' from the class definition." ) )
+
+ return
+ )
+
+ it( 'should be configurable with a class name for a singleton class, eagerly', ->
+ Deft.Injector.configure(
+ classNameForSingletonClassEagerly:
+ className: 'ExampleSingletonClass'
+ eager: true
+ )
+
+ expect(
+ Deft.Injector.canResolve( 'classNameForSingletonClassEagerly' )
+ ).toBe( true )
+
+ return
+ )
+
+ it( 'should be configurable with a class name for a singleton class, (explicitly) lazily', ->
+ Deft.Injector.configure(
+ classNameForSingletonClassLazily:
+ className: 'ExampleSingletonClass'
+ eager: false
+ )
+
+ expect(
+ Deft.Injector.canResolve( 'classNameForSingletonClassLazily' )
+ ).toBe( true )
+
+ return
+ )
+
+ it( 'should be configurable with a class name for a singleton class, (explicitly) as a singleton', ->
+ Deft.Injector.configure(
+ classNameForSingletonClassAsSingleton:
+ className: 'ExampleSingletonClass'
+ singleton: true
+ )
+
+ expect(
+ Deft.Injector.canResolve( 'classNameForSingletonClassAsSingleton' )
+ ).toBe( true )
+
+ return
+ )
+
+ it( 'should be configurable with a class name for a singleton class, (explicitly) as a singleton, eagerly', ->
+ Deft.Injector.configure(
+ classNameForSingletonClassAsSingletonEagerly:
+ className: 'ExampleSingletonClass'
+ singleton: true
+ eager: true
+ )
+
+ expect(
+ Deft.Injector.canResolve( 'classNameForSingletonClassAsSingletonEagerly' )
+ ).toBe( true )
+
+ return
+ )
+
+ it( 'should be configurable with a class name for a singleton class, (explicitly) as a singleton, (explicitly) lazily', ->
+ Deft.Injector.configure(
+ classNameForSingletonClassAsSingletonLazily:
+ className: 'ExampleSingletonClass'
+ singleton: true
+ eager: false
+ )
+
+ expect(
+ Deft.Injector.canResolve( 'classNameForSingletonClassAsSingletonLazily' )
+ ).toBe( true )
+
+ return
+ )
+
+ it( 'should not be configurable with a class name for a singleton class, as a prototype', ->
+ expect( ->
+ Deft.Injector.configure(
+ classNameForSingletonClassAsPrototype:
+ className: 'ExampleSingletonClass'
+ singleton: false
+ )
+ ).toThrow( new Error( "Error while configuring rule for 'classNameForSingletonClassAsPrototype': singleton classes cannot be configured for injection as a prototype. Consider removing 'singleton: true' from the class definition." ) )
+
+ return
+ )
+
+ it( 'should not be configurable with a class name for a singleton class, as a prototype, eagerly', ->
+ expect( ->
+ Deft.Injector.configure(
+ classNameForSingletonClassAsPrototypeEagerly:
+ className: 'ExampleSingletonClass'
+ singleton: false
+ eager: true
+ )
+ ).toThrow( new Error( "Error while configuring 'classNameForSingletonClassAsPrototypeEagerly': only singletons can be created eagerly." ) )
+
+ return
+ )
+
+ it( 'should not be configurable with a class name for a singleton class, as a prototype, (explicitly) lazily', ->
+ expect( ->
+ Deft.Injector.configure(
+ classNameForSingletonClassAsPrototypeLazily:
+ className: 'ExampleSingletonClass'
+ singleton: false
+ eager: false
+ )
+ ).toThrow( new Error( "Error while configuring rule for 'classNameForSingletonClassAsPrototypeLazily': singleton classes cannot be configured for injection as a prototype. Consider removing 'singleton: true' from the class definition." ) )
+
+ return
+ )
+
+ describe( 'Resolution of a dependency configured with a class name for a singleton class', ->
+
+ it( 'should resolve a dependency configured with a class name for a singleton class with the corresponding singleton class instance', ->
+ expect(
+ classNameForSingletonClassInstance = Deft.Injector.resolve( 'classNameForSingletonClass' )
+ ).toBe( ExampleSingletonClass )
+
+ expect(
+ Deft.Injector.resolve( 'classNameForSingletonClass' )
+ ).toBe( classNameForSingletonClassInstance )
+
+ return
+ )
+
+ it( 'should resolve a dependency configured with a class name for a singleton class, eagerly, with the corresponding singleton class instance', ->
+ expect(
+ classNameForSingletonClassEagerlyInstance = Deft.Injector.resolve( 'classNameForSingletonClassEagerly' )
+ ).toBe( ExampleSingletonClass )
+
+ expect(
+ Deft.Injector.resolve( 'classNameForSingletonClassEagerly' )
+ ).toBe( classNameForSingletonClassEagerlyInstance )
+
+ return
+ )
+
+ it( 'should resolve a dependency configured with a class name for a singleton class, (explicitly) lazily, with the corresponding singleton class instance', ->
+ expect(
+ classNameForSingletonClassEagerlyInstance = Deft.Injector.resolve( 'classNameForSingletonClassLazily' )
+ ).toBe( ExampleSingletonClass )
+
+ expect(
+ Deft.Injector.resolve( 'classNameForSingletonClassLazily' )
+ ).toBe( classNameForSingletonClassEagerlyInstance )
+
+ return
+ )
+
+ it( 'should resolve a dependency configured with a class name for a singleton class, (explicitly) as a singleton, with the corresponding singleton class instance', ->
+ expect(
+ classNameForSingletonClassAsSingletonInstance = Deft.Injector.resolve( 'classNameForSingletonClassAsSingleton' )
+ ).toBe( ExampleSingletonClass )
+
+ expect(
+ Deft.Injector.resolve( 'classNameForSingletonClassAsSingleton' )
+ ).toBe( classNameForSingletonClassAsSingletonInstance )
+
+ return
+ )
+
+ it( 'should resolve a dependency configured with a class name for a singleton class, (explicitly) as a singleton, eagerly, with the corresponding singleton class instance', ->
+ expect(
+ classNameForSingletonClassAsSingletonEagerlyInstance = Deft.Injector.resolve( 'classNameForSingletonClassAsSingletonEagerly' )
+ ).toBe( ExampleSingletonClass )
+
+ expect(
+ Deft.Injector.resolve( 'classNameForSingletonClassAsSingletonEagerly' )
+ ).toBe( classNameForSingletonClassAsSingletonEagerlyInstance )
+
+ return
+ )
+
+ it( 'should resolve a dependency configured with a class name for a singleton class, (explicitly) as a singleton, (explicitly) lazily, with the corresponding singleton class instance', ->
+ expect(
+ classNameForSingletonClassAsSingletonLazilyInstance = Deft.Injector.resolve( 'classNameForSingletonClassAsSingletonLazily' )
+ ).toBe( ExampleSingletonClass )
+
+ expect(
+ Deft.Injector.resolve( 'classNameForSingletonClassAsSingletonLazily' )
+ ).toBe( classNameForSingletonClassAsSingletonLazilyInstance )
+
+ return
+ )
+ )
+
+ return
+ )
describe( 'Configuration with a factory function', ->
@@ -1268,6 +1491,12 @@ describe( 'Deft.ioc.Injector', ->
'classNameWithParametersAsSingletonLazily'
'classNameWithParametersAsPrototype'
'classNameWithParametersAsPrototypeLazily'
+ 'classNameForSingletonClass'
+ 'classNameForSingletonClassEagerly'
+ 'classNameForSingletonClassLazily'
+ 'classNameForSingletonClassAsSingleton'
+ 'classNameForSingletonClassAsSingletonEagerly'
+ 'classNameForSingletonClassAsSingletonLazily'
'fn'
'fnEagerly'
'fnLazily'
@@ -1424,6 +1653,12 @@ describe( 'Deft.ioc.Injector', ->
classNameWithParametersAsSingletonLazily: null
classNameWithParametersAsPrototype: null
classNameWithParametersAsPrototypeLazily: null
+ classNameForSingletonClass: null
+ classNameForSingletonClassEagerly: null
+ classNameForSingletonClassLazily: null
+ classNameForSingletonClassAsSingleton: null
+ classNameForSingletonClassAsSingletonEagerly: null
+ classNameForSingletonClassAsSingletonLazily: null
fn: null
fnEagerly: null
fnLazily: null
View
42 spec/coffee/Deft/mixin/Controllable.coffee
@@ -7,21 +7,21 @@ Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
Jasmine test suite for Deft.mixin.Controllable
###
describe( 'Deft.mixin.Controllable', ->
-
- it( 'should create an instance of the associated view controller (configured with the target view instance) when an instance of the target view is created', ->
+
+ it( 'should create an instance of the view controller specified by the target view `controller` property and configure it with a reference to the target view instance when an instance of the target view is created', ->
exampleViewInstance = null
exampleViewControllerInstance = null
+ Ext.define( 'ExampleViewController',
+ extend: 'Deft.mvc.ViewController'
+ )
+
Ext.define( 'ExampleView',
extend: 'Ext.Container'
mixins: [ 'Deft.mixin.Controllable' ]
controller: 'ExampleViewController'
)
- Ext.define( 'ExampleViewController',
- extend: 'Deft.mvc.ViewController'
- )
-
constructorSpy = spyOn( ExampleViewController.prototype, 'constructor' ).andCallFake( ->
exampleViewControllerInstance = @
return constructorSpy.originalValue.apply( @, arguments )
@@ -32,34 +32,30 @@ describe( 'Deft.mixin.Controllable', ->
expect( ExampleViewController::constructor ).toHaveBeenCalled()
expect( ExampleViewController::constructor.callCount ).toBe( 1 )
expect( exampleViewControllerInstance.getView() ).toBe( exampleViewInstance )
+
+ return
)
- it( 'should throw an error if the target view \`controller\` property is not populated', ->
+ it( 'should re-throw any error thrown by the view controller during instantiation', ->
- Ext.define( 'ExampleView',
- extend: 'Ext.Container'
- mixins: [ 'Deft.mixin.Controllable' ]
- )
-
- Ext.define( 'ExampleViewController',
+ Ext.define( 'ExampleErrorThrowingViewController',
extend: 'Deft.mvc.ViewController'
+
+ constructor: ->
+ throw new Error( 'Error thrown by \`ExampleErrorThrowingViewController\`.' )
)
- expect( ->
- Ext.create( 'ExampleView' )
- ).toThrow( 'Error initializing Controllable instance: `controller` was not specified.' )
- )
-
- it( 'should throw an error if the target view \`controller\` property specifies a non-existent class', ->
-
Ext.define( 'ExampleView',
extend: 'Ext.Container'
mixins: [ 'Deft.mixin.Controllable' ]
- controller: 'doesntexist'
+ controller: 'ExampleErrorThrowingViewController'
)
expect( ->
Ext.create( 'ExampleView' )
- ).toThrow( 'Error initializing Controllable instance: an error occurred while creating an instance of the specified controller: \'doesntexist\'.' )
+ return
+ ).toThrow( 'Error thrown by \`ExampleErrorThrowingViewController\`.' )
+
+ return
)
-)
+)
View
2  spec/coffee/Deft/mixin/Injectable.coffee
@@ -21,5 +21,7 @@ describe( 'Deft.mixin.Injectable', ->
spyOn( Deft.Injector, 'inject' ).andCallFake( -> return )
exampleInstance = Ext.create( 'ExampleClass' )
+
+ return
)
)
View
152 spec/js/Deft/ioc/Injector.js
@@ -1,4 +1,4 @@
-// Generated by CoffeeScript 1.3.1
+// Generated by CoffeeScript 1.3.3
/*
Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org)
Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
@@ -18,6 +18,13 @@ describe('Deft.ioc.Injector', function() {
return this;
}
});
+ Ext.define('ExampleSingletonClass', {
+ singleton: true,
+ constructor: function(config) {
+ this.initConfig(config);
+ return this;
+ }
+ });
beforeEach(function() {
this.addMatchers({
toBeInstanceOf: function(className) {
@@ -422,6 +429,141 @@ describe('Deft.ioc.Injector', function() {
});
});
});
+ describe('Configuration with a class name for a singleton class', function() {
+ it('should be configurable with a class name for a singleton class', function() {
+ Deft.Injector.configure({
+ classNameForSingletonClass: {
+ className: 'ExampleSingletonClass'
+ }
+ });
+ expect(Deft.Injector.canResolve('classNameForSingletonClass')).toBe(true);
+ });
+ it('should not be configurable with a class name for a singleton class and constructor parameters', function() {
+ expect(function() {
+ return Deft.Injector.configure({
+ classNameForSingletonClassWithParameters: {
+ className: 'ExampleSingletonClass',
+ parameters: [
+ {
+ parameter: 'expected value'
+ }
+ ]
+ }
+ });
+ }).toThrow(new Error("Error while configuring rule for 'classNameForSingletonClassWithParameters': parameters cannot be applied to singleton classes. Consider removing 'singleton: true' from the class definition."));
+ });
+ it('should be configurable with a class name for a singleton class, eagerly', function() {
+ Deft.Injector.configure({
+ classNameForSingletonClassEagerly: {
+ className: 'ExampleSingletonClass',
+ eager: true
+ }
+ });
+ expect(Deft.Injector.canResolve('classNameForSingletonClassEagerly')).toBe(true);
+ });
+ it('should be configurable with a class name for a singleton class, (explicitly) lazily', function() {
+ Deft.Injector.configure({
+ classNameForSingletonClassLazily: {
+ className: 'ExampleSingletonClass',
+ eager: false
+ }
+ });
+ expect(Deft.Injector.canResolve('classNameForSingletonClassLazily')).toBe(true);
+ });
+ it('should be configurable with a class name for a singleton class, (explicitly) as a singleton', function() {
+ Deft.Injector.configure({
+ classNameForSingletonClassAsSingleton: {
+ className: 'ExampleSingletonClass',
+ singleton: true
+ }
+ });
+ expect(Deft.Injector.canResolve('classNameForSingletonClassAsSingleton')).toBe(true);
+ });
+ it('should be configurable with a class name for a singleton class, (explicitly) as a singleton, eagerly', function() {
+ Deft.Injector.configure({
+ classNameForSingletonClassAsSingletonEagerly: {
+ className: 'ExampleSingletonClass',
+ singleton: true,
+ eager: true
+ }
+ });
+ expect(Deft.Injector.canResolve('classNameForSingletonClassAsSingletonEagerly')).toBe(true);
+ });
+ it('should be configurable with a class name for a singleton class, (explicitly) as a singleton, (explicitly) lazily', function() {
+ Deft.Injector.configure({
+ classNameForSingletonClassAsSingletonLazily: {
+ className: 'ExampleSingletonClass',
+ singleton: true,
+ eager: false
+ }
+ });
+ expect(Deft.Injector.canResolve('classNameForSingletonClassAsSingletonLazily')).toBe(true);
+ });
+ it('should not be configurable with a class name for a singleton class, as a prototype', function() {
+ expect(function() {
+ return Deft.Injector.configure({
+ classNameForSingletonClassAsPrototype: {
+ className: 'ExampleSingletonClass',
+ singleton: false
+ }
+ });
+ }).toThrow(new Error("Error while configuring rule for 'classNameForSingletonClassAsPrototype': singleton classes cannot be configured for injection as a prototype. Consider removing 'singleton: true' from the class definition."));
+ });
+ it('should not be configurable with a class name for a singleton class, as a prototype, eagerly', function() {
+ expect(function() {
+ return Deft.Injector.configure({
+ classNameForSingletonClassAsPrototypeEagerly: {
+ className: 'ExampleSingletonClass',
+ singleton: false,
+ eager: true
+ }
+ });
+ }).toThrow(new Error("Error while configuring 'classNameForSingletonClassAsPrototypeEagerly': only singletons can be created eagerly."));
+ });
+ it('should not be configurable with a class name for a singleton class, as a prototype, (explicitly) lazily', function() {
+ expect(function() {
+ return Deft.Injector.configure({
+ classNameForSingletonClassAsPrototypeLazily: {
+ className: 'ExampleSingletonClass',
+ singleton: false,
+ eager: false
+ }
+ });
+ }).toThrow(new Error("Error while configuring rule for 'classNameForSingletonClassAsPrototypeLazily': singleton classes cannot be configured for injection as a prototype. Consider removing 'singleton: true' from the class definition."));
+ });
+ describe('Resolution of a dependency configured with a class name for a singleton class', function() {
+ it('should resolve a dependency configured with a class name for a singleton class with the corresponding singleton class instance', function() {
+ var classNameForSingletonClassInstance;
+ expect(classNameForSingletonClassInstance = Deft.Injector.resolve('classNameForSingletonClass')).toBe(ExampleSingletonClass);
+ expect(Deft.Injector.resolve('classNameForSingletonClass')).toBe(classNameForSingletonClassInstance);
+ });
+ it('should resolve a dependency configured with a class name for a singleton class, eagerly, with the corresponding singleton class instance', function() {
+ var classNameForSingletonClassEagerlyInstance;
+ expect(classNameForSingletonClassEagerlyInstance = Deft.Injector.resolve('classNameForSingletonClassEagerly')).toBe(ExampleSingletonClass);
+ expect(Deft.Injector.resolve('classNameForSingletonClassEagerly')).toBe(classNameForSingletonClassEagerlyInstance);
+ });
+ it('should resolve a dependency configured with a class name for a singleton class, (explicitly) lazily, with the corresponding singleton class instance', function() {
+ var classNameForSingletonClassEagerlyInstance;
+ expect(classNameForSingletonClassEagerlyInstance = Deft.Injector.resolve('classNameForSingletonClassLazily')).toBe(ExampleSingletonClass);
+ expect(Deft.Injector.resolve('classNameForSingletonClassLazily')).toBe(classNameForSingletonClassEagerlyInstance);
+ });
+ it('should resolve a dependency configured with a class name for a singleton class, (explicitly) as a singleton, with the corresponding singleton class instance', function() {
+ var classNameForSingletonClassAsSingletonInstance;
+ expect(classNameForSingletonClassAsSingletonInstance = Deft.Injector.resolve('classNameForSingletonClassAsSingleton')).toBe(ExampleSingletonClass);
+ expect(Deft.Injector.resolve('classNameForSingletonClassAsSingleton')).toBe(classNameForSingletonClassAsSingletonInstance);
+ });
+ it('should resolve a dependency configured with a class name for a singleton class, (explicitly) as a singleton, eagerly, with the corresponding singleton class instance', function() {
+ var classNameForSingletonClassAsSingletonEagerlyInstance;
+ expect(classNameForSingletonClassAsSingletonEagerlyInstance = Deft.Injector.resolve('classNameForSingletonClassAsSingletonEagerly')).toBe(ExampleSingletonClass);
+ expect(Deft.Injector.resolve('classNameForSingletonClassAsSingletonEagerly')).toBe(classNameForSingletonClassAsSingletonEagerlyInstance);
+ });
+ return it('should resolve a dependency configured with a class name for a singleton class, (explicitly) as a singleton, (explicitly) lazily, with the corresponding singleton class instance', function() {
+ var classNameForSingletonClassAsSingletonLazilyInstance;
+ expect(classNameForSingletonClassAsSingletonLazilyInstance = Deft.Injector.resolve('classNameForSingletonClassAsSingletonLazily')).toBe(ExampleSingletonClass);
+ expect(Deft.Injector.resolve('classNameForSingletonClassAsSingletonLazily')).toBe(classNameForSingletonClassAsSingletonLazilyInstance);
+ });
+ });
+ });
describe('Configuration with a factory function', function() {
var expectedFnAsSingletonEagerlyInstance, expectedFnEagerlyInstance, factoryFunction;
factoryFunction = function() {
@@ -748,7 +890,7 @@ describe('Deft.ioc.Injector', function() {
typeDescriptor = typeDescriptors[_i];
describeConfigurationByValueOfType.call(this, typeDescriptor);
}
- configuredIdentifiers = ['classNameAsString', 'className', 'classNameEagerly', 'classNameLazily', 'classNameAsSingleton', 'classNameAsSingletonEagerly', 'classNameAsSingletonLazily', 'classNameAsPrototype', 'classNameAsPrototypeLazily', 'classNameWithParameters', 'classNameWithParametersEagerly', 'classNameWithParametersLazily', 'classNameWithParametersAsSingleton', 'classNameWithParametersAsSingletonEagerly', 'classNameWithParametersAsSingletonLazily', 'classNameWithParametersAsPrototype', 'classNameWithParametersAsPrototypeLazily', 'fn', 'fnEagerly', 'fnLazily', 'fnAsSingleton', 'fnAsSingletonEagerly', 'fnAsSingletonLazily', 'fnAsPrototype', 'fnAsPrototypeLazily', 'booleanValue', 'booleanValueLazily', 'booleanValueAsSingleton', 'booleanValueAsSingletonLazily', 'stringValue', 'stringValueLazily', 'stringValueAsSingleton', 'stringValueAsSingletonLazily', 'numberValue', 'numberValueLazily', 'numberValueAsSingleton', 'numberValueAsSingletonLazily', 'dateValue', 'dateValueLazily', 'dateValueAsSingleton', 'dateValueAsSingletonLazily', 'arrayValue', 'arrayValueLazily', 'arrayValueAsSingleton', 'arrayValueAsSingletonLazily', 'objectValue', 'objectValueLazily', 'objectValueAsSingleton', 'objectValueAsSingletonLazily', 'classValue', 'classValueLazily', 'classValueAsSingleton', 'classValueAsSingletonLazily', 'functionValue', 'functionValueLazily', 'functionValueAsSingleton', 'functionValueAsSingletonLazily'];
+ configuredIdentifiers = ['classNameAsString', 'className', 'classNameEagerly', 'classNameLazily', 'classNameAsSingleton', 'classNameAsSingletonEagerly', 'classNameAsSingletonLazily', 'classNameAsPrototype', 'classNameAsPrototypeLazily', 'classNameWithParameters', 'classNameWithParametersEagerly', 'classNameWithParametersLazily', 'classNameWithParametersAsSingleton', 'classNameWithParametersAsSingletonEagerly', 'classNameWithParametersAsSingletonLazily', 'classNameWithParametersAsPrototype', 'classNameWithParametersAsPrototypeLazily', 'classNameForSingletonClass', 'classNameForSingletonClassEagerly', 'classNameForSingletonClassLazily', 'classNameForSingletonClassAsSingleton', 'classNameForSingletonClassAsSingletonEagerly', 'classNameForSingletonClassAsSingletonLazily', 'fn', 'fnEagerly', 'fnLazily', 'fnAsSingleton', 'fnAsSingletonEagerly', 'fnAsSingletonLazily', 'fnAsPrototype', 'fnAsPrototypeLazily', 'booleanValue', 'booleanValueLazily', 'booleanValueAsSingleton', 'booleanValueAsSingletonLazily', 'stringValue', 'stringValueLazily', 'stringValueAsSingleton', 'stringValueAsSingletonLazily', 'numberValue', 'numberValueLazily', 'numberValueAsSingleton', 'numberValueAsSingletonLazily', 'dateValue', 'dateValueLazily', 'dateValueAsSingleton', 'dateValueAsSingletonLazily', 'arrayValue', 'arrayValueLazily', 'arrayValueAsSingleton', 'arrayValueAsSingletonLazily', 'objectValue', 'objectValueLazily', 'objectValueAsSingleton', 'objectValueAsSingletonLazily', 'classValue', 'classValueLazily', 'classValueAsSingleton', 'classValueAsSingletonLazily', 'functionValue', 'functionValueLazily', 'functionValueAsSingleton', 'functionValueAsSingletonLazily'];
describe('Resolution', function() {
it('should resolve a value for configured identifiers', function() {
var configuredIdentifier, _j, _len1;
@@ -839,6 +981,12 @@ describe('Deft.ioc.Injector', function() {
classNameWithParametersAsSingletonLazily: null,
classNameWithParametersAsPrototype: null,
classNameWithParametersAsPrototypeLazily: null,
+ classNameForSingletonClass: null,
+ classNameForSingletonClassEagerly: null,
+ classNameForSingletonClassLazily: null,
+ classNameForSingletonClassAsSingleton: null,
+ classNameForSingletonClassAsSingletonEagerly: null,
+ classNameForSingletonClassAsSingletonLazily: null,
fn: null,
fnEagerly: null,
fnLazily: null,
View
38 spec/js/Deft/mixin/Controllable.js
@@ -1,4 +1,4 @@
-// Generated by CoffeeScript 1.3.1
+// Generated by CoffeeScript 1.3.3
/*
Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org)
Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
@@ -9,18 +9,18 @@ Jasmine test suite for Deft.mixin.Controllable
*/
describe('Deft.mixin.Controllable', function() {
- it('should create an instance of the associated view controller (configured with the target view instance) when an instance of the target view is created', function() {
+ it('should create an instance of the view controller specified by the target view `controller` property and configure it with a reference to the target view instance when an instance of the target view is created', function() {
var constructorSpy, exampleViewControllerInstance, exampleViewInstance;
exampleViewInstance = null;
exampleViewControllerInstance = null;
+ Ext.define('ExampleViewController', {
+ extend: 'Deft.mvc.ViewController'
+ });
Ext.define('ExampleView', {
extend: 'Ext.Container',
mixins: ['Deft.mixin.Controllable'],
controller: 'ExampleViewController'
});
- Ext.define('ExampleViewController', {
- extend: 'Deft.mvc.ViewController'
- });
constructorSpy = spyOn(ExampleViewController.prototype, 'constructor').andCallFake(function() {
exampleViewControllerInstance = this;
return constructorSpy.originalValue.apply(this, arguments);
@@ -28,28 +28,22 @@ describe('Deft.mixin.Controllable', function() {
exampleViewInstance = Ext.create('ExampleView');
expect(ExampleViewController.prototype.constructor).toHaveBeenCalled();
expect(ExampleViewController.prototype.constructor.callCount).toBe(1);
- return expect(exampleViewControllerInstance.getView()).toBe(exampleViewInstance);
+ expect(exampleViewControllerInstance.getView()).toBe(exampleViewInstance);
});
- it('should throw an error if the target view \`controller\` property is not populated', function() {
- Ext.define('ExampleView', {
- extend: 'Ext.Container',
- mixins: ['Deft.mixin.Controllable']
- });
- Ext.define('ExampleViewController', {
- extend: 'Deft.mvc.ViewController'
+ return it('should re-throw any error thrown by the view controller during instantiation', function() {
+ Ext.define('ExampleErrorThrowingViewController', {
+ extend: 'Deft.mvc.ViewController',
+ constructor: function() {
+ throw new Error('Error thrown by \`ExampleErrorThrowingViewController\`.');
+ }
});
- return expect(function() {
- return Ext.create('ExampleView');
- }).toThrow('Error initializing Controllable instance: `controller` was not specified.');
- });
- return it('should throw an error if the target view \`controller\` property specifies a non-existent class', function() {
Ext.define('ExampleView', {
extend: 'Ext.Container',
mixins: ['Deft.mixin.Controllable'],
- controller: 'doesntexist'
+ controller: 'ExampleErrorThrowingViewController'
});
- return expect(function() {
- return Ext.create('ExampleView');
- }).toThrow('Error initializing Controllable instance: an error occurred while creating an instance of the specified controller: \'doesntexist\'.');
+ expect(function() {
+ Ext.create('ExampleView');
+ }).toThrow('Error thrown by \`ExampleErrorThrowingViewController\`.');
});
});
View
4 spec/js/Deft/mixin/Injectable.js
@@ -1,4 +1,4 @@
-// Generated by CoffeeScript 1.3.1
+// Generated by CoffeeScript 1.3.3
/*
Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org)
Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
@@ -20,6 +20,6 @@ describe('Deft.mixin.Injectable', function() {
}
});
spyOn(Deft.Injector, 'inject').andCallFake(function() {});
- return exampleInstance = Ext.create('ExampleClass');
+ exampleInstance = Ext.create('ExampleClass');
});
});
View
2  spec/js/Deft/mvc/ViewController.js
@@ -1,4 +1,4 @@
-// Generated by CoffeeScript 1.3.1
+// Generated by CoffeeScript 1.3.3
/*
Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org)
Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
View
2  spec/js/Deft/promise/Deferred.js
@@ -1,4 +1,4 @@
-// Generated by CoffeeScript 1.3.1
+// Generated by CoffeeScript 1.3.3
/*
Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org)
Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
View
2  spec/js/Deft/promise/Promise.js
@@ -1,4 +1,4 @@
-// Generated by CoffeeScript 1.3.1
+// Generated by CoffeeScript 1.3.3
/*
Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org)
Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
View
2  spec/js/Deft/util/Function.js
@@ -1,4 +1,4 @@
-// Generated by CoffeeScript 1.3.1
+// Generated by CoffeeScript 1.3.3
/*
Copyright (c) 2012 [DeftJS Framework Contributors](http://deftjs.org)
Open source under the [MIT License](http://en.wikipedia.org/wiki/MIT_License).
View
190 spec/lib/jasmine-1.1.0/jasmine-html.js
@@ -1,190 +0,0 @@
-jasmine.TrivialReporter = function(doc) {
- this.document = doc || document;
- this.suiteDivs = {};
- this.logRunningSpecs = false;
-};
-
-jasmine.TrivialReporter.prototype.createDom = function(type, attrs, childrenVarArgs) {
- var el = document.createElement(type);
-
- for (var i = 2; i < arguments.length; i++) {
- var child = arguments[i];
-
- if (typeof child === 'string') {
- el.appendChild(document.createTextNode(child));
- } else {
- if (child) { el.appendChild(child); }
- }
- }
-
- for (var attr in attrs) {
- if (attr == "className") {
- el[attr] = attrs[attr];
- } else {
- el.setAttribute(attr, attrs[attr]);
- }
- }
-
- return el;
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerStarting = function(runner) {
- var showPassed, showSkipped;
-
- this.outerDiv = this.createDom('div', { className: 'jasmine_reporter' },
- this.createDom('div', { className: 'banner' },
- this.createDom('div', { className: 'logo' },
- this.createDom('span', { className: 'title' }, "Jasmine"),
- this.createDom('span', { className: 'version' }, runner.env.versionString())),
- this.createDom('div', { className: 'options' },
- "Show ",
- showPassed = this.createDom('input', { id: "__jasmine_TrivialReporter_showPassed__", type: 'checkbox' }),
- this.createDom('label', { "for": "__jasmine_TrivialReporter_showPassed__" }, " passed "),
- showSkipped = this.createDom('input', { id: "__jasmine_TrivialReporter_showSkipped__", type: 'checkbox' }),
- this.createDom('label', { "for": "__jasmine_TrivialReporter_showSkipped__" }, " skipped")
- )
- ),
-
- this.runnerDiv = this.createDom('div', { className: 'runner running' },
- this.createDom('a', { className: 'run_spec', href: '?' }, "run all"),
- this.runnerMessageSpan = this.createDom('span', {}, "Running..."),
- this.finishedAtSpan = this.createDom('span', { className: 'finished-at' }, ""))
- );
-
- this.document.body.appendChild(this.outerDiv);
-
- var suites = runner.suites();
- for (var i = 0; i < suites.length; i++) {
- var suite = suites[i];
- var suiteDiv = this.createDom('div', { className: 'suite' },
- this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, "run"),
- this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(suite.getFullName()) }, suite.description));
- this.suiteDivs[suite.id] = suiteDiv;
- var parentDiv = this.outerDiv;
- if (suite.parentSuite) {
- parentDiv = this.suiteDivs[suite.parentSuite.id];
- }
- parentDiv.appendChild(suiteDiv);
- }
-
- this.startedAt = new Date();
-
- var self = this;
- showPassed.onclick = function(evt) {
- if (showPassed.checked) {
- self.outerDiv.className += ' show-passed';
- } else {
- self.outerDiv.className = self.outerDiv.className.replace(/ show-passed/, '');
- }
- };
-
- showSkipped.onclick = function(evt) {
- if (showSkipped.checked) {
- self.outerDiv.className += ' show-skipped';
- } else {
- self.outerDiv.className = self.outerDiv.className.replace(/ show-skipped/, '');
- }
- };
-};
-
-jasmine.TrivialReporter.prototype.reportRunnerResults = function(runner) {
- var results = runner.results();
- var className = (results.failedCount > 0) ? "runner failed" : "runner passed";
- this.runnerDiv.setAttribute("class", className);
- //do it twice for IE
- this.runnerDiv.setAttribute("className", className);
- var specs = runner.specs();
- var specCount = 0;
- for (var i = 0; i < specs.length; i++) {
- if (this.specFilter(specs[i])) {
- specCount++;
- }
- }
- var message = "" + specCount + " spec" + (specCount == 1 ? "" : "s" ) + ", " + results.failedCount + " failure" + ((results.failedCount == 1) ? "" : "s");
- message += " in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s";
- this.runnerMessageSpan.replaceChild(this.createDom('a', { className: 'description', href: '?'}, message), this.runnerMessageSpan.firstChild);
-
- this.finishedAtSpan.appendChild(document.createTextNode("Finished at " + new Date().toString()));
-};
-
-jasmine.TrivialReporter.prototype.reportSuiteResults = function(suite) {
- var results = suite.results();
- var status = results.passed() ? 'passed' : 'failed';
- if (results.totalCount === 0) { // todo: change this to check results.skipped
- status = 'skipped';
- }
- this.suiteDivs[suite.id].className += " " + status;
-};
-
-jasmine.TrivialReporter.prototype.reportSpecStarting = function(spec) {
- if (this.logRunningSpecs) {
- this.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
- }
-};
-
-jasmine.TrivialReporter.prototype.reportSpecResults = function(spec) {
- var results = spec.results();
- var status = results.passed() ? 'passed' : 'failed';
- if (results.skipped) {
- status = 'skipped';
- }
- var specDiv = this.createDom('div', { className: 'spec ' + status },
- this.createDom('a', { className: 'run_spec', href: '?spec=' + encodeURIComponent(spec.getFullName()) }, "run"),
- this.createDom('a', {
- className: 'description',
- href: '?spec=' + encodeURIComponent(spec.getFullName()),
- title: spec.getFullName()
- }, spec.description));
-
-
- var resultItems = results.getItems();
- var messagesDiv = this.createDom('div', { className: 'messages' });
- for (var i = 0; i < resultItems.length; i++) {
- var result = resultItems[i];
-
- if (result.type == 'log') {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
- } else if (result.type == 'expect' && result.passed && !result.passed()) {
- messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
-
- if (result.trace.stack) {
- messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
- }
- }
- }
-
- if (messagesDiv.childNodes.length > 0) {
- specDiv.appendChild(messagesDiv);
- }
-
- this.suiteDivs[spec.suite.id].appendChild(specDiv);
-};
-
-jasmine.TrivialReporter.prototype.log = function() {
- var console = jasmine.getGlobal().console;
- if (console && console.log) {
- if (console.log.apply) {
- console.log.apply(console, arguments);
- } else {
- console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
- }
- }
-};
-
-jasmine.TrivialReporter.prototype.getLocation = function() {
- return this.document.location;
-};
-
-jasmine.TrivialReporter.prototype.specFilter = function(spec) {
- var paramMap = {};
- var params = this.getLocation().search.substring(1).split('&');
- for (var i = 0; i < params.length; i++) {
- var p = params[i].split('=');
- paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
- }
-
- if (!paramMap.spec) {
- return true;
- }
- return spec.getFullName().indexOf(paramMap.spec) === 0;
-};
View
166 spec/lib/jasmine-1.1.0/jasmine.css
@@ -1,166 +0,0 @@
-body {
- font-family: "Helvetica Neue Light", "Lucida Grande", "Calibri", "Arial", sans-serif;
-}
-
-
-.jasmine_reporter a:visited, .jasmine_reporter a {
- color: #303;
-}
-
-.jasmine_reporter a:hover, .jasmine_reporter a:active {
- color: blue;
-}
-
-.run_spec {
- float:right;
- padding-right: 5px;
- font-size: .8em;
- text-decoration: none;
-}
-
-.jasmine_reporter {
- margin: 0 5px;
-}
-
-.banner {
- color: #303;
- background-color: #fef;
- padding: 5px;
-}
-
-.logo {
- float: left;
- font-size: 1.1em;
- padding-left: 5px;
-}
-
-.logo .version {
- font-size: .6em;
- padding-left: 1em;
-}
-
-.runner.running {
- background-color: yellow;
-}
-
-
-.options {
- text-align: right;
- font-size: .8em;
-}
-
-
-
-
-.suite {
- border: 1px outset gray;
- margin: 5px 0;
- padding-left: 1em;
-}
-
-.suite .suite {
- margin: 5px;
-}
-
-.suite.passed {
- background-color: #dfd;
-}
-
-.suite.failed {
- background-color: #fdd;
-}
-
-.spec {
- margin: 5px;
- padding-left: 1em;
- clear: both;
-}
-
-.spec.failed, .spec.passed, .spec.skipped {
- padding-bottom: 5px;
- border: 1px solid gray;
-}
-
-.spec.failed {
- background-color: #fbb;
- border-color: red;
-}
-
-.spec.passed {
- background-color: #bfb;
- border-color: green;
-}
-
-.spec.skipped {
- background-color: #bbb;
-}
-
-.messages {
- border-left: 1px dashed gray;
- padding-left: 1em;
- padding-right: 1em;
-}
-
-.passed {
- background-color: #cfc;
- display: none;
-}
-
-.failed {
- background-color: #fbb;
-}
-
-.skipped {
- color: #777;
- background-color: #eee;
- display: none;
-}
-
-
-/*.resultMessage {*/
- /*white-space: pre;*/
-/*}*/
-
-.resultMessage span.result {
- display: block;
- line-height: 2em;
- color: black;
-}
-
-.resultMessage .mismatch {
- color: black;
-}
-
-.stackTrace {
- white-space: pre;
- font-size: .8em;
- margin-left: 10px;
- max-height: 5em;
- overflow: auto;
- border: 1px inset red;
- padding: 1em;
- background: #eef;
-}
-
-.finished-at {
- padding-left: 1em;
- font-size: .6em;
-}
-
-.show-passed .passed,
-.show-skipped .skipped {
- display: block;
-}
-
-
-#jasmine_content {
- position:fixed;
- right: 100%;
-}
-
-.runner {
- border: 1px solid gray;
- display: block;
- margin: 5px 0;
- padding: 2px 0 2px 10px;
-}
View
BIN  spec/lib/jasmine-1.1.0/jasmine_favicon.png
Deleted file not rendered
View
0  spec/lib/jasmine-1.1.0/MIT.LICENSE → spec/lib/jasmine-1.2.0/MIT.LICENSE
File renamed without changes
View
616 spec/lib/jasmine-1.2.0/jasmine-html.js
@@ -0,0 +1,616 @@
+jasmine.HtmlReporterHelpers = {};
+
+jasmine.HtmlReporterHelpers.createDom = function(type, attrs, childrenVarArgs) {
+ var el = document.createElement(type);
+
+ for (var i = 2; i < arguments.length; i++) {
+ var child = arguments[i];
+
+ if (typeof child === 'string') {
+ el.appendChild(document.createTextNode(child));
+ } else {
+ if (child) {
+ el.appendChild(child);
+ }
+ }
+ }
+
+ for (var attr in attrs) {
+ if (attr == "className") {
+ el[attr] = attrs[attr];
+ } else {
+ el.setAttribute(attr, attrs[attr]);
+ }
+ }
+
+ return el;
+};
+
+jasmine.HtmlReporterHelpers.getSpecStatus = function(child) {
+ var results = child.results();
+ var status = results.passed() ? 'passed' : 'failed';
+ if (results.skipped) {
+ status = 'skipped';
+ }
+
+ return status;
+};
+
+jasmine.HtmlReporterHelpers.appendToSummary = function(child, childElement) {
+ var parentDiv = this.dom.summary;
+ var parentSuite = (typeof child.parentSuite == 'undefined') ? 'suite' : 'parentSuite';
+ var parent = child[parentSuite];
+
+ if (parent) {
+ if (typeof this.views.suites[parent.id] == 'undefined') {
+ this.views.suites[parent.id] = new jasmine.HtmlReporter.SuiteView(parent, this.dom, this.views);
+ }
+ parentDiv = this.views.suites[parent.id].element;
+ }
+
+ parentDiv.appendChild(childElement);
+};
+
+
+jasmine.HtmlReporterHelpers.addHelpers = function(ctor) {
+ for(var fn in jasmine.HtmlReporterHelpers) {
+ ctor.prototype[fn] = jasmine.HtmlReporterHelpers[fn];
+ }
+};
+
+jasmine.HtmlReporter = function(_doc) {
+ var self = this;
+ var doc = _doc || window.document;
+
+ var reporterView;
+
+ var dom = {};
+
+ // Jasmine Reporter Public Interface
+ self.logRunningSpecs = false;
+
+ self.reportRunnerStarting = function(runner) {
+ var specs = runner.specs() || [];
+
+ if (specs.length == 0) {
+ return;
+ }
+
+ createReporterDom(runner.env.versionString());
+ doc.body.appendChild(dom.reporter);
+
+ reporterView = new jasmine.HtmlReporter.ReporterView(dom);
+ reporterView.addSpecs(specs, self.specFilter);
+ };
+
+ self.reportRunnerResults = function(runner) {
+ reporterView && reporterView.complete();
+ };
+
+ self.reportSuiteResults = function(suite) {
+ reporterView.suiteComplete(suite);
+ };
+
+ self.reportSpecStarting = function(spec) {
+ if (self.logRunningSpecs) {
+ self.log('>> Jasmine Running ' + spec.suite.description + ' ' + spec.description + '...');
+ }
+ };
+
+ self.reportSpecResults = function(spec) {
+ reporterView.specComplete(spec);
+ };
+
+ self.log = function() {
+ var console = jasmine.getGlobal().console;
+ if (console && console.log) {
+ if (console.log.apply) {
+ console.log.apply(console, arguments);
+ } else {
+ console.log(arguments); // ie fix: console.log.apply doesn't exist on ie
+ }
+ }
+ };
+
+ self.specFilter = function(spec) {
+ if (!focusedSpecName()) {
+ return true;
+ }
+
+ return spec.getFullName().indexOf(focusedSpecName()) === 0;
+ };
+
+ return self;
+
+ function focusedSpecName() {
+ var specName;
+
+ (function memoizeFocusedSpec() {
+ if (specName) {
+ return;
+ }
+
+ var paramMap = [];
+ var params = doc.location.search.substring(1).split('&');
+
+ for (var i = 0; i < params.length; i++) {
+ var p = params[i].split('=');
+ paramMap[decodeURIComponent(p[0])] = decodeURIComponent(p[1]);
+ }
+
+ specName = paramMap.spec;
+ })();
+
+ return specName;
+ }
+
+ function createReporterDom(version) {
+ dom.reporter = self.createDom('div', { id: 'HTMLReporter', className: 'jasmine_reporter' },
+ dom.banner = self.createDom('div', { className: 'banner' },
+ self.createDom('span', { className: 'title' }, "Jasmine "),
+ self.createDom('span', { className: 'version' }, version)),
+
+ dom.symbolSummary = self.createDom('ul', {className: 'symbolSummary'}),
+ dom.alert = self.createDom('div', {className: 'alert'}),
+ dom.results = self.createDom('div', {className: 'results'},
+ dom.summary = self.createDom('div', { className: 'summary' }),
+ dom.details = self.createDom('div', { id: 'details' }))
+ );
+ }
+};
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter);jasmine.HtmlReporter.ReporterView = function(dom) {
+ this.startedAt = new Date();
+ this.runningSpecCount = 0;
+ this.completeSpecCount = 0;
+ this.passedCount = 0;
+ this.failedCount = 0;
+ this.skippedCount = 0;
+
+ this.createResultsMenu = function() {
+ this.resultsMenu = this.createDom('span', {className: 'resultsMenu bar'},
+ this.summaryMenuItem = this.createDom('a', {className: 'summaryMenuItem', href: "#"}, '0 specs'),
+ ' | ',
+ this.detailsMenuItem = this.createDom('a', {className: 'detailsMenuItem', href: "#"}, '0 failing'));
+
+ this.summaryMenuItem.onclick = function() {
+ dom.reporter.className = dom.reporter.className.replace(/ showDetails/g, '');
+ };
+
+ this.detailsMenuItem.onclick = function() {
+ showDetails();
+ };
+ };
+
+ this.addSpecs = function(specs, specFilter) {
+ this.totalSpecCount = specs.length;
+
+ this.views = {
+ specs: {},
+ suites: {}
+ };
+
+ for (var i = 0; i < specs.length; i++) {
+ var spec = specs[i];
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom, this.views);
+ if (specFilter(spec)) {
+ this.runningSpecCount++;
+ }
+ }
+ };
+
+ this.specComplete = function(spec) {
+ this.completeSpecCount++;
+
+ if (isUndefined(this.views.specs[spec.id])) {
+ this.views.specs[spec.id] = new jasmine.HtmlReporter.SpecView(spec, dom);
+ }
+
+ var specView = this.views.specs[spec.id];
+
+ switch (specView.status()) {
+ case 'passed':
+ this.passedCount++;
+ break;
+
+ case 'failed':
+ this.failedCount++;
+ break;
+
+ case 'skipped':
+ this.skippedCount++;
+ break;
+ }
+
+ specView.refresh();
+ this.refresh();
+ };
+
+ this.suiteComplete = function(suite) {
+ var suiteView = this.views.suites[suite.id];
+ if (isUndefined(suiteView)) {
+ return;
+ }
+ suiteView.refresh();
+ };
+
+ this.refresh = function() {
+
+ if (isUndefined(this.resultsMenu)) {
+ this.createResultsMenu();
+ }
+
+ // currently running UI
+ if (isUndefined(this.runningAlert)) {
+ this.runningAlert = this.createDom('a', {href: "?", className: "runningAlert bar"});
+ dom.alert.appendChild(this.runningAlert);
+ }
+ this.runningAlert.innerHTML = "Running " + this.completeSpecCount + " of " + specPluralizedFor(this.totalSpecCount);
+
+ // skipped specs UI
+ if (isUndefined(this.skippedAlert)) {
+ this.skippedAlert = this.createDom('a', {href: "?", className: "skippedAlert bar"});
+ }
+
+ this.skippedAlert.innerHTML = "Skipping " + this.skippedCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.skippedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.skippedAlert);
+ }
+
+ // passing specs UI
+ if (isUndefined(this.passedAlert)) {
+ this.passedAlert = this.createDom('span', {href: "?", className: "passingAlert bar"});
+ }
+ this.passedAlert.innerHTML = "Passing " + specPluralizedFor(this.passedCount);
+
+ // failing specs UI
+ if (isUndefined(this.failedAlert)) {
+ this.failedAlert = this.createDom('span', {href: "?", className: "failingAlert bar"});
+ }
+ this.failedAlert.innerHTML = "Failing " + specPluralizedFor(this.failedCount);
+
+ if (this.failedCount === 1 && isDefined(dom.alert)) {
+ dom.alert.appendChild(this.failedAlert);
+ dom.alert.appendChild(this.resultsMenu);
+ }
+
+ // summary info
+ this.summaryMenuItem.innerHTML = "" + specPluralizedFor(this.runningSpecCount);
+ this.detailsMenuItem.innerHTML = "" + this.failedCount + " failing";
+ };
+
+ this.complete = function() {
+ dom.alert.removeChild(this.runningAlert);
+
+ this.skippedAlert.innerHTML = "Ran " + this.runningSpecCount + " of " + specPluralizedFor(this.totalSpecCount) + " - run all";
+
+ if (this.failedCount === 0) {
+ dom.alert.appendChild(this.createDom('span', {className: 'passingAlert bar'}, "Passing " + specPluralizedFor(this.passedCount)));
+ } else {
+ showDetails();
+ }
+
+ dom.banner.appendChild(this.createDom('span', {className: 'duration'}, "finished in " + ((new Date().getTime() - this.startedAt.getTime()) / 1000) + "s"));
+ };
+
+ return this;
+
+ function showDetails() {
+ if (dom.reporter.className.search(/showDetails/) === -1) {
+ dom.reporter.className += " showDetails";
+ }
+ }
+
+ function isUndefined(obj) {
+ return typeof obj === 'undefined';
+ }
+
+ function isDefined(obj) {
+ return !isUndefined(obj);
+ }
+
+ function specPluralizedFor(count) {
+ var str = count + " spec";
+ if (count > 1) {
+ str += "s"
+ }
+ return str;
+ }
+
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.ReporterView);
+
+
+jasmine.HtmlReporter.SpecView = function(spec, dom, views) {
+ this.spec = spec;
+ this.dom = dom;
+ this.views = views;
+
+ this.symbol = this.createDom('li', { className: 'pending' });
+ this.dom.symbolSummary.appendChild(this.symbol);
+
+ this.summary = this.createDom('div', { className: 'specSummary' },
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.description)
+ );
+
+ this.detail = this.createDom('div', { className: 'specDetail' },
+ this.createDom('a', {
+ className: 'description',
+ href: '?spec=' + encodeURIComponent(this.spec.getFullName()),
+ title: this.spec.getFullName()
+ }, this.spec.getFullName())
+ );
+};
+
+jasmine.HtmlReporter.SpecView.prototype.status = function() {
+ return this.getSpecStatus(this.spec);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.refresh = function() {
+ this.symbol.className = this.status();
+
+ switch (this.status()) {
+ case 'skipped':
+ break;
+
+ case 'passed':
+ this.appendSummaryToSuiteDiv();
+ break;
+
+ case 'failed':
+ this.appendSummaryToSuiteDiv();
+ this.appendFailureDetail();
+ break;
+ }
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendSummaryToSuiteDiv = function() {
+ this.summary.className += ' ' + this.status();
+ this.appendToSummary(this.spec, this.summary);
+};
+
+jasmine.HtmlReporter.SpecView.prototype.appendFailureDetail = function() {
+ this.detail.className += ' ' + this.status();
+
+ var resultItems = this.spec.results().getItems();
+ var messagesDiv = this.createDom('div', { className: 'messages' });
+
+ for (var i = 0; i < resultItems.length; i++) {
+ var result = resultItems[i];
+
+ if (result.type == 'log') {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage log'}, result.toString()));
+ } else if (result.type == 'expect' && result.passed && !result.passed()) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'resultMessage fail'}, result.message));
+
+ if (result.trace.stack) {
+ messagesDiv.appendChild(this.createDom('div', {className: 'stackTrace'}, result.trace.stack));
+ }
+ }
+ }
+
+ if (messagesDiv.childNodes.length > 0) {
+ this.detail.appendChild(messagesDiv);
+ this.dom.details.appendChild(this.detail);
+ }
+};
+
+jasmine.HtmlReporterHelpers.addHelpers(jasmine.HtmlReporter.SpecView);jasmine.HtmlReporter.SuiteView = function(suite, dom, views) {
+ this.suite = suite;
+ this.dom = dom;
+ this.views = views;
+
+ this.element = this.createDom('div', { className: 'suite' },
+ this.createDom('a', { className: 'description', href: '?spec=' + encodeURIComponent(this.suite.getFullName()) }, this.suite.description)
+ );
+
+ this.appendToSummary(this.suite, this.element);
+};