Reformat code to use otbs brace style

It's more compact and more common in the coding world these days.
This commit is contained in:
Mike Bierlee 2023-03-07 01:24:18 +03:00
parent 6d1bf44d28
commit 9b05aa3af9
30 changed files with 673 additions and 1308 deletions

View file

@ -1,3 +1,3 @@
{ {
"dfmt.braceStyle": "allman" "dfmt.braceStyle": "otbs"
} }

View file

@ -37,7 +37,7 @@ import poodinis;
class Driver {} class Driver {}
interface Database {}; interface Database {}
class RelationalDatabase : Database { class RelationalDatabase : Database {
private Driver driver; private Driver driver;

View file

@ -12,53 +12,42 @@ import std.digest.md;
import std.stdio; import std.stdio;
import std.conv; import std.conv;
class SecurityAuditor class SecurityAuditor {
{ public void submitAudit() {
public void submitAudit()
{
writeln("Hmmmyes I have received your audit. It is.... adequate."); writeln("Hmmmyes I have received your audit. It is.... adequate.");
} }
} }
class SuperSecurityDevice class SuperSecurityDevice {
{
private int seed; private int seed;
public this() public this() {
{
auto randomGenerator = Random(unpredictableSeed); auto randomGenerator = Random(unpredictableSeed);
seed = uniform(0, 999, randomGenerator); seed = uniform(0, 999, randomGenerator);
} }
public string getPassword() public string getPassword() {
{
return to!string(seed) ~ "t1m3sp13!!:"; return to!string(seed) ~ "t1m3sp13!!:";
} }
} }
class SecurityManager class SecurityManager {
{
@Autowire private SuperSecurityDevice levelOneSecurity; @Autowire private SuperSecurityDevice levelOneSecurity;
@Autowire @AssignNewInstance private SuperSecurityDevice levelTwoSecurity; @Autowire @AssignNewInstance private SuperSecurityDevice levelTwoSecurity;
@Autowire @OptionalDependency private SecurityAuditor auditor; @Autowire @OptionalDependency private SecurityAuditor auditor;
public void doAudit() public void doAudit() {
{ if (auditor !is null) {
if (auditor !is null)
{
auditor.submitAudit(); auditor.submitAudit();
} } else {
else
{
writeln("I uh, will skip the audit for now..."); writeln("I uh, will skip the audit for now...");
} }
} }
} }
void main() void main() {
{
auto dependencies = new shared DependencyContainer(); auto dependencies = new shared DependencyContainer();
dependencies.register!SuperSecurityDevice; // Registered with the default "Single instance" scope dependencies.register!SuperSecurityDevice; // Registered with the default "Single instance" scope
dependencies.register!SecurityManager; dependencies.register!SecurityManager;
@ -68,12 +57,9 @@ void main()
writeln("Password for user one: " ~ manager.levelOneSecurity.getPassword()); writeln("Password for user one: " ~ manager.levelOneSecurity.getPassword());
writeln("Password for user two: " ~ manager.levelTwoSecurity.getPassword()); writeln("Password for user two: " ~ manager.levelTwoSecurity.getPassword());
if (manager.levelOneSecurity is manager.levelTwoSecurity) if (manager.levelOneSecurity is manager.levelTwoSecurity) {
{
writeln("SECURITY BREACH!!!!!"); // Should not be printed since levelTwoSecurity is a new instance. writeln("SECURITY BREACH!!!!!"); // Should not be printed since levelTwoSecurity is a new instance.
} } else {
else
{
writeln("Security okay!"); writeln("Security okay!");
} }

View file

@ -9,64 +9,50 @@ import poodinis;
import std.stdio; import std.stdio;
class TownSquare class TownSquare {
{
@Autowire private MarketStall marketStall; @Autowire private MarketStall marketStall;
public void makeSound() public void makeSound() {
{
marketStall.announceGoodsForSale(); marketStall.announceGoodsForSale();
} }
} }
interface Goods interface Goods {
{
public string getGoodsName(); public string getGoodsName();
} }
class Fish : Goods class Fish : Goods {
{ public override string getGoodsName() {
public override string getGoodsName()
{
return "Fish"; return "Fish";
} }
} }
class MarketStall class MarketStall {
{
private Goods goods; private Goods goods;
this(Goods goods) this(Goods goods) {
{
this.goods = goods; this.goods = goods;
} }
public void announceGoodsForSale() public void announceGoodsForSale() {
{
writeln(goods.getGoodsName() ~ " for sale!"); writeln(goods.getGoodsName() ~ " for sale!");
} }
} }
class ExampleApplicationContext : ApplicationContext class ExampleApplicationContext : ApplicationContext {
{
@Autowire private Goods goods; @Autowire private Goods goods;
public override void registerDependencies(shared(DependencyContainer) container) public override void registerDependencies(shared(DependencyContainer) container) {
{
container.register!(Goods, Fish); container.register!(Goods, Fish);
container.register!TownSquare; container.register!TownSquare;
} }
@Component public MarketStall marketStall() @Component public MarketStall marketStall() {
{
return new MarketStall(goods); return new MarketStall(goods);
} }
} }
void main() void main() {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.registerContext!ExampleApplicationContext; container.registerContext!ExampleApplicationContext;

View file

@ -9,50 +9,39 @@ import poodinis;
import std.stdio; import std.stdio;
interface Pie interface Pie {
{
public void eat(); public void eat();
} }
class BlueBerryPie : Pie class BlueBerryPie : Pie {
{ public override void eat() {
public override void eat()
{
writeln("Nom nom nom. I like this one!"); writeln("Nom nom nom. I like this one!");
} }
} }
class ApplePie : Pie class ApplePie : Pie {
{ public override void eat() {
public override void eat()
{
writeln("Nom nom nom. These aren't real apples..."); writeln("Nom nom nom. These aren't real apples...");
} }
} }
class CardboardBoxPie : Pie class CardboardBoxPie : Pie {
{ public override void eat() {
public override void eat()
{
writeln("Nom nom nom. This... is not a pie."); writeln("Nom nom nom. This... is not a pie.");
} }
} }
class PieEater class PieEater {
{
@Autowire private Pie[] pies; @Autowire private Pie[] pies;
public void eatThemAll() public void eatThemAll() {
{ foreach (pie; pies) {
foreach (pie; pies)
{
pie.eat(); pie.eat();
} }
} }
} }
void main() void main() {
{
auto dependencies = new shared DependencyContainer(); auto dependencies = new shared DependencyContainer();
dependencies.register!(Pie, BlueBerryPie); dependencies.register!(Pie, BlueBerryPie);
dependencies.register!(Pie, ApplePie); dependencies.register!(Pie, ApplePie);

View file

@ -7,64 +7,52 @@
import std.stdio; import std.stdio;
class Scheduler class Scheduler {
{
private Calendar calendar; private Calendar calendar;
// All parameters will autmatically be assigned when Scheduler is created. // All parameters will autmatically be assigned when Scheduler is created.
this(Calendar calendar) this(Calendar calendar) {
{
this.calendar = calendar; this.calendar = calendar;
} }
public void scheduleJob() public void scheduleJob() {
{
calendar.findOpenDate(); calendar.findOpenDate();
} }
} }
class Calendar class Calendar {
{
private HardwareClock hardwareClock; private HardwareClock hardwareClock;
// This constructor contains built-in type "int" and thus will not be used. // This constructor contains built-in type "int" and thus will not be used.
this(int initialDateTimeStamp, HardwareClock hardwareClock) this(int initialDateTimeStamp, HardwareClock hardwareClock) {
{
} }
// This constructor is chosen instead as candidate for injection when Calendar is created. // This constructor is chosen instead as candidate for injection when Calendar is created.
this(HardwareClock hardwareClock) this(HardwareClock hardwareClock) {
{
this.hardwareClock = hardwareClock; this.hardwareClock = hardwareClock;
} }
public void findOpenDate() public void findOpenDate() {
{
hardwareClock.doThings(); hardwareClock.doThings();
} }
} }
class HardwareClock class HardwareClock {
{
// Parameterless constructors will halt any further selection of constructors. // Parameterless constructors will halt any further selection of constructors.
this() this() {
{
} }
// As a result, this constructor will not be used when HardwareClock is created. // As a result, this constructor will not be used when HardwareClock is created.
this(Calendar calendar) this(Calendar calendar) {
{
throw new Exception("This constructor should not be used by Poodinis"); throw new Exception("This constructor should not be used by Poodinis");
} }
public void doThings() public void doThings() {
{
writeln("Things are being done!"); writeln("Things are being done!");
} }
} }
void main() void main() {
{
import poodinis; // Locally imported to emphasize that classes do not depend on Poodinis. import poodinis; // Locally imported to emphasize that classes do not depend on Poodinis.
auto dependencies = new shared DependencyContainer(); auto dependencies = new shared DependencyContainer();

View file

@ -8,12 +8,10 @@
import poodinis; import poodinis;
import std.stdio; import std.stdio;
class Doohickey class Doohickey {
{
} }
void main() void main() {
{
auto dependencies = new shared DependencyContainer(); auto dependencies = new shared DependencyContainer();
dependencies.register!Doohickey.initializedBy({ dependencies.register!Doohickey.initializedBy({
writeln("Creating Doohickey via initializer delegate."); writeln("Creating Doohickey via initializer delegate.");

View file

@ -9,44 +9,34 @@ import poodinis;
import std.stdio; import std.stdio;
class ADependency class ADependency {
{ @PostConstruct public void postConstructor() {
@PostConstruct public void postConstructor()
{
writeln("The dependency is created."); writeln("The dependency is created.");
} }
public void callMe() public void callMe() {
{
writeln("The dependency was called."); writeln("The dependency was called.");
} }
} }
class AClass class AClass {
{
@Autowire public ADependency dependency; // Dependencies are autowired before the post-constructor is called. @Autowire public ADependency dependency; // Dependencies are autowired before the post-constructor is called.
@PostConstruct public void postConstructor() @PostConstruct public void postConstructor() {
{
writeln("The class is created."); writeln("The class is created.");
if (dependency !is null) if (dependency !is null) {
{
writeln("The dependency is autowired."); writeln("The dependency is autowired.");
} } else {
else
{
writeln("The dependency was NOT autowired."); writeln("The dependency was NOT autowired.");
} }
} }
@PreDestroy public void preDestructor() @PreDestroy public void preDestructor() {
{
writeln("The class is no longer registered with the container."); writeln("The class is no longer registered with the container.");
} }
} }
public void main() public void main() {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(ADependency).onConstructed((Object obj) { container.register!(ADependency).onConstructed((Object obj) {
writeln("ADependency constructed"); writeln("ADependency constructed");

View file

@ -9,50 +9,39 @@ import poodinis;
import std.stdio; import std.stdio;
interface Engine interface Engine {
{
public void engage(); public void engage();
} }
class FuelEngine : Engine class FuelEngine : Engine {
{ public void engage() {
public void engage()
{
writeln("VROOOOOOM!"); writeln("VROOOOOOM!");
} }
} }
class ElectricEngine : Engine class ElectricEngine : Engine {
{ public void engage() {
public void engage()
{
writeln("hummmmmmmm...."); writeln("hummmmmmmm....");
} }
} }
class HybridCar class HybridCar {
{
alias KilometersPerHour = int; alias KilometersPerHour = int;
@Autowire!FuelEngine private Engine fuelEngine; @Autowire!FuelEngine private Engine fuelEngine;
@Autowire!ElectricEngine private Engine electricEngine; @Autowire!ElectricEngine private Engine electricEngine;
public void moveAtSpeed(KilometersPerHour speed) public void moveAtSpeed(KilometersPerHour speed) {
{ if (speed <= 45) {
if (speed <= 45)
{
electricEngine.engage(); electricEngine.engage();
} } else {
else
{
fuelEngine.engage(); fuelEngine.engage();
} }
} }
} }
void main() void main() {
{
auto dependencies = new shared DependencyContainer(); auto dependencies = new shared DependencyContainer();
dependencies.register!HybridCar; dependencies.register!HybridCar;

View file

@ -7,31 +7,25 @@
import poodinis; import poodinis;
class Driver class Driver {
{
} }
interface Database interface Database {
{
} }
class RelationalDatabase : Database class RelationalDatabase : Database {
{
private Driver driver; private Driver driver;
this(Driver driver) this(Driver driver) { // Automatically injected on creation by container
{ // Automatically injected on creation by container
this.driver = driver; this.driver = driver;
} }
} }
class DataWriter class DataWriter {
{
@Autowire private Database database; // Automatically injected when class is resolved @Autowire private Database database; // Automatically injected when class is resolved
} }
void main() void main() {
{
auto dependencies = new shared DependencyContainer(); auto dependencies = new shared DependencyContainer();
dependencies.register!Driver; dependencies.register!Driver;
dependencies.register!DataWriter; dependencies.register!DataWriter;

View file

@ -7,28 +7,23 @@
import poodinis; import poodinis;
class Violin class Violin {
{
} }
interface InstrumentPlayer interface InstrumentPlayer {
{
} }
class ViolinPlayer : InstrumentPlayer class ViolinPlayer : InstrumentPlayer {
{
// Autowired concrete types can be registered on resolve // Autowired concrete types can be registered on resolve
@Autowire private Violin violin; @Autowire private Violin violin;
} }
class Orchestra class Orchestra {
{
// Autowired non-concrete types can be registered on resolved, given they have a qualifier. // Autowired non-concrete types can be registered on resolved, given they have a qualifier.
@Autowire!ViolinPlayer private InstrumentPlayer violinPlayer; @Autowire!ViolinPlayer private InstrumentPlayer violinPlayer;
} }
void main() void main() {
{
auto dependencies = new shared DependencyContainer(); auto dependencies = new shared DependencyContainer();
/* /*

View file

@ -10,12 +10,9 @@ import poodinis;
import std.stdio; import std.stdio;
import std.string; import std.string;
class IntValueInjector : ValueInjector!int class IntValueInjector : ValueInjector!int {
{ int get(string key) {
int get(string key) switch (key) {
{
switch (key)
{
case "http.port": case "http.port":
return 8080; return 8080;
case "http.keep_alive": case "http.keep_alive":
@ -26,12 +23,9 @@ class IntValueInjector : ValueInjector!int
} }
} }
class StringValueInjector : ValueInjector!string class StringValueInjector : ValueInjector!string {
{ string get(string key) {
string get(string key) switch (key) {
{
switch (key)
{
case "http.hostname": case "http.hostname":
return "acme.org"; return "acme.org";
default: default:
@ -40,8 +34,7 @@ class StringValueInjector : ValueInjector!string
} }
} }
class HttpServer class HttpServer {
{
@Value("http.port") @Value("http.port")
private int port = 80; private int port = 80;
@ -55,15 +48,13 @@ class HttpServer
@MandatoryValue("http.keep_alive") @MandatoryValue("http.keep_alive")
private int keepAliveTime; // A ResolveException is thrown when the value is not available, default assignments are not used. private int keepAliveTime; // A ResolveException is thrown when the value is not available, default assignments are not used.
public void serve() public void serve() {
{
writeln(format("Serving pages for %s:%s with max connection count of %s", writeln(format("Serving pages for %s:%s with max connection count of %s",
hostName, port, maxConnections)); hostName, port, maxConnections));
} }
} }
void main() void main() {
{
auto dependencies = new shared DependencyContainer(); auto dependencies = new shared DependencyContainer();
dependencies.register!(ValueInjector!int, IntValueInjector); dependencies.register!(ValueInjector!int, IntValueInjector);
dependencies.register!(ValueInjector!string, StringValueInjector); dependencies.register!(ValueInjector!string, StringValueInjector);

View file

@ -20,25 +20,17 @@
module poodinis.altphobos; module poodinis.altphobos;
template isFunction(X...) template isFunction(X...) {
{ static if (X.length == 1) {
static if (X.length == 1) static if (is(typeof(&X[0]) U : U*) && is(U == function) || is(typeof(&X[0]) U == delegate)) {
{
static if (is(typeof(&X[0]) U : U*) && is(U == function) || is(typeof(&X[0]) U == delegate))
{
// x is a (nested) function symbol. // x is a (nested) function symbol.
enum isFunction = true; enum isFunction = true;
} } else static if (is(X[0] T)) {
else static if (is(X[0] T))
{
// x is a type. Take the type of it and examine. // x is a type. Take the type of it and examine.
enum isFunction = is(T == function); enum isFunction = is(T == function);
} } else
else
enum isFunction = false; enum isFunction = false;
} } else {
else
{
enum isFunction = false; enum isFunction = false;
} }
} }

View file

@ -30,13 +30,11 @@ import std.string : format;
import std.traits : BaseClassesTuple, FieldNameTuple, fullyQualifiedName, hasUDA, isDynamicArray; import std.traits : BaseClassesTuple, FieldNameTuple, fullyQualifiedName, hasUDA, isDynamicArray;
import std.range : ElementType; import std.range : ElementType;
debug debug {
{
import std.stdio : writeln; import std.stdio : writeln;
} }
private struct UseMemberType private struct UseMemberType {
{
} }
/** /**
@ -72,8 +70,7 @@ private struct UseMemberType
* autowire member "fuelEngine" as if it's of type "FuelEngine". This means that the members of instance "fuelEngine" * autowire member "fuelEngine" as if it's of type "FuelEngine". This means that the members of instance "fuelEngine"
* will also be autowired because the autowire mechanism knows that member "fuelEngine" is an instance of "FuelEngine" * will also be autowired because the autowire mechanism knows that member "fuelEngine" is an instance of "FuelEngine"
*/ */
struct Autowire(QualifierType) struct Autowire(QualifierType) {
{
QualifierType qualifier; QualifierType qualifier;
} }
@ -82,8 +79,7 @@ struct Autowire(QualifierType)
* Optional dependencies will not lead to a resolveException when there is no type registered for them. * Optional dependencies will not lead to a resolveException when there is no type registered for them.
* The member will remain null. * The member will remain null.
*/ */
struct OptionalDependency struct OptionalDependency {
{
} }
/** /**
@ -99,14 +95,11 @@ struct OptionalDependency
*--- *---
* antenna will always be assigned a new instance of class Antenna. * antenna will always be assigned a new instance of class Antenna.
*/ */
struct AssignNewInstance struct AssignNewInstance {
{
} }
private void printDebugAutowiredInstance(TypeInfo instanceType, void* instanceAddress) private void printDebugAutowiredInstance(TypeInfo instanceType, void* instanceAddress) {
{ debug {
debug
{
writeln(format("DEBUG: Autowiring members of [%s@%s]", instanceType, instanceAddress)); writeln(format("DEBUG: Autowiring members of [%s@%s]", instanceType, instanceAddress));
} }
} }
@ -120,65 +113,48 @@ private void printDebugAutowiredInstance(TypeInfo instanceType, void* instanceAd
* *
* See_Also: Autowire * See_Also: Autowire
*/ */
public void autowire(Type)(shared(DependencyContainer) container, Type instance) public void autowire(Type)(shared(DependencyContainer) container, Type instance) {
{ debug (poodinisVerbose) {
debug (poodinisVerbose)
{
printDebugAutowiredInstance(typeid(Type), &instance); printDebugAutowiredInstance(typeid(Type), &instance);
} }
// Recurse into base class if there are more between Type and Object in the hierarchy // Recurse into base class if there are more between Type and Object in the hierarchy
static if (BaseClassesTuple!Type.length > 1) static if (BaseClassesTuple!Type.length > 1) {
{
autowire!(BaseClassesTuple!Type[0])(container, instance); autowire!(BaseClassesTuple!Type[0])(container, instance);
} }
foreach (index, name; FieldNameTuple!Type) foreach (index, name; FieldNameTuple!Type) {
{
autowireMember!(name, index, Type)(container, instance); autowireMember!(name, index, Type)(container, instance);
} }
} }
private void printDebugAutowiringCandidate(TypeInfo candidateInstanceType, private void printDebugAutowiringCandidate(TypeInfo candidateInstanceType,
void* candidateInstanceAddress, TypeInfo instanceType, void* instanceAddress, string member) void* candidateInstanceAddress, TypeInfo instanceType, void* instanceAddress, string member) {
{ debug {
debug
{
writeln(format("DEBUG: Autowired instance [%s@%s] to [%s@%s].%s", candidateInstanceType, writeln(format("DEBUG: Autowired instance [%s@%s] to [%s@%s].%s", candidateInstanceType,
candidateInstanceAddress, instanceType, instanceAddress, member)); candidateInstanceAddress, instanceType, instanceAddress, member));
} }
} }
private void printDebugAutowiringArray(TypeInfo superTypeInfo, private void printDebugAutowiringArray(TypeInfo superTypeInfo,
TypeInfo instanceType, void* instanceAddress, string member) TypeInfo instanceType, void* instanceAddress, string member) {
{ debug {
debug
{
writeln(format("DEBUG: Autowired all registered instances of super type %s to [%s@%s].%s", writeln(format("DEBUG: Autowired all registered instances of super type %s to [%s@%s].%s",
superTypeInfo, instanceType, instanceAddress, member)); superTypeInfo, instanceType, instanceAddress, member));
} }
} }
private void autowireMember(string member, size_t memberIndex, Type)( private void autowireMember(string member, size_t memberIndex, Type)(
shared(DependencyContainer) container, Type instance) shared(DependencyContainer) container, Type instance) {
{ foreach (attribute; __traits(getAttributes, Type.tupleof[memberIndex])) {
foreach (attribute; __traits(getAttributes, Type.tupleof[memberIndex])) static if (is(attribute == Autowire!T, T)) {
{
static if (is(attribute == Autowire!T, T))
{
injectInstance!(member, memberIndex, typeof(attribute.qualifier))(container, instance); injectInstance!(member, memberIndex, typeof(attribute.qualifier))(container, instance);
} } else static if (__traits(isSame, attribute, Autowire)) {
else static if (__traits(isSame, attribute, Autowire))
{
injectInstance!(member, memberIndex, UseMemberType)(container, instance); injectInstance!(member, memberIndex, UseMemberType)(container, instance);
} } else static if (is(typeof(attribute) == Value)) {
else static if (is(typeof(attribute) == Value))
{
enum key = attribute.key; enum key = attribute.key;
injectValue!(member, memberIndex, key, false)(container, instance); injectValue!(member, memberIndex, key, false)(container, instance);
} } else static if (is(typeof(attribute) == MandatoryValue)) {
else static if (is(typeof(attribute) == MandatoryValue))
{
enum key = attribute.key; enum key = attribute.key;
injectValue!(member, memberIndex, key, true)(container, instance); injectValue!(member, memberIndex, key, true)(container, instance);
} }
@ -186,20 +162,15 @@ private void autowireMember(string member, size_t memberIndex, Type)(
} }
private void injectInstance(string member, size_t memberIndex, QualifierType, Type)( private void injectInstance(string member, size_t memberIndex, QualifierType, Type)(
shared(DependencyContainer) container, Type instance) shared(DependencyContainer) container, Type instance) {
{ if (instance.tupleof[memberIndex] is null) {
if (instance.tupleof[memberIndex] is null)
{
alias MemberType = typeof(Type.tupleof[memberIndex]); alias MemberType = typeof(Type.tupleof[memberIndex]);
enum isOptional = hasUDA!(Type.tupleof[memberIndex], OptionalDependency); enum isOptional = hasUDA!(Type.tupleof[memberIndex], OptionalDependency);
static if (isDynamicArray!MemberType) static if (isDynamicArray!MemberType) {
{
injectMultipleInstances!(member, memberIndex, isOptional, MemberType)(container, injectMultipleInstances!(member, memberIndex, isOptional, MemberType)(container,
instance); instance);
} } else {
else
{
injectSingleInstance!(member, memberIndex, isOptional, MemberType, QualifierType)(container, injectSingleInstance!(member, memberIndex, isOptional, MemberType, QualifierType)(container,
instance); instance);
} }
@ -207,107 +178,80 @@ private void injectInstance(string member, size_t memberIndex, QualifierType, Ty
} }
private void injectMultipleInstances(string member, size_t memberIndex, private void injectMultipleInstances(string member, size_t memberIndex,
bool isOptional, MemberType, Type)(shared(DependencyContainer) container, Type instance) bool isOptional, MemberType, Type)(shared(DependencyContainer) container, Type instance) {
{
alias MemberElementType = ElementType!MemberType; alias MemberElementType = ElementType!MemberType;
static if (isOptional) static if (isOptional) {
{
auto instances = container.resolveAll!MemberElementType(ResolveOption.noResolveException); auto instances = container.resolveAll!MemberElementType(ResolveOption.noResolveException);
} } else {
else
{
auto instances = container.resolveAll!MemberElementType; auto instances = container.resolveAll!MemberElementType;
} }
instance.tupleof[memberIndex] = instances; instance.tupleof[memberIndex] = instances;
debug (poodinisVerbose) debug (poodinisVerbose) {
{
printDebugAutowiringArray(typeid(MemberElementType), typeid(Type), &instance, member); printDebugAutowiringArray(typeid(MemberElementType), typeid(Type), &instance, member);
} }
} }
private void injectSingleInstance(string member, size_t memberIndex, private void injectSingleInstance(string member, size_t memberIndex,
bool isOptional, MemberType, QualifierType, Type)( bool isOptional, MemberType, QualifierType, Type)(
shared(DependencyContainer) container, Type instance) shared(DependencyContainer) container, Type instance) {
{ debug (poodinisVerbose) {
debug (poodinisVerbose)
{
TypeInfo qualifiedInstanceType = typeid(MemberType); TypeInfo qualifiedInstanceType = typeid(MemberType);
} }
enum assignNewInstance = hasUDA!(Type.tupleof[memberIndex], AssignNewInstance); enum assignNewInstance = hasUDA!(Type.tupleof[memberIndex], AssignNewInstance);
MemberType qualifiedInstance; MemberType qualifiedInstance;
static if (!is(QualifierType == UseMemberType)) static if (!is(QualifierType == UseMemberType)) {
{
qualifiedInstance = createOrResolveInstance!(MemberType, QualifierType, qualifiedInstance = createOrResolveInstance!(MemberType, QualifierType,
assignNewInstance, isOptional)(container); assignNewInstance, isOptional)(container);
debug (poodinisVerbose) debug (poodinisVerbose) {
{
qualifiedInstanceType = typeid(QualifierType); qualifiedInstanceType = typeid(QualifierType);
} }
} } else {
else
{
qualifiedInstance = createOrResolveInstance!(MemberType, MemberType, qualifiedInstance = createOrResolveInstance!(MemberType, MemberType,
assignNewInstance, isOptional)(container); assignNewInstance, isOptional)(container);
} }
instance.tupleof[memberIndex] = qualifiedInstance; instance.tupleof[memberIndex] = qualifiedInstance;
debug (poodinisVerbose) debug (poodinisVerbose) {
{
printDebugAutowiringCandidate(qualifiedInstanceType, printDebugAutowiringCandidate(qualifiedInstanceType,
&qualifiedInstance, typeid(Type), &instance, member); &qualifiedInstance, typeid(Type), &instance, member);
} }
} }
private QualifierType createOrResolveInstance(MemberType, QualifierType, private QualifierType createOrResolveInstance(MemberType, QualifierType,
bool createNew, bool isOptional)(shared(DependencyContainer) container) bool createNew, bool isOptional)(shared(DependencyContainer) container) {
{ static if (createNew) {
static if (createNew)
{
auto instanceFactory = new InstanceFactory(); auto instanceFactory = new InstanceFactory();
instanceFactory.factoryParameters = InstanceFactoryParameters(typeid(MemberType), instanceFactory.factoryParameters = InstanceFactoryParameters(typeid(MemberType),
CreatesSingleton.no); CreatesSingleton.no);
return cast(MemberType) instanceFactory.getInstance(); return cast(MemberType) instanceFactory.getInstance();
} } else {
else static if (isOptional) {
{
static if (isOptional)
{
return container.resolve!(MemberType, QualifierType)(ResolveOption.noResolveException); return container.resolve!(MemberType, QualifierType)(ResolveOption.noResolveException);
} } else {
else
{
return container.resolve!(MemberType, QualifierType); return container.resolve!(MemberType, QualifierType);
} }
} }
} }
private void injectValue(string member, size_t memberIndex, string key, bool mandatory, Type)( private void injectValue(string member, size_t memberIndex, string key, bool mandatory, Type)(
shared(DependencyContainer) container, Type instance) shared(DependencyContainer) container, Type instance) {
{
alias MemberType = typeof(Type.tupleof[memberIndex]); alias MemberType = typeof(Type.tupleof[memberIndex]);
try try {
{
auto injector = container.resolve!(ValueInjector!MemberType); auto injector = container.resolve!(ValueInjector!MemberType);
instance.tupleof[memberIndex] = injector.get(key); instance.tupleof[memberIndex] = injector.get(key);
debug (poodinisVerbose) debug (poodinisVerbose) {
{
printDebugValueInjection(typeid(Type), &instance, member, typeid(MemberType), key); printDebugValueInjection(typeid(Type), &instance, member, typeid(MemberType), key);
} }
} } catch (ResolveException e) {
catch (ResolveException e)
{
throw new ValueInjectionException(format( throw new ValueInjectionException(format(
"Could not inject value of type %s into %s.%s: value injector is missing for this type.", "Could not inject value of type %s into %s.%s: value injector is missing for this type.",
typeid(MemberType), typeid(Type), member)); typeid(MemberType), typeid(Type), member));
} } catch (ValueNotAvailableException e) {
catch (ValueNotAvailableException e) static if (mandatory) {
{
static if (mandatory)
{
throw new ValueInjectionException(format("Could not inject value of type %s into %s.%s", throw new ValueInjectionException(format("Could not inject value of type %s into %s.%s",
typeid(MemberType), typeid(Type), member), e); typeid(MemberType), typeid(Type), member), e);
} }
@ -315,10 +259,8 @@ private void injectValue(string member, size_t memberIndex, string key, bool man
} }
private void printDebugValueInjection(TypeInfo instanceType, private void printDebugValueInjection(TypeInfo instanceType,
void* instanceAddress, string member, TypeInfo valueType, string key) void* instanceAddress, string member, TypeInfo valueType, string key) {
{ debug {
debug
{
writeln(format("DEBUG: Injected value with key '%s' of type %s into [%s@%s].%s", writeln(format("DEBUG: Injected value with key '%s' of type %s into [%s@%s].%s",
key, valueType, instanceType, instanceAddress, member)); key, valueType, instanceType, instanceAddress, member));
} }
@ -330,24 +272,20 @@ private void printDebugValueInjection(TypeInfo instanceType,
* See_Also: DependencyContainer * See_Also: DependencyContainer
* Deprecated: Using the global container is undesired. See DependencyContainer.getInstance(). * Deprecated: Using the global container is undesired. See DependencyContainer.getInstance().
*/ */
public deprecated void globalAutowire(Type)(Type instance) public deprecated void globalAutowire(Type)(Type instance) {
{
DependencyContainer.getInstance().autowire(instance); DependencyContainer.getInstance().autowire(instance);
} }
class AutowiredRegistration(RegistrationType : Object) : Registration class AutowiredRegistration(RegistrationType : Object) : Registration {
{
private shared(DependencyContainer) container; private shared(DependencyContainer) container;
public this(TypeInfo registeredType, InstanceFactory instanceFactory, public this(TypeInfo registeredType, InstanceFactory instanceFactory,
shared(DependencyContainer) originatingContainer) shared(DependencyContainer) originatingContainer) {
{
super(registeredType, typeid(RegistrationType), instanceFactory, originatingContainer); super(registeredType, typeid(RegistrationType), instanceFactory, originatingContainer);
} }
public override Object getInstance( public override Object getInstance(
InstantiationContext context = new AutowireInstantiationContext()) InstantiationContext context = new AutowireInstantiationContext()) {
{
enforce(!(originatingContainer is null), enforce(!(originatingContainer is null),
"The registration's originating container is null. There is no way to resolve autowire dependencies."); "The registration's originating container is null. There is no way to resolve autowire dependencies.");
@ -355,8 +293,7 @@ class AutowiredRegistration(RegistrationType : Object) : Registration
AutowireInstantiationContext autowireContext = cast(AutowireInstantiationContext) context; AutowireInstantiationContext autowireContext = cast(AutowireInstantiationContext) context;
enforce(!(autowireContext is null), "Given instantiation context type could not be cast to an AutowireInstantiationContext. If you relied on using the default assigned context: make sure you're calling getInstance() on an instance of type AutowiredRegistration!"); enforce(!(autowireContext is null), "Given instantiation context type could not be cast to an AutowireInstantiationContext. If you relied on using the default assigned context: make sure you're calling getInstance() on an instance of type AutowiredRegistration!");
if (autowireContext.autowireInstance) if (autowireContext.autowireInstance) {
{
originatingContainer.autowire(instance); originatingContainer.autowire(instance);
} }
@ -365,18 +302,14 @@ class AutowiredRegistration(RegistrationType : Object) : Registration
return instance; return instance;
} }
private void delegate() getPreDestructor(RegistrationType instance) private void delegate() getPreDestructor(RegistrationType instance) {
{
void delegate() preDestructor = null; void delegate() preDestructor = null;
foreach (memberName; __traits(allMembers, RegistrationType)) foreach (memberName; __traits(allMembers, RegistrationType)) {
{ foreach (overload; __traits(getOverloads, instance, memberName)) {
foreach (overload; __traits(getOverloads, instance, memberName))
{
static if (__traits(compiles, __traits(getProtection, overload)) static if (__traits(compiles, __traits(getProtection, overload))
&& __traits(getProtection, overload) == "public" && __traits(getProtection, overload) == "public"
&& isFunction!overload && isFunction!overload
&& hasUDA!(overload, PreDestroy)) && hasUDA!(overload, PreDestroy)) {
{
preDestructor = &__traits(getMember, instance, memberName); preDestructor = &__traits(getMember, instance, memberName);
} }
} }
@ -386,7 +319,6 @@ class AutowiredRegistration(RegistrationType : Object) : Registration
} }
} }
class AutowireInstantiationContext : InstantiationContext class AutowireInstantiationContext : InstantiationContext {
{
public bool autowireInstance = true; public bool autowireInstance = true;
} }

View file

@ -26,23 +26,19 @@ import std.algorithm : canFind;
import std.traits : fullyQualifiedName, hasUDA, BaseTypeTuple; import std.traits : fullyQualifiedName, hasUDA, BaseTypeTuple;
import std.meta : AliasSeq; import std.meta : AliasSeq;
debug (poodinisVerbose) debug (poodinisVerbose) {
{
import std.stdio : writeln; import std.stdio : writeln;
} }
/** /**
* Exception thrown when errors occur while resolving a type in a dependency container. * Exception thrown when errors occur while resolving a type in a dependency container.
*/ */
class ResolveException : Exception class ResolveException : Exception {
{ this(string message, TypeInfo resolveType) {
this(string message, TypeInfo resolveType)
{
super(format("Exception while resolving type %s: %s", resolveType.toString(), message)); super(format("Exception while resolving type %s: %s", resolveType.toString(), message));
} }
this(Throwable cause, TypeInfo resolveType) this(Throwable cause, TypeInfo resolveType) {
{
super(format("Exception while resolving type %s", resolveType.toString()), cause); super(format("Exception while resolving type %s", resolveType.toString()), cause);
} }
} }
@ -50,10 +46,8 @@ class ResolveException : Exception
/** /**
* Exception thrown when errors occur while registering a type in a dependency container. * Exception thrown when errors occur while registering a type in a dependency container.
*/ */
class RegistrationException : Exception class RegistrationException : Exception {
{ this(string message, TypeInfo registrationType) {
this(string message, TypeInfo registrationType)
{
super(format("Exception while registering type %s: %s", super(format("Exception while registering type %s: %s",
registrationType.toString(), message)); registrationType.toString(), message));
} }
@ -62,8 +56,7 @@ class RegistrationException : Exception
/** /**
* Options which influence the process of registering dependencies * Options which influence the process of registering dependencies
*/ */
public enum RegistrationOption public enum RegistrationOption {
{
none = 0, none = 0,
/** /**
* Prevent a concrete type being registered on itself. With this option you will always need * Prevent a concrete type being registered on itself. With this option you will always need
@ -75,8 +68,7 @@ public enum RegistrationOption
/** /**
* Options which influence the process of resolving dependencies * Options which influence the process of resolving dependencies
*/ */
public enum ResolveOption public enum ResolveOption {
{
none = 0, none = 0,
/** /**
* Registers the type you're trying to resolve before returning it. * Registers the type you're trying to resolve before returning it.
@ -99,8 +91,7 @@ public enum ResolveOption
* Multiple methods can be marked and will all be called after construction. The order in which * Multiple methods can be marked and will all be called after construction. The order in which
* methods are called is undetermined. Methods should have the signature void(void). * methods are called is undetermined. Methods should have the signature void(void).
*/ */
struct PostConstruct struct PostConstruct {
{
} }
/** /**
@ -110,8 +101,7 @@ struct PostConstruct
* This method is called when removeRegistration or clearAllRegistrations is called. * This method is called when removeRegistration or clearAllRegistrations is called.
* It will also be called when the container's destructor is called. * It will also be called when the container's destructor is called.
*/ */
struct PreDestroy struct PreDestroy {
{
} }
/** /**
@ -124,8 +114,7 @@ struct PreDestroy
* In most cases you want to use a global singleton dependency container provided by getInstance() to manage all dependencies. * In most cases you want to use a global singleton dependency container provided by getInstance() to manage all dependencies.
* You can still create new instances of this class for exceptional situations. * You can still create new instances of this class for exceptional situations.
*/ */
synchronized class DependencyContainer synchronized class DependencyContainer {
{
private Registration[][TypeInfo] registrations; private Registration[][TypeInfo] registrations;
private Registration[] autowireStack; private Registration[] autowireStack;
@ -133,8 +122,7 @@ synchronized class DependencyContainer
private RegistrationOption persistentRegistrationOptions; private RegistrationOption persistentRegistrationOptions;
private ResolveOption persistentResolveOptions; private ResolveOption persistentResolveOptions;
~this() ~this() {
{
clearAllRegistrations(); clearAllRegistrations();
} }
@ -158,8 +146,7 @@ synchronized class DependencyContainer
* *
* See_Also: singleInstance, newInstance, existingInstance * See_Also: singleInstance, newInstance, existingInstance
*/ */
public Registration register(ConcreteType)(RegistrationOption options = RegistrationOption.none) public Registration register(ConcreteType)(RegistrationOption options = RegistrationOption.none) {
{
return register!(ConcreteType, ConcreteType)(options); return register!(ConcreteType, ConcreteType)(options);
} }
@ -182,20 +169,17 @@ synchronized class DependencyContainer
*/ */
public Registration register(SuperType, ConcreteType: public Registration register(SuperType, ConcreteType:
SuperType)(RegistrationOption options = RegistrationOption.none) SuperType)(RegistrationOption options = RegistrationOption.none)
if (!is(ConcreteType == struct)) if (!is(ConcreteType == struct)) {
{
TypeInfo registeredType = typeid(SuperType); TypeInfo registeredType = typeid(SuperType);
TypeInfo_Class concreteType = typeid(ConcreteType); TypeInfo_Class concreteType = typeid(ConcreteType);
debug (poodinisVerbose) debug (poodinisVerbose) {
{
writeln(format("DEBUG: Register type %s (as %s)", writeln(format("DEBUG: Register type %s (as %s)",
concreteType.toString(), registeredType.toString())); concreteType.toString(), registeredType.toString()));
} }
auto existingRegistration = getExistingRegistration(registeredType, concreteType); auto existingRegistration = getExistingRegistration(registeredType, concreteType);
if (existingRegistration) if (existingRegistration) {
{
return existingRegistration; return existingRegistration;
} }
@ -204,11 +188,9 @@ synchronized class DependencyContainer
instanceFactory, this); instanceFactory, this);
newRegistration.initializeFactoryType().singleInstance(); newRegistration.initializeFactoryType().singleInstance();
static if (!is(SuperType == ConcreteType)) static if (!is(SuperType == ConcreteType)) {
{
if (!hasOption(options, persistentRegistrationOptions, if (!hasOption(options, persistentRegistrationOptions,
RegistrationOption.doNotAddConcreteTypeRegistration)) RegistrationOption.doNotAddConcreteTypeRegistration)) {
{
auto concreteTypeRegistration = register!ConcreteType; auto concreteTypeRegistration = register!ConcreteType;
concreteTypeRegistration.linkTo(newRegistration); concreteTypeRegistration.linkTo(newRegistration);
} }
@ -219,38 +201,30 @@ synchronized class DependencyContainer
} }
private bool hasOption(OptionType)(OptionType options, private bool hasOption(OptionType)(OptionType options,
OptionType persistentOptions, OptionType option) OptionType persistentOptions, OptionType option) {
{
return ((options | persistentOptions) & option) != 0; return ((options | persistentOptions) & option) != 0;
} }
private OptionType buildFlags(OptionType)(OptionType[] options) private OptionType buildFlags(OptionType)(OptionType[] options) {
{
OptionType flags; OptionType flags;
foreach (option; options) foreach (option; options) {
{
flags |= option; flags |= option;
} }
return flags; return flags;
} }
private Registration getExistingRegistration(TypeInfo registrationType, TypeInfo qualifierType) private Registration getExistingRegistration(TypeInfo registrationType, TypeInfo qualifierType) {
{
auto existingCandidates = registrationType in registrations; auto existingCandidates = registrationType in registrations;
if (existingCandidates) if (existingCandidates) {
{
return getRegistration(cast(Registration[])*existingCandidates, qualifierType); return getRegistration(cast(Registration[])*existingCandidates, qualifierType);
} }
return null; return null;
} }
private Registration getRegistration(Registration[] candidates, TypeInfo concreteType) private Registration getRegistration(Registration[] candidates, TypeInfo concreteType) {
{ foreach (existingRegistration; candidates) {
foreach (existingRegistration; candidates) if (existingRegistration.instanceType == concreteType) {
{
if (existingRegistration.instanceType == concreteType)
{
return existingRegistration; return existingRegistration;
} }
} }
@ -299,8 +273,7 @@ synchronized class DependencyContainer
*/ */
public RegistrationType resolve(RegistrationType)( public RegistrationType resolve(RegistrationType)(
ResolveOption resolveOptions = ResolveOption.none) ResolveOption resolveOptions = ResolveOption.none)
if (!is(RegistrationType == struct)) if (!is(RegistrationType == struct)) {
{
return resolve!(RegistrationType, RegistrationType)(resolveOptions); return resolve!(RegistrationType, RegistrationType)(resolveOptions);
} }
@ -332,32 +305,26 @@ synchronized class DependencyContainer
*/ */
public QualifierType resolve(RegistrationType, QualifierType: public QualifierType resolve(RegistrationType, QualifierType:
RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) RegistrationType)(ResolveOption resolveOptions = ResolveOption.none)
if (!is(QualifierType == struct)) if (!is(QualifierType == struct)) {
{
TypeInfo resolveType = typeid(RegistrationType); TypeInfo resolveType = typeid(RegistrationType);
TypeInfo qualifierType = typeid(QualifierType); TypeInfo qualifierType = typeid(QualifierType);
debug (poodinisVerbose) debug (poodinisVerbose) {
{
writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString()); writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString());
} }
auto candidates = resolveType in registrations; auto candidates = resolveType in registrations;
if (!candidates) if (!candidates) {
{ static if (is(typeof(typeid(QualifierType)) == TypeInfo_Class) && !__traits(isAbstractClass, QualifierType)) {
static if (is(typeof(typeid(QualifierType)) == TypeInfo_Class) && !__traits(isAbstractClass, QualifierType))
{
if (hasOption(resolveOptions, persistentResolveOptions, ResolveOption if (hasOption(resolveOptions, persistentResolveOptions, ResolveOption
.registerBeforeResolving)) .registerBeforeResolving)) {
{
register!(RegistrationType, QualifierType)(); register!(RegistrationType, QualifierType)();
return resolve!(RegistrationType, QualifierType)(resolveOptions); return resolve!(RegistrationType, QualifierType)(resolveOptions);
} }
} }
if (hasOption(resolveOptions, persistentResolveOptions, if (hasOption(resolveOptions, persistentResolveOptions,
ResolveOption.noResolveException)) ResolveOption.noResolveException)) {
{
return null; return null;
} }
@ -367,37 +334,29 @@ synchronized class DependencyContainer
Registration registration = getQualifiedRegistration(resolveType, Registration registration = getQualifiedRegistration(resolveType,
qualifierType, cast(Registration[])*candidates); qualifierType, cast(Registration[])*candidates);
try try {
{
QualifierType newInstance = resolveAutowiredInstance!QualifierType(registration); QualifierType newInstance = resolveAutowiredInstance!QualifierType(registration);
callPostConstructors(newInstance); callPostConstructors(newInstance);
return newInstance; return newInstance;
} } catch (ValueInjectionException e) {
catch (ValueInjectionException e)
{
throw new ResolveException(e, resolveType); throw new ResolveException(e, resolveType);
} }
} }
bool isRegistered(RegistrationType)() bool isRegistered(RegistrationType)() {
{
TypeInfo typeInfo = typeid(RegistrationType); TypeInfo typeInfo = typeid(RegistrationType);
auto candidates = typeInfo in registrations; auto candidates = typeInfo in registrations;
return candidates !is null; return candidates !is null;
} }
private QualifierType resolveAutowiredInstance(QualifierType)(Registration registration) private QualifierType resolveAutowiredInstance(QualifierType)(Registration registration) {
{
QualifierType instance; QualifierType instance;
if (!(cast(Registration[]) autowireStack).canFind(registration)) if (!(cast(Registration[]) autowireStack).canFind(registration)) {
{
autowireStack ~= cast(shared(Registration)) registration; autowireStack ~= cast(shared(Registration)) registration;
instance = cast(QualifierType) registration.getInstance( instance = cast(QualifierType) registration.getInstance(
new AutowireInstantiationContext()); new AutowireInstantiationContext());
autowireStack = autowireStack[0 .. $ - 1]; autowireStack = autowireStack[0 .. $ - 1];
} } else {
else
{
auto autowireContext = new AutowireInstantiationContext(); auto autowireContext = new AutowireInstantiationContext();
autowireContext.autowireInstance = false; autowireContext.autowireInstance = false;
instance = cast(QualifierType) registration.getInstance(autowireContext); instance = cast(QualifierType) registration.getInstance(autowireContext);
@ -423,25 +382,21 @@ synchronized class DependencyContainer
* --- * ---
*/ */
public RegistrationType[] resolveAll(RegistrationType)( public RegistrationType[] resolveAll(RegistrationType)(
ResolveOption resolveOptions = ResolveOption.none) ResolveOption resolveOptions = ResolveOption.none) {
{
RegistrationType[] instances; RegistrationType[] instances;
TypeInfo resolveType = typeid(RegistrationType); TypeInfo resolveType = typeid(RegistrationType);
auto qualifiedRegistrations = resolveType in registrations; auto qualifiedRegistrations = resolveType in registrations;
if (!qualifiedRegistrations) if (!qualifiedRegistrations) {
{
if (hasOption(resolveOptions, persistentResolveOptions, if (hasOption(resolveOptions, persistentResolveOptions,
ResolveOption.noResolveException)) ResolveOption.noResolveException)) {
{
return []; return [];
} }
throw new ResolveException("Type not registered.", resolveType); throw new ResolveException("Type not registered.", resolveType);
} }
foreach (registration; cast(Registration[])*qualifiedRegistrations) foreach (registration; cast(Registration[])*qualifiedRegistrations) {
{
instances ~= resolveAutowiredInstance!RegistrationType(registration); instances ~= resolveAutowiredInstance!RegistrationType(registration);
} }
@ -449,12 +404,9 @@ synchronized class DependencyContainer
} }
private Registration getQualifiedRegistration(TypeInfo resolveType, private Registration getQualifiedRegistration(TypeInfo resolveType,
TypeInfo qualifierType, Registration[] candidates) TypeInfo qualifierType, Registration[] candidates) {
{ if (resolveType == qualifierType) {
if (resolveType == qualifierType) if (candidates.length > 1) {
{
if (candidates.length > 1)
{
string candidateList = candidates.toConcreteTypeListString(); string candidateList = candidates.toConcreteTypeListString();
throw new ResolveException( throw new ResolveException(
"Multiple qualified candidates available: " ~ candidateList ~ ". Please use a qualifier.", "Multiple qualified candidates available: " ~ candidateList ~ ". Please use a qualifier.",
@ -467,17 +419,13 @@ synchronized class DependencyContainer
return getRegistration(candidates, qualifierType); return getRegistration(candidates, qualifierType);
} }
private void callPostConstructors(Type)(Type instance) private void callPostConstructors(Type)(Type instance) {
{ foreach (memberName; __traits(allMembers, Type)) {
foreach (memberName; __traits(allMembers, Type)) foreach (overload; __traits(getOverloads, instance, memberName)) {
{
foreach (overload; __traits(getOverloads, instance, memberName))
{
static if (__traits(compiles, __traits(getProtection, overload)) static if (__traits(compiles, __traits(getProtection, overload))
&& __traits(getProtection, overload) == "public" && __traits(getProtection, overload) == "public"
&& isFunction!overload && isFunction!overload
&& hasUDA!(overload, PostConstruct)) && hasUDA!(overload, PostConstruct)) {
{
__traits(getMember, instance, memberName)(); __traits(getMember, instance, memberName)();
} }
} }
@ -487,10 +435,8 @@ synchronized class DependencyContainer
/** /**
* Clears all dependency registrations managed by this container. * Clears all dependency registrations managed by this container.
*/ */
public void clearAllRegistrations() public void clearAllRegistrations() {
{ foreach (registrationsOfType; registrations) {
foreach (registrationsOfType; registrations)
{
callPreDestructorsOfRegistrations(registrationsOfType); callPreDestructorsOfRegistrations(registrationsOfType);
} }
registrations.destroy(); registrations.destroy();
@ -506,20 +452,16 @@ synchronized class DependencyContainer
* container.removeRegistration!Animal; * container.removeRegistration!Animal;
* --- * ---
*/ */
public void removeRegistration(RegistrationType)() public void removeRegistration(RegistrationType)() {
{
auto registrationsOfType = *(typeid(RegistrationType) in registrations); auto registrationsOfType = *(typeid(RegistrationType) in registrations);
callPreDestructorsOfRegistrations(registrationsOfType); callPreDestructorsOfRegistrations(registrationsOfType);
registrations.remove(typeid(RegistrationType)); registrations.remove(typeid(RegistrationType));
} }
private void callPreDestructorsOfRegistrations(shared(Registration[]) registrations) private void callPreDestructorsOfRegistrations(shared(Registration[]) registrations) {
{ foreach (registration; registrations) {
foreach (registration; registrations)
{
Registration unsharedRegistration = cast(Registration) registration; Registration unsharedRegistration = cast(Registration) registration;
if (unsharedRegistration.preDestructor !is null) if (unsharedRegistration.preDestructor !is null) {
{
unsharedRegistration.preDestructor()(); unsharedRegistration.preDestructor()();
} }
} }
@ -528,32 +470,28 @@ synchronized class DependencyContainer
/** /**
* Apply persistent registration options which will be used everytime register() is called. * Apply persistent registration options which will be used everytime register() is called.
*/ */
public void setPersistentRegistrationOptions(RegistrationOption options) public void setPersistentRegistrationOptions(RegistrationOption options) {
{
persistentRegistrationOptions = options; persistentRegistrationOptions = options;
} }
/** /**
* Unsets all applied persistent registration options * Unsets all applied persistent registration options
*/ */
public void unsetPersistentRegistrationOptions() public void unsetPersistentRegistrationOptions() {
{
persistentRegistrationOptions = RegistrationOption.none; persistentRegistrationOptions = RegistrationOption.none;
} }
/** /**
* Apply persistent resolve options which will be used everytime resolve() is called. * Apply persistent resolve options which will be used everytime resolve() is called.
*/ */
public void setPersistentResolveOptions(ResolveOption options) public void setPersistentResolveOptions(ResolveOption options) {
{
persistentResolveOptions = options; persistentResolveOptions = options;
} }
/** /**
* Unsets all applied persistent resolve options * Unsets all applied persistent resolve options
*/ */
public void unsetPersistentResolveOptions() public void unsetPersistentResolveOptions() {
{
persistentResolveOptions = ResolveOption.none; persistentResolveOptions = ResolveOption.none;
} }

View file

@ -20,10 +20,8 @@ import poodinis.autowire : autowire;
import std.traits : hasUDA, ReturnType; import std.traits : hasUDA, ReturnType;
class ApplicationContext class ApplicationContext {
{ public void registerDependencies(shared(DependencyContainer) container) {
public void registerDependencies(shared(DependencyContainer) container)
{
} }
} }
@ -31,16 +29,14 @@ class ApplicationContext
* A component annotation is used for specifying which factory methods produce components in * A component annotation is used for specifying which factory methods produce components in
* an application context. * an application context.
*/ */
struct Component struct Component {
{
} }
/** /**
* This annotation allows you to specify by which super type the component should be registered. This * 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. * enables you to use type-qualified alternatives for dependencies.
*/ */
struct RegisterByType(Type) struct RegisterByType(Type) {
{
Type type; Type type;
} }
@ -48,8 +44,7 @@ struct RegisterByType(Type)
* Components with the prototype registration will be scoped as dependencies which will create * Components with the prototype registration will be scoped as dependencies which will create
* new instances every time they are resolved. The factory method will be called repeatedly. * new instances every time they are resolved. The factory method will be called repeatedly.
*/ */
struct Prototype struct Prototype {
{
} }
/** /**
@ -59,8 +54,7 @@ struct Prototype
* It is mostly used for dependencies which come from an external library or when you don't * It is mostly used for dependencies which come from an external library or when you don't
* want to use annotations to set-up dependencies in your classes. * want to use annotations to set-up dependencies in your classes.
*/ */
public void registerContext(Context : ApplicationContext)(shared(DependencyContainer) container) public void registerContext(Context : ApplicationContext)(shared(DependencyContainer) container) {
{
auto context = new Context(); auto context = new Context();
context.registerDependencies(container); context.registerDependencies(container);
context.registerContextComponents(container); context.registerContextComponents(container);
@ -69,33 +63,24 @@ public void registerContext(Context : ApplicationContext)(shared(DependencyConta
} }
public void registerContextComponents(ApplicationContextType : ApplicationContext)( public void registerContextComponents(ApplicationContextType : ApplicationContext)(
ApplicationContextType context, shared(DependencyContainer) container) ApplicationContextType context, shared(DependencyContainer) container) {
{ foreach (memberName; __traits(allMembers, ApplicationContextType)) {
foreach (memberName; __traits(allMembers, ApplicationContextType)) foreach (overload; __traits(getOverloads, context, memberName)) {
{ static if (__traits(getProtection, overload) == "public" && hasUDA!(overload, Component)) {
foreach (overload; __traits(getOverloads, context, memberName))
{
static if (__traits(getProtection, overload) == "public" && hasUDA!(overload, Component))
{
auto factoryMethod = &__traits(getMember, context, memberName); auto factoryMethod = &__traits(getMember, context, memberName);
Registration registration = null; Registration registration = null;
auto createsSingleton = CreatesSingleton.yes; auto createsSingleton = CreatesSingleton.yes;
foreach (attribute; __traits(getAttributes, overload)) foreach (attribute; __traits(getAttributes, overload)) {
{ static if (is(attribute == RegisterByType!T, T)) {
static if (is(attribute == RegisterByType!T, T))
{
registration = container.register!(typeof(attribute.type), registration = container.register!(typeof(attribute.type),
ReturnType!factoryMethod); ReturnType!factoryMethod);
} } else static if (__traits(isSame, attribute, Prototype)) {
else static if (__traits(isSame, attribute, Prototype))
{
createsSingleton = CreatesSingleton.no; createsSingleton = CreatesSingleton.no;
} }
} }
if (registration is null) if (registration is null) {
{
registration = container.register!(ReturnType!factoryMethod); registration = container.register!(ReturnType!factoryMethod);
} }

View file

@ -19,8 +19,7 @@ import std.exception : enforce;
import std.traits : Parameters, isBuiltinType, fullyQualifiedName; import std.traits : Parameters, isBuiltinType, fullyQualifiedName;
import std.string : format; import std.string : format;
debug debug {
{
import std.stdio : writeln; import std.stdio : writeln;
} }
@ -28,42 +27,34 @@ alias CreatesSingleton = Flag!"CreatesSingleton";
alias InstanceFactoryMethod = Object delegate(); alias InstanceFactoryMethod = Object delegate();
alias InstanceEventHandler = void delegate(Object instance); alias InstanceEventHandler = void delegate(Object instance);
class InstanceCreationException : Exception class InstanceCreationException : Exception {
{ this(string message, string file = __FILE__, size_t line = __LINE__) {
this(string message, string file = __FILE__, size_t line = __LINE__)
{
super(message, file, line); super(message, file, line);
} }
} }
struct InstanceFactoryParameters struct InstanceFactoryParameters {
{
TypeInfo_Class instanceType; TypeInfo_Class instanceType;
CreatesSingleton createsSingleton = CreatesSingleton.yes; CreatesSingleton createsSingleton = CreatesSingleton.yes;
Object existingInstance; Object existingInstance;
InstanceFactoryMethod factoryMethod; InstanceFactoryMethod factoryMethod;
} }
class InstanceFactory class InstanceFactory {
{
private Object instance = null; private Object instance = null;
private InstanceFactoryParameters _factoryParameters; private InstanceFactoryParameters _factoryParameters;
private InstanceEventHandler _constructionHandler; private InstanceEventHandler _constructionHandler;
this() this() {
{
factoryParameters = InstanceFactoryParameters(); factoryParameters = InstanceFactoryParameters();
} }
public @property void factoryParameters(InstanceFactoryParameters factoryParameters) public @property void factoryParameters(InstanceFactoryParameters factoryParameters) {
{ if (factoryParameters.factoryMethod is null) {
if (factoryParameters.factoryMethod is null)
{
factoryParameters.factoryMethod = &this.createInstance; factoryParameters.factoryMethod = &this.createInstance;
} }
if (factoryParameters.existingInstance !is null) if (factoryParameters.existingInstance !is null) {
{
factoryParameters.createsSingleton = CreatesSingleton.yes; factoryParameters.createsSingleton = CreatesSingleton.yes;
this.instance = factoryParameters.existingInstance; this.instance = factoryParameters.existingInstance;
} }
@ -71,99 +62,76 @@ class InstanceFactory
_factoryParameters = factoryParameters; _factoryParameters = factoryParameters;
} }
public @property InstanceFactoryParameters factoryParameters() public @property InstanceFactoryParameters factoryParameters() {
{
return _factoryParameters; return _factoryParameters;
} }
public Object getInstance() public Object getInstance() {
{ if (_factoryParameters.createsSingleton && instance !is null) {
if (_factoryParameters.createsSingleton && instance !is null) debug (poodinisVerbose) {
{
debug (poodinisVerbose)
{
printDebugUseExistingInstance(); printDebugUseExistingInstance();
} }
return instance; return instance;
} }
debug (poodinisVerbose) debug (poodinisVerbose) {
{
printDebugCreateNewInstance(); printDebugCreateNewInstance();
} }
instance = _factoryParameters.factoryMethod(); instance = _factoryParameters.factoryMethod();
if (_constructionHandler !is null) if (_constructionHandler !is null) {
{
_constructionHandler(instance); _constructionHandler(instance);
} }
return instance; return instance;
} }
void onConstructed(InstanceEventHandler handler) void onConstructed(InstanceEventHandler handler) {
{
_constructionHandler = handler; _constructionHandler = handler;
} }
private void printDebugUseExistingInstance() private void printDebugUseExistingInstance() {
{ debug {
debug if (_factoryParameters.instanceType !is null) {
{
if (_factoryParameters.instanceType !is null)
{
writeln(format("DEBUG: Existing instance returned of type %s", writeln(format("DEBUG: Existing instance returned of type %s",
_factoryParameters.instanceType.toString())); _factoryParameters.instanceType.toString()));
} } else {
else
{
writeln("DEBUG: Existing instance returned from custom factory method"); writeln("DEBUG: Existing instance returned from custom factory method");
} }
} }
} }
private void printDebugCreateNewInstance() private void printDebugCreateNewInstance() {
{ debug {
debug if (_factoryParameters.instanceType !is null) {
{
if (_factoryParameters.instanceType !is null)
{
writeln(format("DEBUG: Creating new instance of type %s", writeln(format("DEBUG: Creating new instance of type %s",
_factoryParameters.instanceType.toString())); _factoryParameters.instanceType.toString()));
} } else {
else
{
writeln("DEBUG: Creating new instance from custom factory method"); writeln("DEBUG: Creating new instance from custom factory method");
} }
} }
} }
protected Object createInstance() protected Object createInstance() {
{
enforce!InstanceCreationException(_factoryParameters.instanceType, enforce!InstanceCreationException(_factoryParameters.instanceType,
"Instance type is not defined, cannot create instance without knowing its type."); "Instance type is not defined, cannot create instance without knowing its type.");
return _factoryParameters.instanceType.create(); return _factoryParameters.instanceType.create();
} }
} }
class ConstructorInjectingInstanceFactory(InstanceType) : InstanceFactory class ConstructorInjectingInstanceFactory(InstanceType) : InstanceFactory {
{
private shared DependencyContainer container; private shared DependencyContainer container;
private bool isBeingInjected = false; private bool isBeingInjected = false;
this(shared DependencyContainer container) this(shared DependencyContainer container) {
{
this.container = container; this.container = container;
} }
private static string createArgumentList(Params...)() private static string createArgumentList(Params...)() {
{
string argumentList = ""; string argumentList = "";
foreach (param; Params) foreach (param; Params) {
{ if (argumentList.length > 0) {
if (argumentList.length > 0)
{
argumentList ~= ","; argumentList ~= ",";
} }
@ -172,23 +140,18 @@ class ConstructorInjectingInstanceFactory(InstanceType) : InstanceFactory
return argumentList; return argumentList;
} }
private static string createImportList(Params...)() private static string createImportList(Params...)() {
{
string importList = ""; string importList = "";
foreach (param; Params) foreach (param; Params) {
{
importList ~= createImportsString!param; importList ~= createImportsString!param;
} }
return importList; return importList;
} }
private static bool parametersAreValid(Params...)() private static bool parametersAreValid(Params...)() {
{
bool isValid = true; bool isValid = true;
foreach (param; Params) foreach (param; Params) {
{ if (isBuiltinType!param || is(param == struct)) {
if (isBuiltinType!param || is(param == struct))
{
isValid = false; isValid = false;
break; break;
} }
@ -197,26 +160,23 @@ class ConstructorInjectingInstanceFactory(InstanceType) : InstanceFactory
return isValid; return isValid;
} }
protected override Object createInstance() protected override Object createInstance() {
{
enforce!InstanceCreationException(container, enforce!InstanceCreationException(container,
"A dependency container is not defined. Cannot perform constructor injection without one."); "A dependency container is not defined. Cannot perform constructor injection without one.");
enforce!InstanceCreationException(!isBeingInjected, enforce!InstanceCreationException(!isBeingInjected,
format("%s is already being created and injected; possible circular dependencies in constructors?", format("%s is already being created and injected; possible circular dependencies in constructors?",
InstanceType.stringof)); InstanceType.stringof));
Object instance = null; Object instance = null;
static if (__traits(compiles, __traits(getOverloads, InstanceType, `__ctor`))) static if (__traits(compiles, __traits(getOverloads, InstanceType, `__ctor`))) {
{ foreach (ctor; __traits(getOverloads, InstanceType, `__ctor`)) {
foreach (ctor; __traits(getOverloads, InstanceType, `__ctor`)) static if (parametersAreValid!(Parameters!ctor)) {
{
static if (parametersAreValid!(Parameters!ctor))
{
isBeingInjected = true; isBeingInjected = true;
mixin(createImportsString!InstanceType ~ createImportList!( mixin(createImportsString!InstanceType ~ createImportList!(
Parameters!ctor) ~ ` Parameters!ctor) ~ `
instance = new ` ~ fullyQualifiedName!InstanceType ~ `(` ~ createArgumentList!( instance = new `
Parameters!ctor) ~ `); ~ fullyQualifiedName!InstanceType ~ `(` ~ createArgumentList!(
Parameters!ctor) ~ `);
`); `);
isBeingInjected = false; isBeingInjected = false;
break; break;
@ -224,13 +184,12 @@ class ConstructorInjectingInstanceFactory(InstanceType) : InstanceFactory
} }
} }
if (instance is null) if (instance is null) {
{
instance = typeid(InstanceType).create(); instance = typeid(InstanceType).create();
} }
enforce!InstanceCreationException(instance !is null, enforce!InstanceCreationException(instance !is null,
"Unable to create instance of type" ~ InstanceType.stringof "Unable to create instance of type" ~ InstanceType.stringof
~ ", does it have injectable constructors?"); ~ ", does it have injectable constructors?");
return instance; return instance;

View file

@ -14,16 +14,12 @@ module poodinis.imports;
import std.meta : staticIndexOf; import std.meta : staticIndexOf;
import std.traits : moduleName, TemplateArgsOf, isBuiltinType, isType; import std.traits : moduleName, TemplateArgsOf, isBuiltinType, isType;
public static string createImportsString(Type, ParentTypeList...)() public static string createImportsString(Type, ParentTypeList...)() {
{
string imports = `import ` ~ moduleName!Type ~ `;`; string imports = `import ` ~ moduleName!Type ~ `;`;
static if (__traits(compiles, TemplateArgsOf!Type)) static if (__traits(compiles, TemplateArgsOf!Type)) {
{ foreach (TemplateArgType; TemplateArgsOf!Type) {
foreach (TemplateArgType; TemplateArgsOf!Type)
{
static if (isType!TemplateArgType && static if (isType!TemplateArgType &&
(!isBuiltinType!TemplateArgType && staticIndexOf!(TemplateArgType, ParentTypeList) == -1)) (!isBuiltinType!TemplateArgType && staticIndexOf!(TemplateArgType, ParentTypeList) == -1)) {
{
imports ~= createImportsString!(TemplateArgType, ParentTypeList, Type); imports ~= createImportsString!(TemplateArgType, ParentTypeList, Type);
} }
} }

View file

@ -27,10 +27,8 @@ module poodinis.polyfill;
import std.exception; import std.exception;
static if (!__traits(compiles, basicExceptionCtors)) static if (!__traits(compiles, basicExceptionCtors)) {
{ mixin template basicExceptionCtors() {
mixin template basicExceptionCtors()
{
/++ /++
Params: Params:
msg = The message for the exception. msg = The message for the exception.
@ -38,8 +36,7 @@ static if (!__traits(compiles, basicExceptionCtors))
line = The line number where the exception occurred. line = The line number where the exception occurred.
next = The previous exception in the chain of exceptions, if any. next = The previous exception in the chain of exceptions, if any.
+/ +/
this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @nogc @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) @nogc @safe pure nothrow {
{
super(msg, file, line, next); super(msg, file, line, next);
} }
@ -50,13 +47,10 @@ static if (!__traits(compiles, basicExceptionCtors))
file = The file where the exception occurred. file = The file where the exception occurred.
line = The line number where the exception occurred. line = The line number where the exception occurred.
+/ +/
this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) @nogc @safe pure nothrow this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) @nogc @safe pure nothrow {
{
super(msg, file, line, next); super(msg, file, line, next);
} }
} }
} } else {
else
{
public import std.exception : basicExceptionCtors; public import std.exception : basicExceptionCtors;
} }

View file

@ -17,8 +17,7 @@ import poodinis.container : DependencyContainer;
import poodinis.factory : InstanceFactory, InstanceEventHandler, import poodinis.factory : InstanceFactory, InstanceEventHandler,
InstanceCreationException, InstanceFactoryParameters, CreatesSingleton; InstanceCreationException, InstanceFactoryParameters, CreatesSingleton;
class Registration class Registration {
{
private TypeInfo _registeredType = null; private TypeInfo _registeredType = null;
private TypeInfo_Class _instanceType = null; private TypeInfo_Class _instanceType = null;
private Registration linkedRegistration; private Registration linkedRegistration;
@ -26,82 +25,68 @@ class Registration
private InstanceFactory _instanceFactory; private InstanceFactory _instanceFactory;
private void delegate() _preDestructor; private void delegate() _preDestructor;
public @property registeredType() public @property registeredType() {
{
return _registeredType; return _registeredType;
} }
public @property instanceType() public @property instanceType() {
{
return _instanceType; return _instanceType;
} }
public @property originatingContainer() public @property originatingContainer() {
{
return _originatingContainer; return _originatingContainer;
} }
public @property instanceFactory() public @property instanceFactory() {
{
return _instanceFactory; return _instanceFactory;
} }
public @property preDestructor() public @property preDestructor() {
{
return _preDestructor; return _preDestructor;
} }
protected @property preDestructor(void delegate() preDestructor) protected @property preDestructor(void delegate() preDestructor) {
{
_preDestructor = preDestructor; _preDestructor = preDestructor;
} }
this(TypeInfo registeredType, TypeInfo_Class instanceType, this(TypeInfo registeredType, TypeInfo_Class instanceType,
InstanceFactory instanceFactory, shared(DependencyContainer) originatingContainer) InstanceFactory instanceFactory, shared(DependencyContainer) originatingContainer) {
{
this._registeredType = registeredType; this._registeredType = registeredType;
this._instanceType = instanceType; this._instanceType = instanceType;
this._originatingContainer = originatingContainer; this._originatingContainer = originatingContainer;
this._instanceFactory = instanceFactory; this._instanceFactory = instanceFactory;
} }
public Object getInstance(InstantiationContext context = new InstantiationContext()) public Object getInstance(InstantiationContext context = new InstantiationContext()) {
{ if (linkedRegistration !is null) {
if (linkedRegistration !is null)
{
return linkedRegistration.getInstance(context); return linkedRegistration.getInstance(context);
} }
if (instanceFactory is null) if (instanceFactory is null) {
{
throw new InstanceCreationException( throw new InstanceCreationException(
"No instance factory defined for registration of type " ~ registeredType.toString()); "No instance factory defined for registration of type " ~ registeredType.toString());
} }
return instanceFactory.getInstance(); return instanceFactory.getInstance();
} }
public Registration linkTo(Registration registration) public Registration linkTo(Registration registration) {
{
this.linkedRegistration = registration; this.linkedRegistration = registration;
return this; return this;
} }
Registration onConstructed(InstanceEventHandler handler) Registration onConstructed(InstanceEventHandler handler) {
{
if (instanceFactory !is null) if (instanceFactory !is null)
instanceFactory.onConstructed(handler); instanceFactory.onConstructed(handler);
return this; return this;
} }
} }
private InstanceFactoryParameters copyFactoryParameters(Registration registration) private InstanceFactoryParameters copyFactoryParameters(Registration registration) {
{
return registration.instanceFactory.factoryParameters; return registration.instanceFactory.factoryParameters;
} }
private void setFactoryParameters(Registration registration, InstanceFactoryParameters newParameters) private void setFactoryParameters(Registration registration, InstanceFactoryParameters newParameters) {
{
registration.instanceFactory.factoryParameters = newParameters; registration.instanceFactory.factoryParameters = newParameters;
} }
@ -110,8 +95,7 @@ private void setFactoryParameters(Registration registration, InstanceFactoryPara
* *
* This is not a registration scope. Typically used by Poodinis internally only. * This is not a registration scope. Typically used by Poodinis internally only.
*/ */
public Registration initializeFactoryType(Registration registration) public Registration initializeFactoryType(Registration registration) {
{
auto params = registration.copyFactoryParameters(); auto params = registration.copyFactoryParameters();
params.instanceType = registration.instanceType; params.instanceType = registration.instanceType;
registration.setFactoryParameters(params); registration.setFactoryParameters(params);
@ -123,8 +107,7 @@ public Registration initializeFactoryType(Registration registration)
* *
* Effectively makes the given registration a singleton. * Effectively makes the given registration a singleton.
*/ */
public Registration singleInstance(Registration registration) public Registration singleInstance(Registration registration) {
{
auto params = registration.copyFactoryParameters(); auto params = registration.copyFactoryParameters();
params.createsSingleton = CreatesSingleton.yes; params.createsSingleton = CreatesSingleton.yes;
registration.setFactoryParameters(params); registration.setFactoryParameters(params);
@ -134,8 +117,7 @@ public Registration singleInstance(Registration registration)
/** /**
* Scopes registrations to return a new instance every time the given registration is resolved. * Scopes registrations to return a new instance every time the given registration is resolved.
*/ */
public Registration newInstance(Registration registration) public Registration newInstance(Registration registration) {
{
auto params = registration.copyFactoryParameters(); auto params = registration.copyFactoryParameters();
params.createsSingleton = CreatesSingleton.no; params.createsSingleton = CreatesSingleton.no;
params.existingInstance = null; params.existingInstance = null;
@ -146,8 +128,7 @@ public Registration newInstance(Registration registration)
/** /**
* Scopes registrations to return the given instance every time the given registration is resolved. * Scopes registrations to return the given instance every time the given registration is resolved.
*/ */
public Registration existingInstance(Registration registration, Object instance) public Registration existingInstance(Registration registration, Object instance) {
{
auto params = registration.copyFactoryParameters(); auto params = registration.copyFactoryParameters();
params.createsSingleton = CreatesSingleton.yes; params.createsSingleton = CreatesSingleton.yes;
params.existingInstance = instance; params.existingInstance = instance;
@ -159,8 +140,7 @@ public Registration existingInstance(Registration registration, Object instance)
* Scopes registrations to create new instances using the given initializer delegate. * Scopes registrations to create new instances using the given initializer delegate.
*/ */
public Registration initializedBy(T)(Registration registration, T delegate() initializer) public Registration initializedBy(T)(Registration registration, T delegate() initializer)
if (is(T == class) || is(T == interface)) if (is(T == class) || is(T == interface)) {
{
auto params = registration.copyFactoryParameters(); auto params = registration.copyFactoryParameters();
params.createsSingleton = CreatesSingleton.no; params.createsSingleton = CreatesSingleton.no;
params.factoryMethod = () => cast(Object) initializer(); params.factoryMethod = () => cast(Object) initializer();
@ -171,8 +151,7 @@ public Registration initializedBy(T)(Registration registration, T delegate() ini
/** /**
* Scopes registrations to create a new instance using the given initializer delegate. On subsequent resolves the same instance is returned. * Scopes registrations to create a new instance using the given initializer delegate. On subsequent resolves the same instance is returned.
*/ */
public Registration initializedOnceBy(T : Object)(Registration registration, T delegate() initializer) public Registration initializedOnceBy(T : Object)(Registration registration, T delegate() initializer) {
{
auto params = registration.copyFactoryParameters(); auto params = registration.copyFactoryParameters();
params.createsSingleton = CreatesSingleton.yes; params.createsSingleton = CreatesSingleton.yes;
params.factoryMethod = () => cast(Object) initializer(); params.factoryMethod = () => cast(Object) initializer();
@ -180,13 +159,10 @@ public Registration initializedOnceBy(T : Object)(Registration registration, T d
return registration; return registration;
} }
public string toConcreteTypeListString(Registration[] registrations) public string toConcreteTypeListString(Registration[] registrations) {
{
auto concreteTypeListString = ""; auto concreteTypeListString = "";
foreach (registration; registrations) foreach (registration; registrations) {
{ if (concreteTypeListString.length > 0) {
if (concreteTypeListString.length > 0)
{
concreteTypeListString ~= ", "; concreteTypeListString ~= ", ";
} }
concreteTypeListString ~= registration.instanceType.toString(); concreteTypeListString ~= registration.instanceType.toString();
@ -194,6 +170,5 @@ public string toConcreteTypeListString(Registration[] registrations)
return concreteTypeListString; return concreteTypeListString;
} }
class InstantiationContext class InstantiationContext {
{
} }

View file

@ -18,23 +18,19 @@ import std.string : format;
/** /**
* Thrown when something goes wrong during value injection. * Thrown when something goes wrong during value injection.
*/ */
class ValueInjectionException : Exception class ValueInjectionException : Exception {
{
mixin basicExceptionCtors; mixin basicExceptionCtors;
} }
/** /**
* Thrown by injectors when the value with the given key cannot be found. * Thrown by injectors when the value with the given key cannot be found.
*/ */
class ValueNotAvailableException : Exception class ValueNotAvailableException : Exception {
{ this(string key) {
this(string key)
{
super(format("Value for key %s is not available", key)); super(format("Value for key %s is not available", key));
} }
this(string key, Throwable cause) this(string key, Throwable cause) {
{
super(format("Value for key %s is not available", key), cause); super(format("Value for key %s is not available", key), cause);
} }
} }
@ -56,8 +52,7 @@ class ValueNotAvailableException : Exception
* } * }
* --- * ---
*/ */
struct Value struct Value {
{
/** /**
* The textual key used to find the value by injectors. * The textual key used to find the value by injectors.
* *
@ -83,8 +78,7 @@ struct Value
* } * }
* --- * ---
*/ */
struct MandatoryValue struct MandatoryValue {
{
/** /**
* The textual key used to find the value by injectors. * The textual key used to find the value by injectors.
* *
@ -115,8 +109,7 @@ struct MandatoryValue
* container.register!(ValueInjector!int, MyIntInjector); * container.register!(ValueInjector!int, MyIntInjector);
* --- * ---
*/ */
interface ValueInjector(Type) interface ValueInjector(Type) {
{
/** /**
* Get a value from the injector by key. * Get a value from the injector by key.
* *

View file

@ -10,12 +10,10 @@ import poodinis.test.testclasses;
import std.exception; import std.exception;
version (unittest) version (unittest) {
{
// Test autowiring concrete type to existing instance // Test autowiring concrete type to existing instance
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
auto componentB = new ComponentB(); auto componentB = new ComponentB();
@ -24,8 +22,7 @@ version (unittest)
} }
// Test autowiring interface type to existing instance // Test autowiring interface type to existing instance
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
auto componentD = new ComponentD(); auto componentD = new ComponentD();
@ -34,8 +31,7 @@ version (unittest)
} }
// Test autowiring private members // Test autowiring private members
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
auto componentD = new ComponentD(); auto componentD = new ComponentD();
@ -45,8 +41,7 @@ version (unittest)
} }
// Test autowiring will only happen once // Test autowiring will only happen once
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC).newInstance(); container.register!(InterfaceA, ComponentC).newInstance();
auto componentD = new ComponentD(); auto componentD = new ComponentD();
@ -59,8 +54,7 @@ version (unittest)
} }
// Test autowiring unregistered type // Test autowiring unregistered type
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto componentD = new ComponentD(); auto componentD = new ComponentD();
assertThrown!(ResolveException)(container.autowire(componentD), assertThrown!(ResolveException)(container.autowire(componentD),
@ -68,8 +62,7 @@ version (unittest)
} }
// Test autowiring member with non-autowire attribute does not autowire // Test autowiring member with non-autowire attribute does not autowire
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto componentE = new ComponentE(); auto componentE = new ComponentE();
container.autowire(componentE); container.autowire(componentE);
@ -78,8 +71,7 @@ version (unittest)
} }
// Test autowire class with alias declaration // Test autowire class with alias declaration
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
auto componentDeclarationCocktail = new ComponentDeclarationCocktail(); auto componentDeclarationCocktail = new ComponentDeclarationCocktail();
@ -91,8 +83,7 @@ version (unittest)
} }
// Test autowire class with qualifier // Test autowire class with qualifier
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
container.register!(InterfaceA, ComponentX); container.register!(InterfaceA, ComponentX);
@ -105,8 +96,7 @@ version (unittest)
} }
// Test autowire class with multiple qualifiers // Test autowire class with multiple qualifiers
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
container.register!(InterfaceA, ComponentX); container.register!(InterfaceA, ComponentX);
@ -123,8 +113,7 @@ version (unittest)
} }
// Test getting instance from autowired registration will autowire instance // Test getting instance from autowired registration will autowire instance
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
@ -137,8 +126,7 @@ version (unittest)
} }
// Test autowiring a dynamic array with all qualified types // Test autowiring a dynamic array with all qualified types
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(InterfaceA, ComponentC); container.register!(InterfaceA, ComponentC);
container.register!(InterfaceA, ComponentX); container.register!(InterfaceA, ComponentX);
@ -150,8 +138,7 @@ version (unittest)
} }
// Test autowiring new instance of singleinstance registration with newInstance UDA // Test autowiring new instance of singleinstance registration with newInstance UDA
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
@ -165,8 +152,7 @@ version (unittest)
} }
// Test autowiring members from base class // Test autowiring members from base class
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ComponentA; container.register!ComponentA;
container.register!ComponentB; container.register!ComponentB;
@ -179,8 +165,7 @@ version (unittest)
} }
// Test autowiring optional dependencies // Test autowiring optional dependencies
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto instance = new OuttaTime(); auto instance = new OuttaTime();
@ -192,8 +177,7 @@ version (unittest)
} }
// Test autowiring class using value injection // Test autowiring class using value injection
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(ValueInjector!int, TestInjector); container.register!(ValueInjector!int, TestInjector);
@ -207,8 +191,7 @@ version (unittest)
} }
// Test autowiring classes with recursive template parameters // Test autowiring classes with recursive template parameters
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!CircularTemplateComponentA; container.register!CircularTemplateComponentA;
container.register!CircularTemplateComponentB; container.register!CircularTemplateComponentB;
@ -224,8 +207,7 @@ version (unittest)
} }
// Test autowiring class where a method is marked with @Autowire does nothing // Test autowiring class where a method is marked with @Autowire does nothing
unittest unittest {
{
// It should also not show deprecation warning: // It should also not show deprecation warning:
// Deprecation: `__traits(getAttributes)` may only be used for individual functions, not overload sets such as: `lala` // Deprecation: `__traits(getAttributes)` may only be used for individual functions, not overload sets such as: `lala`
// the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from // the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from

View file

@ -12,21 +12,18 @@ import poodinis.test.foreigndependencies;
import std.exception; import std.exception;
import core.thread; import core.thread;
version (unittest) version (unittest) {
{
// Test register concrete type // Test register concrete type
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto registration = container.register!TestClass; auto registration = container.register!TestClass;
assert(registration.registeredType == typeid(TestClass), assert(registration.registeredType == typeid(TestClass),
"Type of registered type not the same"); "Type of registered type not the same");
} }
// Test resolve registered type // Test resolve registered type
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!TestClass; container.register!TestClass;
TestClass actualInstance = container.resolve!TestClass; TestClass actualInstance = container.resolve!TestClass;
@ -35,81 +32,73 @@ version (unittest)
} }
// Test register interface // Test register interface
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(TestInterface, TestClass); container.register!(TestInterface, TestClass);
TestInterface actualInstance = container.resolve!TestInterface; TestInterface actualInstance = container.resolve!TestInterface;
assert(actualInstance !is null, "Resolved type is null"); assert(actualInstance !is null, "Resolved type is null");
assert(cast(TestInterface) actualInstance, assert(cast(TestInterface) actualInstance,
"Resolved class is not the same type as expected"); "Resolved class is not the same type as expected");
} }
// Test resolve non-registered type // Test resolve non-registered type
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
assertThrown!ResolveException(container.resolve!TestClass, assertThrown!ResolveException(container.resolve!TestClass,
"Resolving non-registered type does not fail"); "Resolving non-registered type does not fail");
} }
// Test clear registrations // Test clear registrations
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!TestClass; container.register!TestClass;
container.clearAllRegistrations(); container.clearAllRegistrations();
assertThrown!ResolveException(container.resolve!TestClass, assertThrown!ResolveException(container.resolve!TestClass,
"Resolving cleared type does not fail"); "Resolving cleared type does not fail");
} }
// Test resolve single instance for type // Test resolve single instance for type
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!TestClass.singleInstance(); container.register!TestClass.singleInstance();
auto instance1 = container.resolve!TestClass; auto instance1 = container.resolve!TestClass;
auto instance2 = container.resolve!TestClass; auto instance2 = container.resolve!TestClass;
assert(instance1 is instance2, assert(instance1 is instance2,
"Resolved instance from single instance scope is not the each time it is resolved"); "Resolved instance from single instance scope is not the each time it is resolved");
} }
// Test resolve new instance for type // Test resolve new instance for type
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!TestClass.newInstance(); container.register!TestClass.newInstance();
auto instance1 = container.resolve!TestClass; auto instance1 = container.resolve!TestClass;
auto instance2 = container.resolve!TestClass; auto instance2 = container.resolve!TestClass;
assert(instance1 !is instance2, assert(instance1 !is instance2,
"Resolved instance from new instance scope is the same each time it is resolved"); "Resolved instance from new instance scope is the same each time it is resolved");
} }
// Test resolve existing instance for type // Test resolve existing instance for type
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto expectedInstance = new TestClass(); auto expectedInstance = new TestClass();
container.register!TestClass.existingInstance(expectedInstance); container.register!TestClass.existingInstance(expectedInstance);
auto actualInstance = container.resolve!TestClass; auto actualInstance = container.resolve!TestClass;
assert(expectedInstance is actualInstance, assert(expectedInstance is actualInstance,
"Resolved instance from existing instance scope is not the same as the registered instance"); "Resolved instance from existing instance scope is not the same as the registered instance");
} }
// Test creating instance via custom initializer on resolve // Test creating instance via custom initializer on resolve
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto expectedInstance = new TestClass(); auto expectedInstance = new TestClass();
container.register!TestClass.initializedBy({ return expectedInstance; }); container.register!TestClass.initializedBy({ return expectedInstance; });
auto actualInstance = container.resolve!TestClass; auto actualInstance = container.resolve!TestClass;
assert(expectedInstance is actualInstance, assert(expectedInstance is actualInstance,
"Resolved instance does not come from the custom initializer"); "Resolved instance does not come from the custom initializer");
} }
// Test creating instance via initializedBy creates new instance every time // Test creating instance via initializedBy creates new instance every time
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!TestClass.initializedBy({ return new TestClass(); }); container.register!TestClass.initializedBy({ return new TestClass(); });
auto firstInstance = container.resolve!TestClass; auto firstInstance = container.resolve!TestClass;
@ -118,8 +107,7 @@ version (unittest)
} }
// Test creating instance via initializedOnceBy creates a singleton instance // Test creating instance via initializedOnceBy creates a singleton instance
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!TestClass.initializedOnceBy({ return new TestClass(); }); container.register!TestClass.initializedOnceBy({ return new TestClass(); });
auto firstInstance = container.resolve!TestClass; auto firstInstance = container.resolve!TestClass;
@ -128,32 +116,29 @@ version (unittest)
} }
// Test autowire resolved instances // Test autowire resolved instances
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!AutowiredClass; container.register!AutowiredClass;
container.register!ComponentClass; container.register!ComponentClass;
auto componentInstance = container.resolve!ComponentClass; auto componentInstance = container.resolve!ComponentClass;
auto autowiredInstance = container.resolve!AutowiredClass; auto autowiredInstance = container.resolve!AutowiredClass;
assert(componentInstance.autowiredClass is autowiredInstance, assert(componentInstance.autowiredClass is autowiredInstance,
"Member is not autowired upon resolving"); "Member is not autowired upon resolving");
} }
// Test circular autowiring // Test circular autowiring
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ComponentMouse; container.register!ComponentMouse;
container.register!ComponentCat; container.register!ComponentCat;
auto mouse = container.resolve!ComponentMouse; auto mouse = container.resolve!ComponentMouse;
auto cat = container.resolve!ComponentCat; auto cat = container.resolve!ComponentCat;
assert(mouse.cat is cat && cat.mouse is mouse && mouse !is cat, assert(mouse.cat is cat && cat.mouse is mouse && mouse !is cat,
"Circular dependencies should be autowirable"); "Circular dependencies should be autowirable");
} }
// Test remove registration // Test remove registration
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!TestClass; container.register!TestClass;
container.removeRegistration!TestClass; container.removeRegistration!TestClass;
@ -161,8 +146,7 @@ version (unittest)
} }
// Test autowiring does not autowire member where instance is non-null // Test autowiring does not autowire member where instance is non-null
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto existingA = new AutowiredClass(); auto existingA = new AutowiredClass();
auto existingB = new ComponentClass(); auto existingB = new ComponentClass();
@ -174,12 +158,11 @@ version (unittest)
auto resolvedB = container.resolve!ComponentClass; auto resolvedB = container.resolve!ComponentClass;
assert(resolvedB.autowiredClass is existingA && resolvedA !is existingA, assert(resolvedB.autowiredClass is existingA && resolvedA !is existingA,
"Autowiring shouldn't rewire member when it is already wired to an instance"); "Autowiring shouldn't rewire member when it is already wired to an instance");
} }
// Test autowiring circular dependency by third-degree // Test autowiring circular dependency by third-degree
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Eenie; container.register!Eenie;
container.register!Meenie; container.register!Meenie;
@ -188,12 +171,11 @@ version (unittest)
auto eenie = container.resolve!Eenie; auto eenie = container.resolve!Eenie;
assert(eenie.meenie.moe.eenie is eenie, assert(eenie.meenie.moe.eenie is eenie,
"Autowiring third-degree circular dependency failed"); "Autowiring third-degree circular dependency failed");
} }
// Test autowiring deep circular dependencies // Test autowiring deep circular dependencies
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Ittie; container.register!Ittie;
container.register!Bittie; container.register!Bittie;
@ -205,8 +187,7 @@ version (unittest)
} }
// Test autowiring deep circular dependencies with newInstance scope does not autowire new instance second time // Test autowiring deep circular dependencies with newInstance scope does not autowire new instance second time
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Ittie.newInstance(); container.register!Ittie.newInstance();
container.register!Bittie.newInstance(); container.register!Bittie.newInstance();
@ -215,12 +196,11 @@ version (unittest)
auto ittie = container.resolve!Ittie; auto ittie = container.resolve!Ittie;
assert(ittie.bittie.banana.bittie.banana is null, assert(ittie.bittie.banana.bittie.banana is null,
"Autowiring deep dependencies with newInstance scope autowired a reoccuring type."); "Autowiring deep dependencies with newInstance scope autowired a reoccuring type.");
} }
// Test autowiring type registered by interface // Test autowiring type registered by interface
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Bunena; container.register!Bunena;
container.register!Bittie; container.register!Bittie;
@ -230,21 +210,17 @@ version (unittest)
.resolve!SuperInterface; .resolve!SuperInterface;
assert(!(superInstance.banana is null), assert(!(superInstance.banana is null),
"Instance which was resolved by interface type was not autowired."); "Instance which was resolved by interface type was not autowired.");
} }
// Test reusing a container after clearing all registrations // Test reusing a container after clearing all registrations
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Banana; container.register!Banana;
container.clearAllRegistrations(); container.clearAllRegistrations();
try try {
{
container.resolve!Banana; container.resolve!Banana;
} } catch (ResolveException e) {
catch (ResolveException e)
{
container.register!Banana; container.register!Banana;
return; return;
} }
@ -252,16 +228,14 @@ version (unittest)
} }
// Test register multiple concrete classess to same interface type // Test register multiple concrete classess to same interface type
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(Color, Blue); container.register!(Color, Blue);
container.register!(Color, Red); container.register!(Color, Red);
} }
// Test removing all registrations for type with multiple registrations. // Test removing all registrations for type with multiple registrations.
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(Color, Blue); container.register!(Color, Blue);
container.register!(Color, Red); container.register!(Color, Red);
@ -269,36 +243,30 @@ version (unittest)
} }
// Test registering same registration again // Test registering same registration again
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto firstRegistration = container.register!(Color, Blue); auto firstRegistration = container.register!(Color, Blue);
auto secondRegistration = container.register!(Color, Blue); auto secondRegistration = container.register!(Color, Blue);
assert(firstRegistration is secondRegistration, assert(firstRegistration is secondRegistration,
"First registration is not the same as the second of equal types"); "First registration is not the same as the second of equal types");
} }
// Test resolve registration with multiple qualifiers // Test resolve registration with multiple qualifiers
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(Color, Blue); container.register!(Color, Blue);
container.register!(Color, Red); container.register!(Color, Red);
try try {
{
container.resolve!Color; container.resolve!Color;
} } catch (ResolveException e) {
catch (ResolveException e)
{
return; return;
} }
assert(false); assert(false);
} }
// Test resolve registration with multiple qualifiers using a qualifier // Test resolve registration with multiple qualifiers using a qualifier
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(Color, Blue); container.register!(Color, Blue);
container.register!(Color, Red); container.register!(Color, Red);
@ -306,14 +274,13 @@ version (unittest)
auto redInstance = container.resolve!(Color, Red); auto redInstance = container.resolve!(Color, Red);
assert(blueInstance !is redInstance, assert(blueInstance !is redInstance,
"Resolving type with multiple, different registrations yielded the same instance"); "Resolving type with multiple, different registrations yielded the same instance");
assert(blueInstance !is null, "Resolved blue instance to null"); assert(blueInstance !is null, "Resolved blue instance to null");
assert(redInstance !is null, "Resolved red instance to null"); assert(redInstance !is null, "Resolved red instance to null");
} }
// Test autowire of unqualified member typed by interface. // Test autowire of unqualified member typed by interface.
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Spiders; container.register!Spiders;
container.register!(TestInterface, TestClass); container.register!(TestInterface, TestClass);
@ -324,32 +291,29 @@ version (unittest)
} }
// Register existing registration // Register existing registration
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto firstRegistration = container.register!TestClass; auto firstRegistration = container.register!TestClass;
auto secondRegistration = container.register!TestClass; auto secondRegistration = container.register!TestClass;
assert(firstRegistration is secondRegistration, assert(firstRegistration is secondRegistration,
"Registering the same registration twice registers the dependencies twice."); "Registering the same registration twice registers the dependencies twice.");
} }
// Register existing registration by supertype // Register existing registration by supertype
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto firstRegistration = container.register!(TestInterface, TestClass); auto firstRegistration = container.register!(TestInterface, TestClass);
auto secondRegistration = container.register!(TestInterface, TestClass); auto secondRegistration = container.register!(TestInterface, TestClass);
assert(firstRegistration is secondRegistration, assert(firstRegistration is secondRegistration,
"Registering the same registration by super type twice registers the dependencies twice."); "Registering the same registration by super type twice registers the dependencies twice.");
} }
// Resolve dependency depending on itself // Resolve dependency depending on itself
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Recursive; container.register!Recursive;
@ -357,12 +321,11 @@ version (unittest)
assert(instance.recursive is instance, "Resolving dependency that depends on itself fails."); assert(instance.recursive is instance, "Resolving dependency that depends on itself fails.");
assert(instance.recursive.recursive is instance, assert(instance.recursive.recursive is instance,
"Resolving dependency that depends on itself fails."); "Resolving dependency that depends on itself fails.");
} }
// Test autowire stack pop-back // Test autowire stack pop-back
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Moolah; container.register!Moolah;
container.register!Wants.newInstance(); container.register!Wants.newInstance();
@ -375,8 +338,7 @@ version (unittest)
} }
// Test resolving registration registered in different thread // Test resolving registration registered in different thread
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto thread = new Thread(delegate() { container.register!TestClass; }); auto thread = new Thread(delegate() { container.register!TestClass; });
@ -387,8 +349,7 @@ version (unittest)
} }
// Test resolving instance previously resolved in different thread // Test resolving instance previously resolved in different thread
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
shared(TestClass) actualTestClass; shared(TestClass) actualTestClass;
@ -403,31 +364,28 @@ version (unittest)
shared(TestClass) expectedTestClass = cast(shared(TestClass)) container.resolve!TestClass; shared(TestClass) expectedTestClass = cast(shared(TestClass)) container.resolve!TestClass;
assert(expectedTestClass is actualTestClass, assert(expectedTestClass is actualTestClass,
"Instance resolved in main thread is not the one resolved in thread"); "Instance resolved in main thread is not the one resolved in thread");
} }
// Test registering type with option doNotAddConcreteTypeRegistration // Test registering type with option doNotAddConcreteTypeRegistration
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(TestInterface, container.register!(TestInterface,
TestClass)(RegistrationOption.doNotAddConcreteTypeRegistration); TestClass)(RegistrationOption.doNotAddConcreteTypeRegistration);
auto firstInstance = container.resolve!TestInterface; auto firstInstance = container.resolve!TestInterface;
assertThrown!ResolveException(container.resolve!TestClass); assertThrown!ResolveException(container.resolve!TestClass);
} }
// Test registering conrete type with registration option doNotAddConcreteTypeRegistration does nothing // Test registering conrete type with registration option doNotAddConcreteTypeRegistration does nothing
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!TestClass(RegistrationOption.doNotAddConcreteTypeRegistration); container.register!TestClass(RegistrationOption.doNotAddConcreteTypeRegistration);
container.resolve!TestClass; container.resolve!TestClass;
} }
// Test registering type will register by contrete type by default // Test registering type will register by contrete type by default
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(TestInterface, TestClass); container.register!(TestInterface, TestClass);
@ -438,8 +396,7 @@ version (unittest)
} }
// Test resolving all registrations to an interface // Test resolving all registrations to an interface
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(Color, Blue); container.register!(Color, Blue);
container.register!(Color, Red); container.register!(Color, Red);
@ -450,8 +407,7 @@ version (unittest)
} }
// Test autowiring instances resolved in array // Test autowiring instances resolved in array
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!UnrelatedClass; container.register!UnrelatedClass;
container.register!(TestInterface, TestClassDeux); container.register!(TestInterface, TestClassDeux);
@ -463,45 +419,40 @@ version (unittest)
} }
// Test set persistent registration options // Test set persistent registration options
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.setPersistentRegistrationOptions( container.setPersistentRegistrationOptions(
RegistrationOption.doNotAddConcreteTypeRegistration); RegistrationOption.doNotAddConcreteTypeRegistration);
container.register!(TestInterface, TestClass); container.register!(TestInterface, TestClass);
assertThrown!ResolveException(container.resolve!TestClass); assertThrown!ResolveException(container.resolve!TestClass);
} }
// Test unset persistent registration options // Test unset persistent registration options
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.setPersistentRegistrationOptions( container.setPersistentRegistrationOptions(
RegistrationOption.doNotAddConcreteTypeRegistration); RegistrationOption.doNotAddConcreteTypeRegistration);
container.unsetPersistentRegistrationOptions(); container.unsetPersistentRegistrationOptions();
container.register!(TestInterface, TestClass); container.register!(TestInterface, TestClass);
container.resolve!TestClass; container.resolve!TestClass;
} }
// Test registration when resolving // Test registration when resolving
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.resolve!(TestInterface, TestClass)(ResolveOption.registerBeforeResolving); container.resolve!(TestInterface, TestClass)(ResolveOption.registerBeforeResolving);
container.resolve!TestClass; container.resolve!TestClass;
} }
// Test set persistent resolve options // Test set persistent resolve options
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.setPersistentResolveOptions(ResolveOption.registerBeforeResolving); container.setPersistentResolveOptions(ResolveOption.registerBeforeResolving);
container.resolve!TestClass; container.resolve!TestClass;
} }
// Test unset persistent resolve options // Test unset persistent resolve options
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.setPersistentResolveOptions(ResolveOption.registerBeforeResolving); container.setPersistentResolveOptions(ResolveOption.registerBeforeResolving);
container.unsetPersistentResolveOptions(); container.unsetPersistentResolveOptions();
@ -509,32 +460,28 @@ version (unittest)
} }
// Test ResolveOption registerBeforeResolving fails for interfaces // Test ResolveOption registerBeforeResolving fails for interfaces
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
assertThrown!ResolveException( assertThrown!ResolveException(
container.resolve!TestInterface(ResolveOption.registerBeforeResolving)); container.resolve!TestInterface(ResolveOption.registerBeforeResolving));
} }
// Test ResolveOption noResolveException does not throw // Test ResolveOption noResolveException does not throw
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto instance = container.resolve!TestInterface(ResolveOption.noResolveException); auto instance = container.resolve!TestInterface(ResolveOption.noResolveException);
assert(instance is null); assert(instance is null);
} }
// ResolveOption noResolveException does not throw for resolveAll // ResolveOption noResolveException does not throw for resolveAll
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto instances = container.resolveAll!TestInterface(ResolveOption.noResolveException); auto instances = container.resolveAll!TestInterface(ResolveOption.noResolveException);
assert(instances.length == 0); assert(instances.length == 0);
} }
// Test autowired, constructor injected class // Test autowired, constructor injected class
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Red; container.register!Red;
container.register!Moolah; container.register!Moolah;
@ -548,8 +495,7 @@ version (unittest)
} }
// Test autowired, constructor injected class where constructor argument is templated // Test autowired, constructor injected class where constructor argument is templated
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!PieChart; container.register!PieChart;
container.register!(TemplatedComponent!PieChart); container.register!(TemplatedComponent!PieChart);
@ -562,8 +508,7 @@ version (unittest)
} }
// Test injecting constructor with super-type parameter // Test injecting constructor with super-type parameter
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Wallpaper; container.register!Wallpaper;
container.register!(Color, Blue); container.register!(Color, Blue);
@ -574,8 +519,7 @@ version (unittest)
} }
// Test prevention of circular dependencies during constructor injection // Test prevention of circular dependencies during constructor injection
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Pot; container.register!Pot;
container.register!Kettle; container.register!Kettle;
@ -584,8 +528,7 @@ version (unittest)
} }
// Test prevention of transitive circular dependencies during constructor injection // Test prevention of transitive circular dependencies during constructor injection
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Rock; container.register!Rock;
container.register!Paper; container.register!Paper;
@ -595,8 +538,7 @@ version (unittest)
} }
// Test injection of foreign dependency in constructor // Test injection of foreign dependency in constructor
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Ola; container.register!Ola;
container.register!Hello; container.register!Hello;
@ -604,8 +546,7 @@ version (unittest)
} }
// Test PostConstruct method is called after resolving a dependency // Test PostConstruct method is called after resolving a dependency
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!PostConstructionDependency; container.register!PostConstructionDependency;
@ -614,8 +555,7 @@ version (unittest)
} }
// Test PostConstruct of base type is called // Test PostConstruct of base type is called
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ChildOfPostConstruction; container.register!ChildOfPostConstruction;
@ -624,8 +564,7 @@ version (unittest)
} }
// Test PostConstruct of class implementing interface is not called // Test PostConstruct of class implementing interface is not called
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ButThereWontBe; container.register!ButThereWontBe;
@ -634,8 +573,7 @@ version (unittest)
} }
// Test postconstruction happens after autowiring and value injection // Test postconstruction happens after autowiring and value injection
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(ValueInjector!int, PostConstructingIntInjector); container.register!(ValueInjector!int, PostConstructingIntInjector);
container.register!PostConstructionDependency; container.register!PostConstructionDependency;
@ -644,8 +582,7 @@ version (unittest)
} }
// Test PreDestroy is called when removing a registration // Test PreDestroy is called when removing a registration
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!PreDestroyerOfFates; container.register!PreDestroyerOfFates;
auto instance = container.resolve!PreDestroyerOfFates; auto instance = container.resolve!PreDestroyerOfFates;
@ -654,8 +591,7 @@ version (unittest)
} }
// Test PreDestroy is called when removing all registrations // Test PreDestroy is called when removing all registrations
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!PreDestroyerOfFates; container.register!PreDestroyerOfFates;
auto instance = container.resolve!PreDestroyerOfFates; auto instance = container.resolve!PreDestroyerOfFates;
@ -664,8 +600,7 @@ version (unittest)
} }
// Test PreDestroy is called when the container is destroyed // Test PreDestroy is called when the container is destroyed
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!PreDestroyerOfFates; container.register!PreDestroyerOfFates;
auto instance = container.resolve!PreDestroyerOfFates; auto instance = container.resolve!PreDestroyerOfFates;
@ -675,8 +610,7 @@ version (unittest)
} }
// Test register class by ancestor type // Test register class by ancestor type
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(Grandma, Kid); container.register!(Grandma, Kid);
auto instance = container.resolve!Grandma; auto instance = container.resolve!Grandma;

View file

@ -10,12 +10,10 @@ import poodinis.test.testclasses;
import std.exception; import std.exception;
version (unittest) version (unittest) {
{
//Test register component registrations from context //Test register component registrations from context
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto context = new TestContext(); auto context = new TestContext();
context.registerContextComponents(container); context.registerContextComponents(container);
@ -25,8 +23,7 @@ version (unittest)
} }
//Test non-annotated methods are not registered //Test non-annotated methods are not registered
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto context = new TestContext(); auto context = new TestContext();
context.registerContextComponents(container); context.registerContextComponents(container);
@ -34,8 +31,7 @@ version (unittest)
} }
//Test register component by base type //Test register component by base type
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto context = new TestContext(); auto context = new TestContext();
context.registerContextComponents(container); context.registerContextComponents(container);
@ -44,8 +40,7 @@ version (unittest)
} }
//Test register components with multiple candidates //Test register components with multiple candidates
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto context = new TestContext(); auto context = new TestContext();
context.registerContextComponents(container); context.registerContextComponents(container);
@ -58,8 +53,7 @@ version (unittest)
} }
//Test register component as prototype //Test register component as prototype
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto context = new TestContext(); auto context = new TestContext();
context.registerContextComponents(container); context.registerContextComponents(container);
@ -72,8 +66,7 @@ version (unittest)
} }
// Test setting up simple dependencies through application context // Test setting up simple dependencies through application context
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.registerContext!SimpleContext; container.registerContext!SimpleContext;
auto instance = container.resolve!CakeChart; auto instance = container.resolve!CakeChart;
@ -82,8 +75,7 @@ version (unittest)
} }
// Test resolving dependency from registered application context // Test resolving dependency from registered application context
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.registerContext!SimpleContext; container.registerContext!SimpleContext;
auto instance = container.resolve!Apple; auto instance = container.resolve!Apple;
@ -92,8 +84,7 @@ version (unittest)
} }
// Test autowiring application context // Test autowiring application context
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!Apple; container.register!Apple;
container.registerContext!AutowiredTestContext; container.registerContext!AutowiredTestContext;
@ -104,8 +95,7 @@ version (unittest)
} }
// Test autowiring application context with dependencies registered in same context // Test autowiring application context with dependencies registered in same context
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.registerContext!ComplexAutowiredTestContext; container.registerContext!ComplexAutowiredTestContext;
auto instance = container.resolve!ClassWrapperWrapper; auto instance = container.resolve!ClassWrapperWrapper;
@ -118,8 +108,7 @@ version (unittest)
} }
// Test resolving registered context // Test resolving registered context
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.registerContext!TestContext; container.registerContext!TestContext;
container.resolve!ApplicationContext; container.resolve!ApplicationContext;

View file

@ -10,15 +10,13 @@ import poodinis.test.testclasses;
import std.exception; import std.exception;
version (unittest) version (unittest) {
{
// Test instance factory with singletons // Test instance factory with singletons
unittest unittest {
{
auto factory = new InstanceFactory(); auto factory = new InstanceFactory();
factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation),
CreatesSingleton.yes); CreatesSingleton.yes);
auto instanceOne = factory.getInstance(); auto instanceOne = factory.getInstance();
auto instanceTwo = factory.getInstance(); auto instanceTwo = factory.getInstance();
@ -27,11 +25,10 @@ version (unittest)
} }
// Test instance factory with new instances // Test instance factory with new instances
unittest unittest {
{
auto factory = new InstanceFactory(); auto factory = new InstanceFactory();
factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation),
CreatesSingleton.no); CreatesSingleton.no);
auto instanceOne = factory.getInstance(); auto instanceOne = factory.getInstance();
auto instanceTwo = factory.getInstance(); auto instanceTwo = factory.getInstance();
@ -40,39 +37,35 @@ version (unittest)
} }
// Test instance factory with existing instances // Test instance factory with existing instances
unittest unittest {
{
auto existingInstance = new TestImplementation(); auto existingInstance = new TestImplementation();
auto factory = new InstanceFactory(); auto factory = new InstanceFactory();
factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation),
CreatesSingleton.yes, existingInstance); CreatesSingleton.yes, existingInstance);
auto instanceOne = factory.getInstance(); auto instanceOne = factory.getInstance();
auto instanceTwo = factory.getInstance(); auto instanceTwo = factory.getInstance();
assert(instanceOne is existingInstance, assert(instanceOne is existingInstance,
"Created factory instance is not the existing instance"); "Created factory instance is not the existing instance");
assert(instanceTwo is existingInstance, assert(instanceTwo is existingInstance,
"Created factory instance is not the existing instance when called again"); "Created factory instance is not the existing instance when called again");
} }
// Test instance factory with existing instances when setting singleton flag to "no" // Test instance factory with existing instances when setting singleton flag to "no"
unittest unittest {
{
auto existingInstance = new TestImplementation(); auto existingInstance = new TestImplementation();
auto factory = new InstanceFactory(); auto factory = new InstanceFactory();
factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation), factory.factoryParameters = InstanceFactoryParameters(typeid(TestImplementation),
CreatesSingleton.no, existingInstance); CreatesSingleton.no, existingInstance);
auto instance = factory.getInstance(); auto instance = factory.getInstance();
assert(instance is existingInstance, assert(instance is existingInstance,
"Created factory instance is not the existing instance"); "Created factory instance is not the existing instance");
} }
// Test creating instance using custom factory method // Test creating instance using custom factory method
unittest unittest {
{ Object factoryMethod() {
Object factoryMethod()
{
auto instance = new TestImplementation(); auto instance = new TestImplementation();
instance.someContent = "Ducks!"; instance.someContent = "Ducks!";
return instance; return instance;
@ -80,17 +73,16 @@ version (unittest)
auto factory = new InstanceFactory(); auto factory = new InstanceFactory();
factory.factoryParameters = InstanceFactoryParameters(null, factory.factoryParameters = InstanceFactoryParameters(null,
CreatesSingleton.yes, null, &factoryMethod); CreatesSingleton.yes, null, &factoryMethod);
auto instance = cast(TestImplementation) factory.getInstance(); auto instance = cast(TestImplementation) factory.getInstance();
assert(instance !is null, assert(instance !is null,
"No instance was created by factory or could not be cast to expected type"); "No instance was created by factory or could not be cast to expected type");
assert(instance.someContent == "Ducks!"); assert(instance.someContent == "Ducks!");
} }
// Test injecting constructor of class // Test injecting constructor of class
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!TestImplementation; container.register!TestImplementation;
@ -102,14 +94,13 @@ version (unittest)
} }
// Test injecting constructor of class with multiple constructors injects the first candidate // Test injecting constructor of class with multiple constructors injects the first candidate
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!SomeOtherClassThen; container.register!SomeOtherClassThen;
container.register!TestImplementation; container.register!TestImplementation;
auto factory = new ConstructorInjectingInstanceFactory!ClassWithMultipleConstructors( auto factory = new ConstructorInjectingInstanceFactory!ClassWithMultipleConstructors(
container); container);
auto instance = cast(ClassWithMultipleConstructors) factory.getInstance(); auto instance = cast(ClassWithMultipleConstructors) factory.getInstance();
assert(instance !is null); assert(instance !is null);
@ -118,14 +109,13 @@ version (unittest)
} }
// Test injecting constructor of class with multiple constructor parameters // Test injecting constructor of class with multiple constructor parameters
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!SomeOtherClassThen; container.register!SomeOtherClassThen;
container.register!TestImplementation; container.register!TestImplementation;
auto factory = new ConstructorInjectingInstanceFactory!ClassWithConstructorWithMultipleParameters( auto factory = new ConstructorInjectingInstanceFactory!ClassWithConstructorWithMultipleParameters(
container); container);
auto instance = cast(ClassWithConstructorWithMultipleParameters) factory.getInstance(); auto instance = cast(ClassWithConstructorWithMultipleParameters) factory.getInstance();
assert(instance !is null); assert(instance !is null);
@ -134,13 +124,12 @@ version (unittest)
} }
// Test injecting constructor of class with primitive constructor parameters // Test injecting constructor of class with primitive constructor parameters
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!SomeOtherClassThen; container.register!SomeOtherClassThen;
auto factory = new ConstructorInjectingInstanceFactory!ClassWithPrimitiveConstructor( auto factory = new ConstructorInjectingInstanceFactory!ClassWithPrimitiveConstructor(
container); container);
auto instance = cast(ClassWithPrimitiveConstructor) factory.getInstance(); auto instance = cast(ClassWithPrimitiveConstructor) factory.getInstance();
assert(instance !is null); assert(instance !is null);
@ -148,8 +137,7 @@ version (unittest)
} }
// Test injecting constructor of class with struct constructor parameters // Test injecting constructor of class with struct constructor parameters
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!SomeOtherClassThen; container.register!SomeOtherClassThen;
@ -161,8 +149,7 @@ version (unittest)
} }
// Test injecting constructor of class with empty constructor will skip injection // Test injecting constructor of class with empty constructor will skip injection
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto factory = new ConstructorInjectingInstanceFactory!ClassWithEmptyConstructor(container); auto factory = new ConstructorInjectingInstanceFactory!ClassWithEmptyConstructor(container);
@ -173,12 +160,11 @@ version (unittest)
} }
// Test injecting constructor of class with no candidates fails // Test injecting constructor of class with no candidates fails
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto factory = new ConstructorInjectingInstanceFactory!ClassWithNonInjectableConstructor( auto factory = new ConstructorInjectingInstanceFactory!ClassWithNonInjectableConstructor(
container); container);
assertThrown!InstanceCreationException(factory.getInstance()); assertThrown!InstanceCreationException(factory.getInstance());
} }

View file

@ -7,9 +7,7 @@
module poodinis.test.foreigndependencies; module poodinis.test.foreigndependencies;
version (unittest) version (unittest) {
{ class Ola {
class Ola
{
} }
} }

View file

@ -10,65 +10,59 @@ import poodinis.test.testclasses;
import std.exception; import std.exception;
version (unittest) version (unittest) {
{
// Test getting instance without scope defined throws exception // Test getting instance without scope defined throws exception
unittest unittest {
{
Registration registration = new Registration(typeid(TestType), null, null, null); Registration registration = new Registration(typeid(TestType), null, null, null);
assertThrown!(InstanceCreationException)(registration.getInstance(), null); assertThrown!(InstanceCreationException)(registration.getInstance(), null);
} }
// Test set single instance scope using scope setter // Test set single instance scope using scope setter
unittest unittest {
{
Registration registration = new Registration(null, typeid(TestType), Registration registration = new Registration(null, typeid(TestType),
new InstanceFactory(), null).initializeFactoryType(); new InstanceFactory(), null).initializeFactoryType();
auto chainedRegistration = registration.singleInstance(); auto chainedRegistration = registration.singleInstance();
auto instance1 = registration.getInstance(); auto instance1 = registration.getInstance();
auto instance2 = registration.getInstance(); auto instance2 = registration.getInstance();
assert(instance1 is instance2, assert(instance1 is instance2,
"Registration with single instance scope did not return the same instance"); "Registration with single instance scope did not return the same instance");
assert(registration is chainedRegistration, assert(registration is chainedRegistration,
"Registration returned by scope setting is not the same as the registration being set"); "Registration returned by scope setting is not the same as the registration being set");
} }
// Test set new instance scope using scope setter // Test set new instance scope using scope setter
unittest unittest {
{
Registration registration = new Registration(null, typeid(TestType), Registration registration = new Registration(null, typeid(TestType),
new InstanceFactory(), null).initializeFactoryType(); new InstanceFactory(), null).initializeFactoryType();
auto chainedRegistration = registration.newInstance(); auto chainedRegistration = registration.newInstance();
auto instance1 = registration.getInstance(); auto instance1 = registration.getInstance();
auto instance2 = registration.getInstance(); auto instance2 = registration.getInstance();
assert(instance1 !is instance2, assert(instance1 !is instance2,
"Registration with new instance scope did not return a different instance"); "Registration with new instance scope did not return a different instance");
assert(registration is chainedRegistration, assert(registration is chainedRegistration,
"Registration returned by scope setting is not the same as the registration being set"); "Registration returned by scope setting is not the same as the registration being set");
} }
// Test set existing instance scope using scope setter // Test set existing instance scope using scope setter
unittest unittest {
{
Registration registration = new Registration(null, null, new InstanceFactory(), null); Registration registration = new Registration(null, null, new InstanceFactory(), null);
auto expectedInstance = new TestType(); auto expectedInstance = new TestType();
auto chainedRegistration = registration.existingInstance(expectedInstance); auto chainedRegistration = registration.existingInstance(expectedInstance);
auto actualInstance = registration.getInstance(); auto actualInstance = registration.getInstance();
assert(expectedInstance is actualInstance, assert(expectedInstance is actualInstance,
"Registration with existing instance scope did not return the same instance"); "Registration with existing instance scope did not return the same instance");
assert(registration is chainedRegistration, assert(registration is chainedRegistration,
"Registration returned by scope setting is not the same as the registration being set"); "Registration returned by scope setting is not the same as the registration being set");
} }
// Test linking registrations // Test linking registrations
unittest unittest {
{
Registration firstRegistration = new Registration(typeid(TestInterface), Registration firstRegistration = new Registration(typeid(TestInterface),
typeid(TestImplementation), new InstanceFactory(), null).initializeFactoryType() typeid(TestImplementation), new InstanceFactory(), null).initializeFactoryType()
.singleInstance(); .singleInstance();
Registration secondRegistration = new Registration(typeid(TestImplementation), Registration secondRegistration = new Registration(typeid(TestImplementation),
typeid(TestImplementation), new InstanceFactory(), null).initializeFactoryType() typeid(TestImplementation), new InstanceFactory(), null).initializeFactoryType()
.singleInstance().linkTo(firstRegistration); .singleInstance().linkTo(firstRegistration);
auto firstInstance = firstRegistration.getInstance(); auto firstInstance = firstRegistration.getInstance();
@ -78,10 +72,9 @@ version (unittest)
} }
// Test custom factory method via initializedBy // Test custom factory method via initializedBy
unittest unittest {
{
Registration registration = new Registration(typeid(TestInterface), Registration registration = new Registration(typeid(TestInterface),
typeid(TestImplementation), new InstanceFactory(), null); typeid(TestImplementation), new InstanceFactory(), null);
registration.initializedBy({ registration.initializedBy({
auto instance = new TestImplementation(); auto instance = new TestImplementation();
@ -97,10 +90,9 @@ version (unittest)
} }
// Test custom factory method via initializedOnceBy // Test custom factory method via initializedOnceBy
unittest unittest {
{
Registration registration = new Registration(typeid(TestInterface), Registration registration = new Registration(typeid(TestInterface),
typeid(TestImplementation), new InstanceFactory(), null); typeid(TestImplementation), new InstanceFactory(), null);
registration.initializedOnceBy({ registration.initializedOnceBy({
auto instance = new TestImplementation(); auto instance = new TestImplementation();
@ -116,10 +108,9 @@ version (unittest)
} }
// Test chaining single/new instance scope to initializedBy will not overwrite the factory method. // Test chaining single/new instance scope to initializedBy will not overwrite the factory method.
unittest unittest {
{
Registration registration = new Registration(typeid(TestInterface), Registration registration = new Registration(typeid(TestInterface),
typeid(TestImplementation), new InstanceFactory(), null); typeid(TestImplementation), new InstanceFactory(), null);
registration.initializedBy({ registration.initializedBy({
auto instance = new TestImplementation(); auto instance = new TestImplementation();

View file

@ -10,92 +10,73 @@ module poodinis.test.testclasses;
import poodinis; import poodinis;
import poodinis.test.foreigndependencies; import poodinis.test.foreigndependencies;
version (unittest) version (unittest) {
{ class ComponentA {
class ComponentA
{
} }
class ComponentB class ComponentB {
{
public @Autowire ComponentA componentA; public @Autowire ComponentA componentA;
} }
interface InterfaceA interface InterfaceA {
{
} }
class ComponentC : InterfaceA class ComponentC : InterfaceA {
{
} }
class ComponentD class ComponentD {
{
public @Autowire InterfaceA componentC = null; public @Autowire InterfaceA componentC = null;
private @Autowire InterfaceA _privateComponentC = null; private @Autowire InterfaceA _privateComponentC = null;
public InterfaceA privateComponentC() public InterfaceA privateComponentC() {
{
return _privateComponentC; return _privateComponentC;
} }
} }
class DummyAttribute class DummyAttribute {
{
}; };
class ComponentE class ComponentE {
{
@DummyAttribute public ComponentC componentC; @DummyAttribute public ComponentC componentC;
} }
class ComponentDeclarationCocktail class ComponentDeclarationCocktail {
{
alias noomer = int; alias noomer = int;
@Autowire public ComponentA componentA; @Autowire public ComponentA componentA;
public void doesNothing() public void doesNothing() {
{
} }
~this() ~this() {
{
} }
} }
class ComponentX : InterfaceA class ComponentX : InterfaceA {
{
} }
class ComponentZ : ComponentB class ComponentZ : ComponentB {
{
} }
class MonkeyShine class MonkeyShine {
{
@Autowire!ComponentX public InterfaceA component; @Autowire!ComponentX public InterfaceA component;
} }
class BootstrapBootstrap class BootstrapBootstrap {
{
@Autowire!ComponentX public InterfaceA componentX; @Autowire!ComponentX public InterfaceA componentX;
@Autowire!ComponentC public InterfaceA componentC; @Autowire!ComponentC public InterfaceA componentC;
} }
class LordOfTheComponents class LordOfTheComponents {
{
@Autowire public InterfaceA[] components; @Autowire public InterfaceA[] components;
} }
class ComponentCharlie class ComponentCharlie {
{
@Autowire @AssignNewInstance public ComponentA componentA; @Autowire @AssignNewInstance public ComponentA componentA;
} }
class OuttaTime class OuttaTime {
{
@Autowire @OptionalDependency public InterfaceA interfaceA; @Autowire @OptionalDependency public InterfaceA interfaceA;
@Autowire @OptionalDependency public ComponentA componentA; @Autowire @OptionalDependency public ComponentA componentA;
@ -103,537 +84,423 @@ version (unittest)
@Autowire @OptionalDependency public ComponentC[] componentCs; @Autowire @OptionalDependency public ComponentC[] componentCs;
} }
class ValuedClass class ValuedClass {
{
@Value("values.int") @Value("values.int")
public int intValue; public int intValue;
@Autowire public ComponentA unrelated; @Autowire public ComponentA unrelated;
} }
class TestInjector : ValueInjector!int class TestInjector : ValueInjector!int {
{ public override int get(string key) {
public override int get(string key)
{
assert(key == "values.int"); assert(key == "values.int");
return 8; return 8;
} }
} }
interface TestInterface interface TestInterface {
{
} }
class TestClass : TestInterface class TestClass : TestInterface {
{
} }
class TestClassDeux : TestInterface class TestClassDeux : TestInterface {
{
@Autowire public UnrelatedClass unrelated; @Autowire public UnrelatedClass unrelated;
} }
class UnrelatedClass class UnrelatedClass {
{
} }
class FailOnCreationClass class FailOnCreationClass {
{ this() {
this()
{
throw new Exception("This class should not be instantiated"); throw new Exception("This class should not be instantiated");
} }
} }
class AutowiredClass class AutowiredClass {
{
} }
class ComponentClass class ComponentClass {
{
@Autowire public AutowiredClass autowiredClass; @Autowire public AutowiredClass autowiredClass;
} }
class ComponentCat class ComponentCat {
{
@Autowire public ComponentMouse mouse; @Autowire public ComponentMouse mouse;
} }
class ComponentMouse class ComponentMouse {
{
@Autowire public ComponentCat cat; @Autowire public ComponentCat cat;
} }
class Eenie class Eenie {
{
@Autowire public Meenie meenie; @Autowire public Meenie meenie;
} }
class Meenie class Meenie {
{
@Autowire public Moe moe; @Autowire public Moe moe;
} }
class Moe class Moe {
{
@Autowire public Eenie eenie; @Autowire public Eenie eenie;
} }
class Ittie class Ittie {
{
@Autowire public Bittie bittie; @Autowire public Bittie bittie;
} }
class Bittie class Bittie {
{
@Autowire public Bunena banana; @Autowire public Bunena banana;
} }
class Bunena class Bunena {
{
@Autowire public Bittie bittie; @Autowire public Bittie bittie;
} }
interface SuperInterface interface SuperInterface {
{
} }
class SuperImplementation : SuperInterface class SuperImplementation : SuperInterface {
{
@Autowire public Bunena banana; @Autowire public Bunena banana;
} }
interface Color interface Color {
{
} }
class Blue : Color class Blue : Color {
{
} }
class Red : Color class Red : Color {
{
} }
class Spiders class Spiders {
{
@Autowire public TestInterface testMember; @Autowire public TestInterface testMember;
} }
class Recursive class Recursive {
{
@Autowire public Recursive recursive; @Autowire public Recursive recursive;
} }
class Moolah class Moolah {
{
} }
class Wants class Wants {
{
@Autowire public Moolah moolah; @Autowire public Moolah moolah;
} }
class John class John {
{
@Autowire public Wants wants; @Autowire public Wants wants;
} }
class Cocktail class Cocktail {
{
@Autowire public Moolah moolah; @Autowire public Moolah moolah;
public Red red; public Red red;
this(Red red) this(Red red) {
{
this.red = red; this.red = red;
} }
} }
class Wallpaper class Wallpaper {
{
public Color color; public Color color;
this(Color color) this(Color color) {
{
this.color = color; this.color = color;
} }
} }
class Pot class Pot {
{ this(Kettle kettle) {
this(Kettle kettle)
{
} }
} }
class Kettle class Kettle {
{ this(Pot pot) {
this(Pot pot)
{
} }
} }
class Rock class Rock {
{ this(Scissors scissors) {
this(Scissors scissors)
{
} }
} }
class Paper class Paper {
{ this(Rock rock) {
this(Rock rock)
{
} }
} }
class Scissors class Scissors {
{ this(Paper paper) {
this(Paper paper)
{
} }
} }
class Hello class Hello {
{ this(Ola ola) {
this(Ola ola)
{
} }
} }
class PostConstructionDependency class PostConstructionDependency {
{
public bool postConstructWasCalled = false; public bool postConstructWasCalled = false;
@PostConstruct public void callMeMaybe() @PostConstruct public void callMeMaybe() {
{
postConstructWasCalled = true; postConstructWasCalled = true;
} }
} }
class ChildOfPostConstruction : PostConstructionDependency class ChildOfPostConstruction : PostConstructionDependency {
{
} }
interface ThereWillBePostConstruction interface ThereWillBePostConstruction {
{
@PostConstruct void constructIt(); @PostConstruct void constructIt();
} }
class ButThereWontBe : ThereWillBePostConstruction class ButThereWontBe : ThereWillBePostConstruction {
{
public bool postConstructWasCalled = false; public bool postConstructWasCalled = false;
public override void constructIt() public override void constructIt() {
{
postConstructWasCalled = true; postConstructWasCalled = true;
} }
} }
class PostConstructWithAutowiring class PostConstructWithAutowiring {
{
@Autowire private PostConstructionDependency dependency; @Autowire private PostConstructionDependency dependency;
@Value("") @Value("")
private int theNumber = 1; private int theNumber = 1;
@PostConstruct public void doIt() @PostConstruct public void doIt() {
{
assert(theNumber == 8783); assert(theNumber == 8783);
assert(dependency !is null); assert(dependency !is null);
} }
} }
class PreDestroyerOfFates class PreDestroyerOfFates {
{
public bool preDestroyWasCalled = false; public bool preDestroyWasCalled = false;
@PreDestroy public void callMeMaybe() @PreDestroy public void callMeMaybe() {
{
preDestroyWasCalled = true; preDestroyWasCalled = true;
} }
} }
class PostConstructingIntInjector : ValueInjector!int class PostConstructingIntInjector : ValueInjector!int {
{ int get(string key) {
int get(string key)
{
return 8783; return 8783;
} }
} }
interface Fruit interface Fruit {
{
string getShape(); string getShape();
} }
interface Animal interface Animal {
{
string getYell(); string getYell();
} }
class Banana class Banana {
{
public string color; public string color;
this(string color) this(string color) {
{
this.color = color; this.color = color;
} }
} }
class Apple class Apple {
{
} }
class Pear : Fruit class Pear : Fruit {
{ public override string getShape() {
public override string getShape()
{
return "Pear shaped"; return "Pear shaped";
} }
} }
class Rabbit : Animal class Rabbit : Animal {
{ public override string getYell() {
public override string getYell()
{
return "Squeeeeeel"; return "Squeeeeeel";
} }
} }
class Wolf : Animal class Wolf : Animal {
{ public override string getYell() {
public override string getYell()
{
return "Wooooooooooo"; return "Wooooooooooo";
} }
} }
class PieChart class PieChart {
{
} }
class CakeChart : PieChart class CakeChart : PieChart {
{
} }
class ClassWrapper class ClassWrapper {
{
public Object someClass; public Object someClass;
this(Object someClass) this(Object someClass) {
{
this.someClass = someClass; this.someClass = someClass;
} }
} }
class ClassWrapperWrapper class ClassWrapperWrapper {
{
public ClassWrapper wrapper; public ClassWrapper wrapper;
this(ClassWrapper wrapper) this(ClassWrapper wrapper) {
{
this.wrapper = wrapper; this.wrapper = wrapper;
} }
} }
class SimpleContext : ApplicationContext class SimpleContext : ApplicationContext {
{ public override void registerDependencies(shared(DependencyContainer) container) {
public override void registerDependencies(shared(DependencyContainer) container)
{
container.register!CakeChart; container.register!CakeChart;
} }
@Component public Apple apple() @Component public Apple apple() {
{
return new Apple(); return new Apple();
} }
} }
class ComplexAutowiredTestContext : ApplicationContext class ComplexAutowiredTestContext : ApplicationContext {
{
@Autowire private Apple apple; @Autowire private Apple apple;
@Autowire protected ClassWrapper classWrapper; @Autowire protected ClassWrapper classWrapper;
public override void registerDependencies(shared(DependencyContainer) container) public override void registerDependencies(shared(DependencyContainer) container) {
{
container.register!Apple; container.register!Apple;
} }
@Component public ClassWrapper wrapper() @Component public ClassWrapper wrapper() {
{
return new ClassWrapper(apple); return new ClassWrapper(apple);
} }
@Component public ClassWrapperWrapper wrapperWrapper() @Component public ClassWrapperWrapper wrapperWrapper() {
{
return new ClassWrapperWrapper(classWrapper); return new ClassWrapperWrapper(classWrapper);
} }
} }
class AutowiredTestContext : ApplicationContext class AutowiredTestContext : ApplicationContext {
{
@Autowire private Apple apple; @Autowire private Apple apple;
@Component public ClassWrapper wrapper() @Component public ClassWrapper wrapper() {
{
return new ClassWrapper(apple); return new ClassWrapper(apple);
} }
} }
class TestContext : ApplicationContext class TestContext : ApplicationContext {
{
@Component public Banana banana() @Component public Banana banana() {
{
return new Banana("Yellow"); return new Banana("Yellow");
} }
public Apple apple() public Apple apple() {
{
return new Apple(); return new Apple();
} }
@Component @RegisterByType!Fruit public Pear pear() @Component @RegisterByType!Fruit public Pear pear() {
{
return new Pear(); return new Pear();
} }
@Component @RegisterByType!Animal public Rabbit rabbit() @Component @RegisterByType!Animal public Rabbit rabbit() {
{
return new Rabbit(); return new Rabbit();
} }
@Component @RegisterByType!Animal public Wolf wolf() @Component @RegisterByType!Animal public Wolf wolf() {
{
return new Wolf(); return new Wolf();
} }
@Component @Prototype public PieChart pieChart() @Component @Prototype public PieChart pieChart() {
{
return new PieChart(); return new PieChart();
} }
} }
class TestImplementation : TestInterface class TestImplementation : TestInterface {
{
public string someContent = ""; public string someContent = "";
} }
class SomeOtherClassThen class SomeOtherClassThen {
{
} }
class ClassWithConstructor class ClassWithConstructor {
{
public TestImplementation testImplementation; public TestImplementation testImplementation;
this(TestImplementation testImplementation) this(TestImplementation testImplementation) {
{
this.testImplementation = testImplementation; this.testImplementation = testImplementation;
} }
} }
class ClassWithMultipleConstructors class ClassWithMultipleConstructors {
{
public SomeOtherClassThen someOtherClassThen; public SomeOtherClassThen someOtherClassThen;
public TestImplementation testImplementation; public TestImplementation testImplementation;
this(SomeOtherClassThen someOtherClassThen) this(SomeOtherClassThen someOtherClassThen) {
{
this.someOtherClassThen = someOtherClassThen; this.someOtherClassThen = someOtherClassThen;
} }
this(SomeOtherClassThen someOtherClassThen, TestImplementation testImplementation) this(SomeOtherClassThen someOtherClassThen, TestImplementation testImplementation) {
{
this.someOtherClassThen = someOtherClassThen; this.someOtherClassThen = someOtherClassThen;
this.testImplementation = testImplementation; this.testImplementation = testImplementation;
} }
} }
class ClassWithConstructorWithMultipleParameters class ClassWithConstructorWithMultipleParameters {
{
public SomeOtherClassThen someOtherClassThen; public SomeOtherClassThen someOtherClassThen;
public TestImplementation testImplementation; public TestImplementation testImplementation;
this(SomeOtherClassThen someOtherClassThen, TestImplementation testImplementation) this(SomeOtherClassThen someOtherClassThen, TestImplementation testImplementation) {
{
this.someOtherClassThen = someOtherClassThen; this.someOtherClassThen = someOtherClassThen;
this.testImplementation = testImplementation; this.testImplementation = testImplementation;
} }
} }
class ClassWithPrimitiveConstructor class ClassWithPrimitiveConstructor {
{
public SomeOtherClassThen someOtherClassThen; public SomeOtherClassThen someOtherClassThen;
this(string willNotBePicked) this(string willNotBePicked) {
{
} }
this(SomeOtherClassThen someOtherClassThen) this(SomeOtherClassThen someOtherClassThen) {
{
this.someOtherClassThen = someOtherClassThen; this.someOtherClassThen = someOtherClassThen;
} }
} }
class ClassWithEmptyConstructor class ClassWithEmptyConstructor {
{
public SomeOtherClassThen someOtherClassThen; public SomeOtherClassThen someOtherClassThen;
this() this() {
{
} }
this(SomeOtherClassThen someOtherClassThen) this(SomeOtherClassThen someOtherClassThen) {
{
this.someOtherClassThen = someOtherClassThen; this.someOtherClassThen = someOtherClassThen;
} }
} }
class ClassWithNonInjectableConstructor class ClassWithNonInjectableConstructor {
{ this(string myName) {
this(string myName)
{
} }
} }
class ClassWithStructConstructor class ClassWithStructConstructor {
{
public SomeOtherClassThen someOtherClassThen; public SomeOtherClassThen someOtherClassThen;
this(Thing willNotBePicked) this(Thing willNotBePicked) {
{
} }
this(SomeOtherClassThen someOtherClassThen) this(SomeOtherClassThen someOtherClassThen) {
{
this.someOtherClassThen = someOtherClassThen; this.someOtherClassThen = someOtherClassThen;
} }
} }
class TestType class TestType {
{
} }
class Dependency class Dependency {
{
} }
struct Thing struct Thing {
{
int x; int x;
} }
class MyConfig class MyConfig {
{
@Value("conf.stuffs") @Value("conf.stuffs")
int stuffs; int stuffs;
@ -644,105 +511,83 @@ version (unittest)
Thing thing; Thing thing;
} }
class ConfigWithDefaults class ConfigWithDefaults {
{
@Value("conf.missing") @Value("conf.missing")
int noms = 9; int noms = 9;
} }
class ConfigWithMandatory class ConfigWithMandatory {
{
@MandatoryValue("conf.mustbethere") @MandatoryValue("conf.mustbethere")
int nums; int nums;
} }
class IntInjector : ValueInjector!int class IntInjector : ValueInjector!int {
{ public override int get(string key) {
public override int get(string key)
{
assert(key == "conf.stuffs"); assert(key == "conf.stuffs");
return 364; return 364;
} }
} }
class StringInjector : ValueInjector!string class StringInjector : ValueInjector!string {
{ public override string get(string key) {
public override string get(string key)
{
assert(key == "conf.name"); assert(key == "conf.name");
return "Le Chef"; return "Le Chef";
} }
} }
class ThingInjector : ValueInjector!Thing class ThingInjector : ValueInjector!Thing {
{ public override Thing get(string key) {
public override Thing get(string key)
{
assert(key == "conf.thing"); assert(key == "conf.thing");
return Thing(8899); return Thing(8899);
} }
} }
class DefaultIntInjector : ValueInjector!int class DefaultIntInjector : ValueInjector!int {
{ public override int get(string key) {
public override int get(string key)
{
throw new ValueNotAvailableException(key); throw new ValueNotAvailableException(key);
} }
} }
class MandatoryAvailableIntInjector : ValueInjector!int class MandatoryAvailableIntInjector : ValueInjector!int {
{ public override int get(string key) {
public override int get(string key)
{
return 7466; return 7466;
} }
} }
class MandatoryUnavailableIntInjector : ValueInjector!int class MandatoryUnavailableIntInjector : ValueInjector!int {
{ public override int get(string key) {
public override int get(string key)
{
throw new ValueNotAvailableException(key); throw new ValueNotAvailableException(key);
} }
} }
class DependencyInjectedIntInjector : ValueInjector!int class DependencyInjectedIntInjector : ValueInjector!int {
{
@Autowire public Dependency dependency; @Autowire public Dependency dependency;
public override int get(string key) public override int get(string key) {
{
return 2345; return 2345;
} }
} }
class CircularIntInjector : ValueInjector!int class CircularIntInjector : ValueInjector!int {
{
@Autowire public ValueInjector!int dependency; @Autowire public ValueInjector!int dependency;
private int count = 0; private int count = 0;
public override int get(string key) public override int get(string key) {
{
count += 1; count += 1;
if (count >= 3) if (count >= 3) {
{
return count; return count;
} }
return dependency.get(key); return dependency.get(key);
} }
} }
class ValueInjectedIntInjector : ValueInjector!int class ValueInjectedIntInjector : ValueInjector!int {
{
@Value("five") @Value("five")
public int count = 0; public int count = 0;
public override int get(string key) public override int get(string key) {
{ if (key == "five") {
if (key == "five")
{
return 5; return 5;
} }
@ -750,14 +595,11 @@ version (unittest)
} }
} }
class DependencyValueInjectedIntInjector : ValueInjector!int class DependencyValueInjectedIntInjector : ValueInjector!int {
{
@Autowire public ConfigWithDefaults config; @Autowire public ConfigWithDefaults config;
public override int get(string key) public override int get(string key) {
{ if (key == "conf.missing") {
if (key == "conf.missing")
{
return 8899; return 8899;
} }
@ -765,57 +607,46 @@ version (unittest)
} }
} }
class TemplatedComponent(T) class TemplatedComponent(T) {
{
@Autowire T instance; @Autowire T instance;
} }
class CircularTemplateComponentA : TemplatedComponent!CircularTemplateComponentB class CircularTemplateComponentA : TemplatedComponent!CircularTemplateComponentB {
{
} }
class CircularTemplateComponentB : TemplatedComponent!CircularTemplateComponentA class CircularTemplateComponentB : TemplatedComponent!CircularTemplateComponentA {
{
} }
class ClassWithTemplatedConstructorArg(T) class ClassWithTemplatedConstructorArg(T) {
{
public TemplatedComponent!T dependency; public TemplatedComponent!T dependency;
this(TemplatedComponent!T assignedDependency) this(TemplatedComponent!T assignedDependency) {
{
this.dependency = assignedDependency; this.dependency = assignedDependency;
} }
} }
class Grandma class Grandma {
{
} }
class Mommy : Grandma class Mommy : Grandma {
{
} }
class Kid : Mommy class Kid : Mommy {
{
} }
class AutowiredMethod class AutowiredMethod {
{
@Autowire @Autowire
public int lala() public int lala() {
{
return 42; return 42;
} }
@Autowire @Autowire
public int lala(int valla) public int lala(int valla) {
{
return valla; return valla;
} }
} }

View file

@ -5,6 +5,5 @@
* The full terms of the license can be found in the LICENSE file. * The full terms of the license can be found in the LICENSE file.
*/ */
void main() void main() {
{
} }

View file

@ -10,32 +10,26 @@ import poodinis.test.testclasses;
import std.exception; import std.exception;
version (unittest) version (unittest) {
{
struct LocalStruct struct LocalStruct {
{
bool wasInjected = false; bool wasInjected = false;
} }
class LocalStructInjector : ValueInjector!LocalStruct class LocalStructInjector : ValueInjector!LocalStruct {
{ public override LocalStruct get(string key) {
public override LocalStruct get(string key)
{
auto data = LocalStruct(true); auto data = LocalStruct(true);
return data; return data;
} }
} }
class LocalClassWithStruct class LocalClassWithStruct {
{
@Value("") @Value("")
public LocalStruct localStruct; public LocalStruct localStruct;
} }
// Test injection of values // Test injection of values
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!MyConfig; container.register!MyConfig;
container.register!(ValueInjector!int, IntInjector); container.register!(ValueInjector!int, IntInjector);
@ -49,8 +43,7 @@ version (unittest)
} }
// Test injection of values throws exception when injector is not there // Test injection of values throws exception when injector is not there
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!MyConfig; container.register!MyConfig;
assertThrown!ResolveException(container.resolve!MyConfig); assertThrown!ResolveException(container.resolve!MyConfig);
@ -59,8 +52,7 @@ version (unittest)
} }
// Test injection of values with defaults // Test injection of values with defaults
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ConfigWithDefaults; container.register!ConfigWithDefaults;
container.register!(ValueInjector!int, DefaultIntInjector); container.register!(ValueInjector!int, DefaultIntInjector);
@ -70,8 +62,7 @@ version (unittest)
} }
// Test mandatory injection of values which are available // Test mandatory injection of values which are available
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ConfigWithMandatory; container.register!ConfigWithMandatory;
container.register!(ValueInjector!int, MandatoryAvailableIntInjector); container.register!(ValueInjector!int, MandatoryAvailableIntInjector);
@ -81,8 +72,7 @@ version (unittest)
} }
// Test mandatory injection of values which are not available // Test mandatory injection of values which are not available
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ConfigWithMandatory; container.register!ConfigWithMandatory;
container.register!(ValueInjector!int, MandatoryUnavailableIntInjector); container.register!(ValueInjector!int, MandatoryUnavailableIntInjector);
@ -92,8 +82,7 @@ version (unittest)
} }
// Test injecting dependencies within value injectors // Test injecting dependencies within value injectors
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
auto dependency = new Dependency(); auto dependency = new Dependency();
container.register!Dependency.existingInstance(dependency); container.register!Dependency.existingInstance(dependency);
@ -104,8 +93,7 @@ version (unittest)
} }
// Test injecting circular dependencies within value injectors // Test injecting circular dependencies within value injectors
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(ValueInjector!int, CircularIntInjector); container.register!(ValueInjector!int, CircularIntInjector);
auto injector = cast(CircularIntInjector) container.resolve!(ValueInjector!int); auto injector = cast(CircularIntInjector) container.resolve!(ValueInjector!int);
@ -115,8 +103,7 @@ version (unittest)
} }
// Test value injection within value injectors // Test value injection within value injectors
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(ValueInjector!int, ValueInjectedIntInjector); container.register!(ValueInjector!int, ValueInjectedIntInjector);
auto injector = cast(ValueInjectedIntInjector) container.resolve!(ValueInjector!int); auto injector = cast(ValueInjectedIntInjector) container.resolve!(ValueInjector!int);
@ -125,21 +112,19 @@ version (unittest)
} }
// Test value injection within dependencies of value injectors // Test value injection within dependencies of value injectors
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!ConfigWithDefaults; container.register!ConfigWithDefaults;
container.register!(ValueInjector!int, DependencyValueInjectedIntInjector); container.register!(ValueInjector!int, DependencyValueInjectedIntInjector);
auto injector = cast(DependencyValueInjectedIntInjector) container.resolve!( auto injector = cast(DependencyValueInjectedIntInjector) container.resolve!(
ValueInjector!int); ValueInjector!int);
assert(injector.config.noms == 8899); assert(injector.config.noms == 8899);
} }
// Test resolving locally defined struct injector (github issue #20) // Test resolving locally defined struct injector (github issue #20)
unittest unittest {
{
auto container = new shared DependencyContainer(); auto container = new shared DependencyContainer();
container.register!(ValueInjector!LocalStruct, LocalStructInjector); container.register!(ValueInjector!LocalStruct, LocalStructInjector);
container.register!LocalClassWithStruct; container.register!LocalClassWithStruct;