Skip to content

hyakugei/SwiftSuspenders

 
 

Repository files navigation

SwiftSuspenders

SwiftSuspenders is a very basic metadata driven IOC (Inversion Of Control) solution for AS3. In its basic approach, it is similar to the SmartyPants IOC framework, but it differs from SmartyPants in two respects: It is inferior in capabilities and it is quite somewhat faster.

Its main Raison d’être is supporting the very nice RobotLegs AS3 MCVS framework by Shaun Smith – hence the name.

Installation

The easiest way to use SwiftSuspenders is by adding the provided swc file to your project. If you want to use the source, you have to add the following parameter to your MXMLC settings:

-keep-as3-metadata+=Inject

Usage

Defining dependencies

SwiftSuspenders supports three types of dependency definitions:

  • value bindings, which simply map an injection request to be satisfied by injecting the given object
  • class bindings, which map an injection request to be satisfied by injecting a new instance of the given class
  • singleton bindings, which map all injection requests for the given class by injecting the same shared instance, which itself gets created on first request

For all three definition types, it’s possible to specify names, which allows using multiple injection bindings to the same class.

Defining injection points

Dependency bindings can be injected into an object using constructor injection, setter injection, field injection or method injection (or a combination of these).
setter, field and method injection require metadata for all injections to be added to the injectee class, whereas you only need to add metadata for named dependencies when using constructor injection:

[Inject]

and for injecting named dependencies

[Inject(name="NamedDependency")]

When using named dependencies for constructor injection, the metadata has to be placed above the class definition, not above the constructor. This is an unfortunate restriction the Flash Player imposes.

For methods and constructors accepting multiple parameters, it’s possible to define mixes of named and unnamed dependency bindings. In this case, trailing unnamed dependencies can simply be omitted in the metadata, whereas unnamed dependencies followed by named ones have to be declared as the empty string:

[Inject(name='', name="NamedDependency")]

Examples

Field and Setter Injection

Suppose you have a class into which you want to inject dependencies that looks like this (Note that I’ve left out import statements for brevity):

package
{
	public class MyDependentClass
	{
		[Inject]
		public var firstDepency : MovieClip;
		
		[Inject(name="currentTime")]
		public var secondDependency : Date;
		
		[Inject]
		public function set thirdDependency(value : Sprite) : void
		{
			m_thirdDependency = value;
		}
		private var m_thirdDependency : Sprite;
	}
}

To inject dependencies into an instance of this class, you would first define dependency mappings and then invoke SwiftSuspendersInjector#injectInto:

var injector : SwiftSuspendersInjector = new SwiftSuspendersInjector();
injector.mapValue(MovieClip, new MovieClip());
var currentTime : Date = new Date();
injector.mapClass(Date, currentTime, 'currentTime');
injector.mapSingleton(Sprite); //obviously, you wouldn't _really_ use Sprite singletons
var injectee : MyDependentClass = new MyDependentClass();
injector.injectInto(injectee);

Method Injection

Suppose you have a class into which you want to inject dependencies that looks like this (Note that I’ve left out import statements for brevity):

package
{
	public class MyDependentClass
	{
		private var myMovieClip : MovieClip;
		private var currentTime : Date;
		
		[Inject]
		public function setFirstDependency(injection : MovieClip) : void
		{
			myMovieClip = injection;
		}
		
		[Inject(name="currentTime")]
		public function setSecondDependency(injection : Date) : void
		{
			currentTime = injection;
		}
		
		[Inject(name='', name="currentTime")]
		public function setMultipleDependencies(movieClip : MovieClip, date : Date) : void
		{
			myMovieClip = movieClip;
			currentTime = date;
		}
	}
}

To inject dependencies into an instance of this class, you would first define dependency mappings and then invoke SwiftSuspendersInjector#injectInto:

var injector : SwiftSuspendersInjector = new SwiftSuspendersInjector();
injector.mapValue(MovieClip, new MovieClip());
var currentTime : Date = new Date();
injector.mapValue(Date, currentTime, 'currentTime');
var injectee : TestInjectee = new TestInjectee();
injector.injectInto(injectee);

In this case, the defined dependencies are partly redundant, which is waste- but otherwise not harmful.

Constructor Injection

Suppose you have a class into which you want to inject dependencies that looks like this (Note that I’ve left out import statements for brevity):

package
{
	[Inject(name='', name="currentTime")]
	public class MyDependentClass
	{
		private var myMovieClip : MovieClip;
		private var currentTime : Date;
		
		public function MyDependentClass(movieClip : MovieClip, date : Date)
		{
			myMovieClip = movieClip;
			currentTime = date;
		}
	}
}

To inject dependencies into an instance of this class, you would first define dependency mappings and then invoke SwiftSuspendersInjector#instantiate:

var injector : SwiftSuspendersInjector = new SwiftSuspendersInjector();
injector.mapValue(MovieClip, new MovieClip());
var currentTime : Date = new Date();
injector.mapValue(Date, currentTime, 'currentTime');
var injectee : TestInjectee = injector.instantiate(TestInjectee);

More Information

As these are a rather contrived and useless examples, I urge you to check out RobotLegs and its examples, which contain much better examples for using IOC in AS3.

About

Basic metadata-based IOC solution for AS3

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • ActionScript 100.0%