Skip to content

Instantly share code, notes, and snippets.

@JoeRobich
Created September 14, 2012 04:26
Show Gist options
  • Save JoeRobich/3719764 to your computer and use it in GitHub Desktop.
Save JoeRobich/3719764 to your computer and use it in GitHub Desktop.
ActionScript IoC
package com.thedevstop.utilities
{
import flash.utils.Dictionary;
public class HashMap extends Dictionary
{
public function get(key:*):*
{
return this[key];
}
public function set(key:*, value:*):void
{
this[key] = value;
}
public function remove(key:*):void
{
delete this[key];
}
public function contains(key:*):Boolean
{
return get(key) !== undefined;
}
public function get keys():Array
{
var keys:Array = [];
for (var key:* in this)
keys.push(key);
return keys;
}
public function get values():Array
{
var values:Array = [];
for (var key:* in keys)
values.push(get(key));
return values;
}
public function clear():void
{
for (var key:* in keys)
remove(key);
}
}
}
package com.thedevstop.utilities
{
import flash.utils.describeType;
import flash.utils.Dictionary;
import flash.utils.getDefinitionByName;
public class Injector
{
private var _providers:HashMap = new HashMap();
public function Injector()
{
}
public function bind(type:*, concrete:*):void
{
if (type is String)
type = getDefinitionByName(type);
if (!(type is Class))
throw new Error("type must be either a Class or a Qualified Class Name.");
if (type != String &&
concrete is String)
concrete = getDefinitionByName(concrete);
if (concrete is Class)
_providers.set(type, function() { return resolveByClass(concrete); } );
else
_providers.set(type, function() { return concrete; } );
}
public function resolve(type:*):*
{
if (type is String)
type = getDefinitionByName(type);
if (!(type is Class))
throw new Error("type must be either a Class or a Qualified Class Name.");
if (_providers.contains(type))
return _providers.get(type)();
return resolveByClass(type);
}
private function resolveByClass(type:Class):*
{
if (type.instance !== undefined)
return type.instance;
var parameters:Array = [];
var description:XML = describeType(type);
for each (var parameter:XML in description.factory.constructor.parameter)
{
if ([email protected]() != "false")
break;
parameters.push(resolve([email protected]()));
}
return createObject(type, parameters);
}
private function createObject(type:Class, parameters:Array):*
{
switch (parameters.length)
{
case 0 : return new type();
case 1 : return new type(parameters[0]);
case 2 : return new type(parameters[0], parameters[1]);
case 3 : return new type(parameters[0], parameters[1], parameters[2]);
case 4 : return new type(parameters[0], parameters[1], parameters[2], parameters[3]);
case 5 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4]);
case 6 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5]);
case 7 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6]);
case 8 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7]);
case 9 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8]);
case 10 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9]);
case 11 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10]);
case 12 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11]);
case 13 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12]);
case 14 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12], parameters[13]);
case 15 : return new type(parameters[0], parameters[1], parameters[2], parameters[3], parameters[4], parameters[5], parameters[6], parameters[7], parameters[8], parameters[9], parameters[10], parameters[11], parameters[12], parameters[13], parameters[14]);
default : throw new Error("Too many constructor parameters for createObject");
}
}
}
}
@druttka
Copy link

druttka commented Sep 14, 2012

Nice, looks like this would support some common use cases. A few thoughts:

  • In get values(), loop through this instead of through keys. Otherwise you loop twice - once to get the copy and again to iterate over it.
  • Naming Nitpick, I probably would have gone _bindings, _registrations, maybe something else over _providers. Note: Providers was used a lot in a past project to mean something very different, which might be why I am avoiding it here.
  • Some duplication at the top of bind and top of resolve. Could the logic of checking for string and turning that into Class be moved out?
  • Is line 50-51 support for singletons?!
  • What if we actually want to specify what to use for the optional parameters?
  • Let me encourage you to kick up asunit (let's not bring flex into this?) when this goes "official" =p

@druttka
Copy link

druttka commented Sep 14, 2012

Preemptive strike: I haven't had my morning coffee, so I hope the above made any bit of sense.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment