diff --git a/backbone.geppetto.js b/backbone.geppetto.js index ee954ea..5a4a342 100755 --- a/backbone.geppetto.js +++ b/backbone.geppetto.js @@ -124,10 +124,8 @@ wireSingleton: function(key, clazz, wiring) { - var constructor = (clazz.prototype.initialize ? this._wrapConstructor(clazz, wiring) : clazz); - this._mappings[key] = { - clazz: constructor, + clazz: clazz, object: null, type: TYPES.SINGLETON, wiring: wiring diff --git a/dist/backbone.geppetto.min.js b/dist/backbone.geppetto.min.js index 1b8296b..a1cbb05 100644 --- a/dist/backbone.geppetto.min.js +++ b/dist/backbone.geppetto.min.js @@ -1 +1 @@ -!function(a){"function"==typeof define&&define.amd?define(["underscore","backbone"],a):a(_,Backbone)}(function(a,b){"use strict";if(!b)throw"Please include Backbone before Geppetto";var c="no mapping found for key: ",d={SINGLETON:"singleton",VIEW:"view",OTHER:"other"},e=function(a){this._mappings={},this._context=a,this.parent=void 0};e.prototype={_createAndSetupInstance:function(a,b){var c=new a;return this.resolve(c,b),c},_retrieveFromCacheOrCreate:function(a,b){var e;if(this._mappings.hasOwnProperty(a)){var f=this._mappings[a];b||f.type!==d.SINGLETON?f.type===d.VIEW?e=f.clazz:f.clazz&&(e=this._createAndSetupInstance(f.clazz,f.wiring)):(f.object||(f.object=this._createAndSetupInstance(f.clazz,f.wiring)),e=f.object)}else{if(!this.parent||!this.parent.hasWiring(a))throw new Error(c+a);e=this.parent._retrieveFromCacheOrCreate(a,b)}return e},_wrapConstructor:function(a,b){var c=this._context;return a.extend({initialize:function(){c.resolver.resolve(this,b),a.prototype.initialize.call(this,arguments)}})},createChildResolver:function(){var a=new e(this._context);return a.parent=this,a},getObject:function(a){return this._retrieveFromCacheOrCreate(a,!1)},wireValue:function(a,b){return this._mappings[a]={clazz:null,object:b,type:d.SINGLETON},this},hasWiring:function(a){return this._mappings.hasOwnProperty(a)||!!this.parent&&this.parent.hasWiring(a)},wireClass:function(a,b,c){return this._mappings[a]={clazz:b,object:null,type:d.OTHER,wiring:c},this},wireView:function(a,b,c){return this._mappings[a]={clazz:this._wrapConstructor(b,c),object:null,type:d.VIEW},this},wireSingleton:function(a,b,c){var e=b.prototype.initialize?this._wrapConstructor(b,c):b;return this._mappings[a]={clazz:e,object:null,type:d.SINGLETON,wiring:c},this},instantiate:function(a){return this._retrieveFromCacheOrCreate(a,!0)},resolve:function(b,c){if(c=c||b.wiring){var d=Number(!a.isArray(c));a.each(c,function(a){b[arguments[d]]=this.getObject(a)},this)}return this.addPubSub(b),this},addPubSub:function(b){b.listen=a.bind(this._context.listen,this._context),b.dispatch=a.bind(this._context.dispatch,this._context)},release:function(a){return delete this._mappings[a],this},releaseAll:function(){return this._mappings={},this}};var f={};f.version="0.7.0",f.EVENT_CONTEXT_SHUTDOWN="Geppetto:contextShutdown",f.Resolver=e;var g={};f.Context=function(c){this.options=c||{},this.parentContext=this.options.parentContext,this.options.resolver?this.resolver=this.options.resolver:this.parentContext?this.resolver=this.parentContext.resolver.createChildResolver():this.resolver||(this.resolver=new e(this)),this.vent={},a.extend(this.vent,b.Events),a.isFunction(this.initialize)&&this.initialize.apply(this,arguments),this._contextId=a.uniqueId("Context"),g[this._contextId]=this;var d=this.wiring||this.options.wiring;d&&this._configureWirings(d)},f.bindContext=function(b){this.options=b||{};var c=this.options.view,d=null;"function"==typeof this.options.context?(d=new this.options.context(this.options),c.close||(c.close=function(){c.trigger("close"),c.remove()}),c.on("close",function(){c.off("close"),d.destroy()})):"object"==typeof this.options.context&&(d=this.options.context),d.resolver.resolve(c),a.each(c.contextEvents,function(b,e){a.isFunction(b)?d.listen(c,e,b):a.isString(b)&&d.listen(c,e,c[b])});var e;return c.wiring||(c.context=d,e=d),e};var h=function(a,b){var c,d;return a.hasOwnProperty("ctor")?(c=a.ctor,d=a.wiring):c=a,[b,c,d]};f.Context.prototype._configureWirings=function(b){a.each(b.singletons,function(a,b){this.wireSingleton.apply(this,h(a,b))},this),a.each(b.classes,function(a,b){this.wireClass.apply(this,h(a,b))},this),a.each(b.values,function(a,b){this.wireValue(b,a)},this),a.each(b.views,function(a,b){this.wireView.apply(this,h(a,b))},this),this.wireCommands(b.commands)};var i=function(b,c,d){if(!a.isObject(b)||!a.isFunction(b.listenTo)||!a.isFunction(b.stopListening))throw"Target for listen() must define a 'listenTo' and 'stopListening' function";if(!a.isString(c))throw"eventName must be a String";if(!a.isFunction(d))throw"callback must be a function"};f.Context.prototype.listen=function(a,b,c){return i(a,b,c),a.listenTo(this.vent,b,c,a)},f.Context.prototype.listenToOnce=function(a,b,c){return i(a,b,c),a.listenToOnce(this.vent,b,c,a)},f.Context.prototype.dispatch=function(b,c){if(!a.isUndefined(c)&&!a.isObject(c))throw"Event payload must be an object";c=c||{},c.eventName=b,this.vent.trigger(b,c)},f.Context.prototype.dispatchToParent=function(a,b){this.parentContext&&this.parentContext.vent.trigger(a,b)},f.Context.prototype.dispatchGlobally=function(b,c){a.each(g,function(a){a.vent.trigger(b,c)})},f.Context.prototype.wireCommand=function(b,c,d){var e=this;if(!a.isFunction(c))throw"Command must be constructable";this.vent.listenTo(this.vent,b,function(f){var g=new c;g.context=e,g.eventName=b,g.eventData=f,e.resolver.resolve(g,d),a.isFunction(g.execute)&&g.execute()},this)},f.Context.prototype.wireCommands=function(b){var c=this;a.each(b,function(b,d){a.isArray(b)?a.each(b,function(a){c.wireCommand(d,a)}):c.wireCommand(d,b)})},f.Context.prototype.wireView=function(a,b,c){return this.resolver.wireView(a,b,c),this},f.Context.prototype.wireSingleton=function(a,b,c){return this.resolver.wireSingleton(a,b,c),this},f.Context.prototype.wireValue=function(a,b){return this.resolver.wireValue(a,b),this},f.Context.prototype.wireClass=function(a,b,c){return this.resolver.wireClass(a,b,c),this},f.Context.prototype.hasWiring=function(a){return this.resolver.hasWiring(a)},f.Context.prototype.getObject=function(a){return this.resolver.getObject(a)},f.Context.prototype.instantiate=function(a){return this.resolver.instantiate(a)},f.Context.prototype.resolve=function(a,b){return this.resolver.resolve(a,b),this},f.Context.prototype.release=function(a){return this.resolver.release(a),this},f.Context.prototype.releaseAll=function(){return this.resolver.releaseAll(),this},f.Context.prototype.destroy=function(){this.vent.stopListening(),this.resolver.releaseAll(),delete g[this._contextId],this.dispatchToParent(f.EVENT_CONTEXT_SHUTDOWN)},f.Context.extend=b.View.extend;var j={contexts:g,countEvents:function(){var b=0;return a.each(g,function(c,d){g.hasOwnProperty(d)&&(b+=a.size(c.vent._events))}),b},countContexts:function(){var b=0;return a.each(g,function(a,c){g.hasOwnProperty(c)&&b++}),b}};return f.setDebug=function(a){return this.debug=a?j:void 0,this.debug},b.Geppetto=f,f}); \ No newline at end of file +!function(a){"object"==typeof exports?module.exports=a(require("underscore"),require("backbone")):"function"==typeof define&&define.amd?define(["underscore","backbone"],a):a(_,Backbone)}(function(a,b){"use strict";if(!b)throw"Please include Backbone before Geppetto";var c="no mapping found for key: ",d={SINGLETON:"singleton",VIEW:"view",OTHER:"other"},e=function(a){this._mappings={},this._context=a,this.parent=void 0};e.prototype={_createAndSetupInstance:function(a,b){var c=new a;return this.resolve(c,b),c},_retrieveFromCacheOrCreate:function(a,b){var e;if(this._mappings.hasOwnProperty(a)){var f=this._mappings[a];b||f.type!==d.SINGLETON?f.type===d.VIEW?e=f.clazz:f.clazz&&(e=this._createAndSetupInstance(f.clazz,f.wiring)):(f.object||(f.object=this._createAndSetupInstance(f.clazz,f.wiring)),e=f.object)}else{if(!this.parent||!this.parent.hasWiring(a))throw new Error(c+a);e=this.parent._retrieveFromCacheOrCreate(a,b)}return e},_wrapConstructor:function(a,b){var c=this._context;return a.extend({initialize:function(){c.resolver.resolve(this,b),a.prototype.initialize.call(this,arguments)}})},createChildResolver:function(){var a=new e(this._context);return a.parent=this,a},getObject:function(a){return this._retrieveFromCacheOrCreate(a,!1)},wireValue:function(a,b){return this._mappings[a]={clazz:null,object:b,type:d.SINGLETON},this},hasWiring:function(a){return this._mappings.hasOwnProperty(a)||!!this.parent&&this.parent.hasWiring(a)},wireClass:function(a,b,c){return this._mappings[a]={clazz:b,object:null,type:d.OTHER,wiring:c},this},wireView:function(a,b,c){return this._mappings[a]={clazz:this._wrapConstructor(b,c),object:null,type:d.VIEW},this},wireSingleton:function(a,b,c){return this._mappings[a]={clazz:b,object:null,type:d.SINGLETON,wiring:c},this},instantiate:function(a){return this._retrieveFromCacheOrCreate(a,!0)},resolve:function(b,c){if(c=c||b.wiring){var d=Number(!a.isArray(c));a.each(c,function(a){b[arguments[d]]=this.getObject(a)},this)}return this.addPubSub(b),this},addPubSub:function(b){b.listen=a.bind(this._context.listen,this._context),b.dispatch=a.bind(this._context.dispatch,this._context)},release:function(a){return delete this._mappings[a],this},releaseAll:function(){return this._mappings={},this}};var f={};f.version="0.7.0",f.EVENT_CONTEXT_SHUTDOWN="Geppetto:contextShutdown",f.Resolver=e;var g={};f.Context=function(c){this.options=c||{},this.parentContext=this.options.parentContext,this.options.resolver?this.resolver=this.options.resolver:this.parentContext?this.resolver=this.parentContext.resolver.createChildResolver():this.resolver||(this.resolver=new e(this)),this.vent={},a.extend(this.vent,b.Events),this._contextId=a.uniqueId("Context"),g[this._contextId]=this;var d=this.wiring||this.options.wiring;d&&this._configureWirings(d),a.isFunction(this.initialize)&&this.initialize.apply(this,arguments)},f.bindContext=function(b){this.options=b||{};var c=this.options.view,d=null;"function"==typeof this.options.context?(d=new this.options.context(this.options),c.close||(c.close=function(){c.trigger("close"),c.remove()}),c.on("close",function(){c.off("close"),d.destroy()})):"object"==typeof this.options.context&&(d=this.options.context),d.resolver.resolve(c),a.each(c.contextEvents,function(b,e){a.isFunction(b)?d.listen(c,e,b):a.isString(b)&&d.listen(c,e,c[b])});var e;return c.wiring||(c.context=d,e=d),e};var h=function(a,b){var c,d;return a.hasOwnProperty("ctor")?(c=a.ctor,d=a.wiring):c=a,[b,c,d]};f.Context.prototype._configureWirings=function(b){a.each(b.singletons,function(a,b){this.wireSingleton.apply(this,h(a,b))},this),a.each(b.classes,function(a,b){this.wireClass.apply(this,h(a,b))},this),a.each(b.values,function(a,b){this.wireValue(b,a)},this),a.each(b.views,function(a,b){this.wireView.apply(this,h(a,b))},this),this.wireCommands(b.commands)};var i=function(b,c,d){if(!a.isObject(b)||!a.isFunction(b.listenTo)||!a.isFunction(b.stopListening))throw"Target for listen() must define a 'listenTo' and 'stopListening' function";if(!a.isString(c))throw"eventName must be a String";if(!a.isFunction(d))throw"callback must be a function"};f.Context.prototype.listen=function(a,b,c){return i(a,b,c),a.listenTo(this.vent,b,c,a)},f.Context.prototype.listenToOnce=function(a,b,c){return i(a,b,c),a.listenToOnce(this.vent,b,c,a)},f.Context.prototype.dispatch=function(b,c){if(!a.isUndefined(c)&&!a.isObject(c))throw"Event payload must be an object";c=c||{},c.eventName=b,this.vent.trigger(b,c)},f.Context.prototype.dispatchToParent=function(a,b){this.parentContext&&this.parentContext.vent.trigger(a,b)},f.Context.prototype.dispatchGlobally=function(b,c){a.each(g,function(a){a.vent.trigger(b,c)})},f.Context.prototype.wireCommand=function(b,c,d){var e=this;if(!a.isFunction(c))throw"Command must be constructable";this.vent.listenTo(this.vent,b,function(f){var g=new c(e,b,f);g.context=e,g.eventName=b,g.eventData=f,e.resolver.resolve(g,d),a.isFunction(g.execute)&&g.execute()},this)},f.Context.prototype.wireCommands=function(b){var c=this;a.each(b,function(b,d){a.isArray(b)?a.each(b,function(a){c.wireCommand(d,a)}):c.wireCommand(d,b)})},f.Context.prototype.wireView=function(a,b,c){return this.resolver.wireView(a,b,c),this},f.Context.prototype.wireSingleton=function(a,b,c){return this.resolver.wireSingleton(a,b,c),this},f.Context.prototype.wireValue=function(a,b){return this.resolver.wireValue(a,b),this},f.Context.prototype.wireClass=function(a,b,c){return this.resolver.wireClass(a,b,c),this},f.Context.prototype.hasWiring=function(a){return this.resolver.hasWiring(a)},f.Context.prototype.getObject=function(a){return this.resolver.getObject(a)},f.Context.prototype.instantiate=function(a){return this.resolver.instantiate(a)},f.Context.prototype.resolve=function(a,b){return this.resolver.resolve(a,b),this},f.Context.prototype.release=function(a){return this.resolver.release(a),this},f.Context.prototype.releaseAll=function(){return this.resolver.releaseAll(),this},f.Context.prototype.destroy=function(){this.vent.stopListening(),this.resolver.releaseAll(),delete g[this._contextId],this.dispatchToParent(f.EVENT_CONTEXT_SHUTDOWN)},f.Context.extend=b.View.extend;var j={contexts:g,countEvents:function(){var b=0;return a.each(g,function(c,d){g.hasOwnProperty(d)&&(b+=a.size(c.vent._events))}),b},countContexts:function(){var b=0;return a.each(g,function(a,c){g.hasOwnProperty(c)&&b++}),b}};return f.setDebug=function(a){return this.debug=a?j:void 0,this.debug},b.Geppetto=f,f}); \ No newline at end of file diff --git a/specs/src/resolver-specs.js b/specs/src/resolver-specs.js index c68b701..9738e7f 100644 --- a/specs/src/resolver-specs.js +++ b/specs/src/resolver-specs.js @@ -363,6 +363,24 @@ define([ throw (/no mapping found/); }); }); + describe('when used with Backbone objects', function(){ + var clazzInstantiated; + var clazz = function(){ + clazzInstantiated++; + }; + var singleton = Backbone.Model.extend({ + wiring : ['clazz'] + }); + beforeEach(function(){ + clazzInstantiated=0; + resolver.wireClass('clazz', clazz); + resolver.wireSingleton('singleton', singleton); + }); + it("should not resolve singleton dependencies twice, see #51", function(){ + var actual = resolver.getObject('singleton'); + expect(clazzInstantiated ).to.equal(1); + }); + }); }); });