Created
October 7, 2012 05:01
-
-
Save JoeRobich/3847162 to your computer and use it in GitHub Desktop.
Port of AsFac ( https://github.com/thedevstop/asfac ) to TypeScript. Greatly simplified since there is no reflection in TypeScript. Passes no parameters when invoking a constructor and does not perform property injection.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface ICallback { | |
(factory:JsFactory, scopeName:string):any; | |
} | |
interface ICallbackDictionary { | |
[name:string]:ICallback; | |
} | |
class JsFactory { | |
static DefaultScopeName = ''; | |
private _registrations:ICallbackDictionary = { }; | |
private _registerCallback (callback:ICallback, typeName:string, scopeName:string, asSingleton:bool=false):void { | |
var qualifiedTypeName = this._getQualifiedTypeName(scopeName, typeName); | |
if (asSingleton) | |
this._registrations[qualifiedTypeName] = (function(callback:ICallback, scopeName:string) { | |
var instance:any = undefined; | |
return function(factory:JsFactory, scopeName:string) { | |
if (typeof(instance) === 'undefined') | |
instance = callback(factory, scopeName); | |
return instance; | |
}; | |
})(callback, scopeName); | |
else | |
this._registrations[qualifiedTypeName] = callback; | |
} | |
private _registerInstance (instance:any, typeName:string, scopeName:string):void { | |
this._registerCallback(function():any { return instance; }, typeName, scopeName); | |
} | |
private _registerType (type:any, typeName:string, scopeName:string, asSingleton:bool):void { | |
this._registerCallback(function():any { return new type(); }, typeName, scopeName, asSingleton); | |
} | |
private _isFunction (obj:any):bool { | |
var typeString:string = Object.prototype.toString.call(obj); | |
return (typeString === '[object Function]' && obj.length > 0); | |
} | |
private _isClass (obj:any):bool { | |
var typeString:string = Object.prototype.toString.call(obj); | |
return (typeString === '[object Function]' && obj.length == 0); | |
} | |
private _getQualifiedTypeName (scopeName:string, typeName:string):string { | |
return scopeName + ':' + typeName; | |
} | |
register (instance:any, typeName:string, scopeName:string=JsFactory.DefaultScopeName, asSingleton:bool=false):void { | |
if (this._isFunction(instance)) | |
this._registerCallback(instance, typeName, scopeName, asSingleton); | |
else if (this._isClass(instance)) | |
this._registerType(instance, typeName, scopeName, asSingleton); | |
else | |
this._registerInstance(instance, typeName, scopeName); | |
} | |
resolve (typeName:string, scopeName:string=JsFactory.DefaultScopeName):any { | |
var qualifiedTypeName = this._getQualifiedTypeName(scopeName, typeName); | |
var callback:any = this._registrations[qualifiedTypeName]; | |
return callback ? callback(this, scopeName) : undefined; | |
} | |
} | |
module JsFactoryLocator { | |
var _instance:JsFactory = null; | |
export var getFactory = function() { | |
if (_instance === null) | |
_instance = new JsFactory(); | |
return _instance; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface IDictionary { | |
[name:string]:any; | |
} | |
class Dictionary implements IDictionary { | |
} | |
function logMessage(message:string):void { | |
console.log(message); | |
document.writeln(message + '<br />'); | |
} | |
function assertTrue(assertion:string, check:bool):void { | |
var message:string = assertion + ': '; | |
message += check ? 'pass' : 'fail'; | |
logMessage(message); | |
} | |
function assertSame(assertion:string, obj1:any, obj2:any):void { | |
assertTrue(assertion, obj1 === obj2); | |
} | |
function assertNotSame(assertion:string, obj1:any, obj2:any):void { | |
assertTrue(assertion, obj1 !== obj2); | |
} | |
function assertNull(assertion:string, obj:any):void { | |
assertSame(assertion, obj, null); | |
} | |
var factory:JsFactory; | |
var instance:any; | |
var instance2:any; | |
factory = new JsFactory(); | |
instance = { foo:"bar" }; | |
factory.register(instance, "Object"); | |
instance2 = factory.resolve("Object"); | |
assertSame("test_should_allow_register_concrete_instance", instance, instance2); | |
factory = new JsFactory(); | |
factory.register(Dictionary, "Dictionary"); | |
instance = factory.resolve("Dictionary"); | |
assertSame("test_should_allow_register_type", instance.constructor, Dictionary); | |
factory = new JsFactory(); | |
instance = [1, 2, 3]; | |
factory.register(function():Array { return instance; }, "Array"); | |
instance2 = factory.resolve("Array"); | |
assertSame("test_should_allow_register_callback", instance, instance2); | |
factory = new JsFactory(); | |
factory.register(function():Dictionary { return new Dictionary(); }, "Dictionary", JsFactory.DefaultScopeName, true); | |
instance = factory.resolve("Dictionary"); | |
instance2 = factory.resolve("Dictionary"); | |
assertSame("test_should_allow_register_callback_as_singleton", instance, instance2); | |
factory = new JsFactory(); | |
factory.register(function():Dictionary { return new Dictionary(); }, "Dictionary", JsFactory.DefaultScopeName, false); | |
instance = factory.resolve("Dictionary"); | |
instance2 = factory.resolve("Dictionary"); | |
assertNotSame("test_should_return_new_instances_when_callback_not_registered_as_singleton", instance, instance2); | |
factory = new JsFactory(); | |
factory.register(Dictionary, "Dictionary", JsFactory.DefaultScopeName, true); | |
instance = factory.resolve("Dictionary"); | |
instance2 = factory.resolve("Dictionary"); | |
assertSame("test_should_allow_register_type_as_singleton", instance, instance2); | |
factory = new JsFactory(); | |
factory.register(Dictionary, "Dictionary", JsFactory.DefaultScopeName, false); | |
instance = factory.resolve("Dictionary"); | |
instance2 = factory.resolve("Dictionary"); | |
assertNotSame("test_should_return_new_instances_when_type_not_registered_as_singleton", instance, instance2); | |
factory = new JsFactory(); | |
factory.register(null, "Dictionary"); | |
instance = factory.resolve("Dictionary"); | |
assertNull("test_should_be_able_register_null_as_an_instance_value", instance); | |
factory = new JsFactory(); | |
instance = { numbers:[1, 2, 3] }; | |
factory.register(instance, "Object"); | |
instance2 = factory.resolve("Object"); | |
assertSame("test_should_resolve_default_scope_if_registered", instance, instance2); | |
factory = new JsFactory(); | |
instance = { numbers:[1, 2, 3] }; | |
factory.register(instance, "Object", "nonDefaultScope"); | |
instance2 = factory.resolve("Object", "nonDefaultScope"); | |
assertSame("test_should_resolve_type_with_specified_scope", instance, instance2); | |
var resolveFunction:Function; | |
factory = new JsFactory(); | |
resolveFunction = function (jsFactory:JsFactory, scopeName:string):any { | |
assertSame("test_should_pass_factory_into_callback_during_resolution", factory, jsFactory); | |
return new Dictionary(); | |
}; | |
factory.register(resolveFunction, "Dictionary"); | |
instance = factory.resolve("Dictionary"); | |
factory = new JsFactory(); | |
var scope:string = "nonDefaultScope"; | |
resolveFunction = function (jsFactory:JsFactory, scopeName:string):any { | |
assertSame("test_should_pass_scope_name_into_callback_during_resolution", scope, scopeName); | |
return new Dictionary(); | |
}; | |
factory.register(resolveFunction, "Dictionary", scope); | |
instance = factory.resolve("Dictionary", scope); | |
instance = new Dictionary(); | |
JsFactoryLocator.getFactory().register(instance, "Dictionary"); | |
factory = new JsFactory(); | |
factory.register(new Dictionary(), "Dictionary"); | |
instance2 = JsFactoryLocator.getFactory().resolve("Dictionary"); | |
assertSame("test_should_resolve_from_singleton_registration", instance, instance2); | |
instance = new Dictionary(); | |
JsFactoryLocator.getFactory().register(new Dictionary(), "Dictionary"); | |
factory = new JsFactory(); | |
factory.register(instance, "Dictionary"); | |
instance2 = factory.resolve("Dictionary"); | |
assertSame("test_should_resolve_from_instance_registration", instance, instance2); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Constructor functions are separated from callback functions since we expect callback functions to take 2 parameters (JsFactory and ScopeName). Ported over the applicable AsFac tests.