From 57b548aeaeea502bbc98c45e9a90690ed93b0dbe Mon Sep 17 00:00:00 2001 From: Mike Bierlee Date: Thu, 24 Dec 2015 19:51:49 +0100 Subject: [PATCH] Add specifying components by supertype --- source/poodinis/context.d | 22 +++++++++++-- test/poodinis/contexttest.d | 66 +++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/source/poodinis/context.d b/source/poodinis/context.d index 195cb3b..1941231 100644 --- a/source/poodinis/context.d +++ b/source/poodinis/context.d @@ -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); } } diff --git a/test/poodinis/contexttest.d b/test/poodinis/contexttest.d index 850c6bb..c9b467f 100644 --- a/test/poodinis/contexttest.d +++ b/test/poodinis/contexttest.d @@ -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"); + } + }