Add specifying components by supertype

This commit is contained in:
Mike Bierlee 2015-12-24 19:51:49 +01:00
parent d888d0a808
commit 57b548aeae
2 changed files with 86 additions and 2 deletions

View file

@ -28,12 +28,30 @@ class ApplicationContext {
*/
struct Component {}
/**
* This annotation allows you to specify by which super type the component should be registered. This
* enables you to use type-qualified alternatives for dependencies.
*/
struct RegisterByType(Type) {
Type type;
}
public void registerContextComponents(ApplicationContextType : ApplicationContext)(ApplicationContextType context, shared(DependencyContainer) container) {
import std.stdio;
foreach (member ; __traits(allMembers, ApplicationContextType)) {
static if (hasUDA!(__traits(getMember, context, member), Component)) {
auto factoryMethod = &__traits(getMember, context, member);
auto registration = container.register!(ReturnType!factoryMethod);
Registration registration = null;
foreach(attribute; __traits(getAttributes, __traits(getMember, context, member))) {
static if (is(attribute == RegisterByType!T, T)) {
registration = container.register!(typeof(attribute.type), ReturnType!factoryMethod);
}
}
if (registration is null) {
registration = container.register!(ReturnType!factoryMethod);
}
registration.instanceFactory = new InstanceFactory(registration.instanceType, CreatesSingleton.yes, null, factoryMethod);
}
}

View file

@ -11,6 +11,14 @@ import std.exception;
version(unittest) {
interface Fruit {
string getShape();
}
interface Animal {
string getYell();
}
class Banana {
public string color;
@ -21,6 +29,24 @@ version(unittest) {
class Apple {}
class Pear : Fruit {
public override string getShape() {
return "Pear shaped";
}
}
class Rabbit : Animal {
public override string getYell() {
return "Squeeeeeel";
}
}
class Wolf : Animal {
public override string getYell() {
return "Wooooooooooo";
}
}
class TestContext : ApplicationContext {
@Component
@ -31,6 +57,24 @@ version(unittest) {
public Apple apple() {
return new Apple();
}
@Component
@RegisterByType!Fruit
public Pear pear() {
return new Pear();
}
@Component
@RegisterByType!Animal
public Rabbit rabbit() {
return new Rabbit();
}
@Component
@RegisterByType!Animal
public Wolf wolf() {
return new Wolf();
}
}
//Test register component registrations from context
@ -51,4 +95,26 @@ version(unittest) {
assertThrown!ResolveException(container.resolve!Apple);
}
//Test register component by base type
unittest {
shared(DependencyContainer) container = new DependencyContainer();
auto context = new TestContext();
context.registerContextComponents(container);
auto instance = container.resolve!Fruit;
assert(instance.getShape() == "Pear shaped");
}
//Test register components with multiple candidates
unittest {
shared(DependencyContainer) container = new DependencyContainer();
auto context = new TestContext();
context.registerContextComponents(container);
auto rabbit = container.resolve!(Animal, Rabbit);
assert(rabbit.getYell() == "Squeeeeeel");
auto wolf = container.resolve!(Animal, Wolf);
assert(wolf.getYell() == "Wooooooooooo");
}
}