Add ability to register a type while resolving it

Closes #5
This commit is contained in:
Mike Bierlee 2016-02-03 22:55:18 +01:00
parent 7775dd3c3a
commit 9ebbb5d917
4 changed files with 336 additions and 299 deletions

View file

@ -3,6 +3,8 @@ Poodinis Changelog
**Version NEXT**
* ADD setting persistent registration options
* DEPRECATE DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION, use doNotAddConcreteTypeRegistration instead
* ADD resolve options to container resolve()
* ADD ability to register a type while resolving it. Use resolve option registerBeforeResolving
**Version 6.0.0**
* CHANGE registration scopes are replaced by a single factory implementation. If you were not doing anything with the internal scope mechanism, you

View file

@ -40,6 +40,11 @@ dependencies.register!(ExampleInterface, ExampleClass)(RegistrationOptions.DO_NO
auto exampleClassInstance = dependencies.resolve!ExampleInterface;
auto exampleClassInstance2 = dependencies.resolve!ExampleClass; // A ResolveException is thrown
```
It is also possible to register a type while resolving it. Doing so means you don't need to explicitly register it beforehand. To do this, use the resolve option "registerBeforeResolving":
```d
dependencies.resolve!ExampleClass([ResolveOption.registerBeforeResolving]);
```
Naturally this can only be done when you are resolving a concrete type or an interface type by qualifier.
Dependency creation behaviour
-----------------

View file

@ -61,6 +61,18 @@ public enum RegistrationOption {
DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION
}
/**
* Options which influence the process of resolving dependencies
*/
public enum ResolveOption {
/**
* Registers the type you're trying to resolve before returning it.
* This essentially makes registration optional for resolving by concerete types.
* Resolinvg will still fail when trying to resolve a dependency by supertype.
*/
registerBeforeResolving
}
/**
* The dependency container maintains all dependencies registered with it.
*
@ -77,6 +89,7 @@ synchronized class DependencyContainer {
private Registration[] autowireStack;
private RegistrationOption[] persistentRegistrationOptions;
private ResolveOption[] persistentResolveOptions;
/**
* Register a dependency by concrete class type.
@ -155,9 +168,11 @@ synchronized class DependencyContainer {
private bool hasOption(OptionType)(OptionType[] options, shared(OptionType[]) persistentOptions, OptionType option) {
foreach (presentOption; persistentOptions) {
// DEPRECATED LEGACY COMPATIBILITY - REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE (SOON)
if (presentOption == RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION) {
presentOption = RegistrationOption.doNotAddConcreteTypeRegistration;
static if (is(OptionType == RegistrationOption)) {
// DEPRECATED LEGACY COMPATIBILITY - REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE (SOON)
if (presentOption == RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION) {
presentOption = RegistrationOption.doNotAddConcreteTypeRegistration;
}
}
if (presentOption == option) {
@ -166,9 +181,11 @@ synchronized class DependencyContainer {
}
foreach(presentOption ; options) {
// DEPRECATED LEGACY COMPATIBILITY - REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE (SOON)
if (presentOption == RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION) {
presentOption = RegistrationOption.doNotAddConcreteTypeRegistration;
static if (is(OptionType == RegistrationOption)) {
// DEPRECATED LEGACY COMPATIBILITY - REMOVE REMOVE REMOVE REMOVE REMOVE REMOVE (SOON)
if (presentOption == RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION) {
presentOption = RegistrationOption.doNotAddConcreteTypeRegistration;
}
}
if (presentOption == option) {
@ -237,8 +254,8 @@ synchronized class DependencyContainer {
* ---
* You need to use the resolve method which allows you to specify a qualifier.
*/
public RegistrationType resolve(RegistrationType)() {
return resolve!(RegistrationType, RegistrationType)();
public RegistrationType resolve(RegistrationType)(ResolveOption[] resolveOptions = []) {
return resolve!(RegistrationType, RegistrationType)(resolveOptions);
}
/**
@ -267,7 +284,7 @@ synchronized class DependencyContainer {
* container.resolve!(Animal, Dog);
* ---
*/
public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)() {
public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)(ResolveOption[] resolveOptions = []) {
TypeInfo resolveType = typeid(RegistrationType);
TypeInfo qualifierType = typeid(QualifierType);
@ -275,6 +292,12 @@ synchronized class DependencyContainer {
writeln("DEBUG: Resolving type " ~ resolveType.toString() ~ " with qualifier " ~ qualifierType.toString());
}
static if (__traits(compiles, new QualifierType())) {
if (hasOption(resolveOptions, persistentResolveOptions, ResolveOption.registerBeforeResolving)) {
register!(RegistrationType, QualifierType)();
}
}
auto candidates = resolveType in registrations;
if (!candidates) {
throw new ResolveException("Type not registered.", resolveType);

View file

@ -627,4 +627,11 @@ version(unittest) {
container.register!(TestInterface, TestClass);
container.resolve!TestClass;
}
// Test registration when resolving
unittest {
shared(DependencyContainer) container = new DependencyContainer();
container.resolve!(TestInterface, TestClass)([ResolveOption.registerBeforeResolving]);
container.resolve!TestClass;
}
}