From 62552920696f639d20e73d131352fc6506fbabff Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Sun, 26 Jun 2016 20:58:15 -0600 Subject: [PATCH 1/3] Use bit flags for options. A more idiomatic and efficient way of passing options. --- example/registeronresolve/app.d | 2 +- source/poodinis/autowire.d | 4 +- source/poodinis/container.d | 125 +++++++++++++++++++------------- test/poodinis/containertest.d | 14 ++-- 4 files changed, 83 insertions(+), 62 deletions(-) diff --git a/example/registeronresolve/app.d b/example/registeronresolve/app.d index 892d173..113080e 100644 --- a/example/registeronresolve/app.d +++ b/example/registeronresolve/app.d @@ -32,7 +32,7 @@ void main() { * By using the resolve option "registerBeforeResolving" you can register the resolved class * immediately. Note that any autowired member will not automatically be registered as well. */ - auto violinPlayer = dependencies.resolve!Violin([ResolveOption.registerBeforeResolving]); + auto violinPlayer = dependencies.resolve!Violin(ResolveOption.registerBeforeResolving); /* * You can make the resolve option persistent by setting it on the container with setPersistentResolveOptions(). diff --git a/source/poodinis/autowire.d b/source/poodinis/autowire.d index 971cc01..ef4a743 100644 --- a/source/poodinis/autowire.d +++ b/source/poodinis/autowire.d @@ -140,7 +140,7 @@ private void autowireMember(string member, size_t memberIndex, Type)(shared(Depe static if (isDynamicArray!MemberType) { alias MemberElementType = ElementType!MemberType; static if (isOptional) { - auto instances = container.resolveAll!MemberElementType([ResolveOption.noResolveException]); + auto instances = container.resolveAll!MemberElementType(ResolveOption.noResolveException); } else { auto instances = container.resolveAll!MemberElementType; } @@ -183,7 +183,7 @@ private QualifierType createOrResolveInstance(MemberType, QualifierType, bool cr return cast(MemberType) instanceFactory.getInstance(); } else { static if (isOptional) { - return container.resolve!(MemberType, QualifierType)([ResolveOption.noResolveException]); + return container.resolve!(MemberType, QualifierType)(ResolveOption.noResolveException); } else { return container.resolve!(MemberType, QualifierType); } diff --git a/source/poodinis/container.d b/source/poodinis/container.d index 784d87b..fdc66ae 100644 --- a/source/poodinis/container.d +++ b/source/poodinis/container.d @@ -47,36 +47,38 @@ class RegistrationException : Exception { * Options which influence the process of registering dependencies */ public enum RegistrationOption { + none = 0, /** * Prevent a concrete type being registered on itself. With this option you will always need * to use the supertype as the type of the dependency. */ - doNotAddConcreteTypeRegistration, + doNotAddConcreteTypeRegistration = 1, /** * Prevent a concrete type being registered on itself. With this option you will always need * to use the supertype as the type of the dependency. * @deprecated use doNotAddConcreteTypeRegistration instead */ - DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION + DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION = doNotAddConcreteTypeRegistration } /** * Options which influence the process of resolving dependencies */ public enum ResolveOption { + none = 0, /** * 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, + registerBeforeResolving = 1 << 0, /** * Does not throw a resolve exception when a type is not registered but will * return null instead. If the type is an array, an empty array is returned instead. */ - noResolveException + noResolveException = 1 << 1 } /** @@ -94,8 +96,8 @@ synchronized class DependencyContainer { private Registration[] autowireStack; - private RegistrationOption[] persistentRegistrationOptions; - private ResolveOption[] persistentResolveOptions; + private RegistrationOption persistentRegistrationOptions; + private ResolveOption persistentResolveOptions; /** * Register a dependency by concrete class type. @@ -117,15 +119,27 @@ synchronized class DependencyContainer { * * See_Also: singleInstance, newInstance, existingInstance */ - public Registration register(ConcreteType)(RegistrationOption[] options = []) { + public Registration register(ConcreteType)(RegistrationOption options = RegistrationOption.none) { return register!(ConcreteType, ConcreteType)(options); } /** - * Deprecated: Use register(SuperType, ConcreteType)(RegistrationOption[]) instead + * Deprecated: Use register(ConcreteType)(RegistrationOptions) instead. */ - public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption[] options...) { - return register!(SuperType, ConcreteType)(options); + deprecated public Registration register(ConcreteType)(RegistrationOption[] options) { + return register!(ConcreteType)(buildFlags(options)); + } + + /** + * Deprecated: Use register(SuperType, ConcreteType)(RegistrationOptions) instead + */ + deprecated public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption first, RegistrationOption[] options...) { + return register!(SuperType, ConcreteType)(first | buildFlags(options)); + } + + /// ditto + deprecated public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption[] options) { + return register!(SuperType, ConcreteType)(buildFlags(options)); } /** @@ -145,7 +159,7 @@ synchronized class DependencyContainer { * * See_Also: singleInstance, newInstance, existingInstance, RegistrationOption */ - public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption[] options = []) { + public Registration register(SuperType, ConcreteType : SuperType)(RegistrationOption options = RegistrationOption.none) { TypeInfo registeredType = typeid(SuperType); TypeInfo_Class concreteType = typeid(ConcreteType); @@ -172,34 +186,16 @@ synchronized class DependencyContainer { return newRegistration; } - private bool hasOption(OptionType)(OptionType[] options, shared(OptionType[]) persistentOptions, OptionType option) { - foreach (presentOption; persistentOptions) { - 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; - } - } + private bool hasOption(OptionType)(OptionType options, OptionType persistentOptions, OptionType option) { + return ((options | persistentOptions) & option) != 0; + } - if (presentOption == option) { - return true; - } + private OptionType buildFlags(OptionType)(OptionType[] options) { + OptionType flags; + foreach (option; options) { + flags |= option; } - - foreach(presentOption ; options) { - 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) { - return true; - } - } - - return false; + return flags; } private Registration getExistingRegistration(TypeInfo registrationType, TypeInfo qualifierType) { @@ -260,10 +256,24 @@ synchronized class DependencyContainer { * --- * You need to use the resolve method which allows you to specify a qualifier. */ - public RegistrationType resolve(RegistrationType)(ResolveOption[] resolveOptions = []) { + public RegistrationType resolve(RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) { return resolve!(RegistrationType, RegistrationType)(resolveOptions); } + /** + * Deprecated: Use register(RegistrationType)(ResolveOption) instead. + */ + deprecated public RegistrationType resolve(RegistrationType)(ResolveOption[] resolveOptions) { + return resolve!(RegistrationType)(buildFlags(resolveOptions)); + } + + /** + * Deprecated: Use register(RegistrationType, QualifierType)(ResolveOption) instead. + */ + deprecated public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)(ResolveOption[] resolveOptions) { + return resolve!(RegistrationType, QualifierType)(buildFlags(resolveOptions)); + } + /** * Resolve dependencies using a qualifier. * @@ -290,7 +300,7 @@ synchronized class DependencyContainer { * container.resolve!(Animal, Dog); * --- */ - public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)(ResolveOption[] resolveOptions = []) { + public QualifierType resolve(RegistrationType, QualifierType : RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) { TypeInfo resolveType = typeid(RegistrationType); TypeInfo qualifierType = typeid(QualifierType); @@ -348,7 +358,7 @@ synchronized class DependencyContainer { * Animal[] animals = container.resolveAll!Animal; * --- */ - public RegistrationType[] resolveAll(RegistrationType)(ResolveOption[] resolveOptions = []) { + public RegistrationType[] resolveAll(RegistrationType)(ResolveOption resolveOptions = ResolveOption.none) { RegistrationType[] instances; TypeInfo resolveType = typeid(RegistrationType); @@ -368,6 +378,13 @@ synchronized class DependencyContainer { return instances; } + /** + * Deprecated: Use resolveAll(RegistrationType)(ResolveOptions) instead. + */ + deprecated public RegistrationType[] resolveAll(RegistrationType)(ResolveOption[] resolveOptions) { + return resolveAll!RegistrationType(buildFlags(resolveOptions)); + } + private Registration getQualifiedRegistration(TypeInfo resolveType, TypeInfo qualifierType, Registration[] candidates) { if (resolveType == qualifierType) { if (candidates.length > 1) { @@ -431,35 +448,39 @@ synchronized class DependencyContainer { /** * Apply persistent registration options which will be used everytime register() is called. */ - public void setPersistentRegistrationOptions(OptionsTuple...)(OptionsTuple registrationOptions) { - unsetPersistentRegistrationOptions(); - foreach (option; registrationOptions) { - persistentRegistrationOptions ~= option; - } + public void setPersistentRegistrationOptions(RegistrationOption[] registrationOptions...) { + persistentRegistrationOptions = buildFlags(registrationOptions); + } + + /// ditto + public void setPersistentRegistrationOptions(RegistrationOption options) { + persistentRegistrationOptions = options; } /** * Unsets all applied registration options */ public void unsetPersistentRegistrationOptions() { - persistentRegistrationOptions = []; + persistentRegistrationOptions = RegistrationOption.none; } /** * Apply persistent resolve options which will be used everytime resolve() is called. */ - public void setPersistentResolveOptions(OptionsTuple...)(OptionsTuple resolveOptions) { - unsetPersistentResolveOptions(); - foreach (option; resolveOptions) { - persistentResolveOptions ~= option; - } + public void setPersistentResolveOptions(ResolveOption[] resolveOptions...) { + persistentResolveOptions = buildFlags(resolveOptions); + } + + /// ditto + public void setPersistentResolveOptions(ResolveOption options) { + persistentResolveOptions = options; } /** * Unsets all applied registration options */ public void unsetPersistentResolveOptions() { - persistentResolveOptions = []; + persistentResolveOptions = ResolveOption.none; } } diff --git a/test/poodinis/containertest.d b/test/poodinis/containertest.d index b2d9b0f..de12384 100644 --- a/test/poodinis/containertest.d +++ b/test/poodinis/containertest.d @@ -497,7 +497,7 @@ version(unittest) { // Test registering type with option doNotAddConcreteTypeRegistration unittest { shared(DependencyContainer) container = new DependencyContainer(); - container.register!(TestInterface, TestClass)([RegistrationOption.doNotAddConcreteTypeRegistration]); + container.register!(TestInterface, TestClass)(RegistrationOption.doNotAddConcreteTypeRegistration); auto firstInstance = container.resolve!TestInterface; assertThrown!ResolveException(container.resolve!TestClass); @@ -506,7 +506,7 @@ version(unittest) { // Test registering type with option DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION (DEPRECATED) unittest { shared(DependencyContainer) container = new DependencyContainer(); - container.register!(TestInterface, TestClass)([RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION]); + container.register!(TestInterface, TestClass)(RegistrationOption.DO_NOT_ADD_CONCRETE_TYPE_REGISTRATION); auto firstInstance = container.resolve!TestInterface; assertThrown!ResolveException(container.resolve!TestClass); @@ -515,7 +515,7 @@ version(unittest) { // Test registering conrete type with registration option doNotAddConcreteTypeRegistration does nothing unittest { shared(DependencyContainer) container = new DependencyContainer(); - container.register!TestClass([RegistrationOption.doNotAddConcreteTypeRegistration]); + container.register!TestClass(RegistrationOption.doNotAddConcreteTypeRegistration); container.resolve!TestClass; } @@ -631,7 +631,7 @@ version(unittest) { // Test registration when resolving unittest { shared(DependencyContainer) container = new DependencyContainer(); - container.resolve!(TestInterface, TestClass)([ResolveOption.registerBeforeResolving]); + container.resolve!(TestInterface, TestClass)(ResolveOption.registerBeforeResolving); container.resolve!TestClass; } @@ -653,20 +653,20 @@ version(unittest) { // Test ResolveOption registerBeforeResolving fails for interfaces unittest { shared(DependencyContainer) container = new DependencyContainer(); - assertThrown!ResolveException(container.resolve!TestInterface([ResolveOption.registerBeforeResolving])); + assertThrown!ResolveException(container.resolve!TestInterface(ResolveOption.registerBeforeResolving)); } // Test ResolveOption noResolveException does not throw unittest { shared(DependencyContainer) container = new DependencyContainer(); - auto instance = container.resolve!TestInterface([ResolveOption.noResolveException]); + auto instance = container.resolve!TestInterface(ResolveOption.noResolveException); assert(instance is null); } // ResolveOption noResolveException does not throw for resolveAll unittest { shared(DependencyContainer) container = new DependencyContainer(); - auto instances = container.resolveAll!TestInterface([ResolveOption.noResolveException]); + auto instances = container.resolveAll!TestInterface(ResolveOption.noResolveException); assert(instances.length == 0); } } From 4e27adc96b264851a8b7e29a1fadf5adb7eedf7e Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Sun, 26 Jun 2016 21:00:15 -0600 Subject: [PATCH 2/3] Transpose static if to avoid generating dead code. --- source/poodinis/container.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/poodinis/container.d b/source/poodinis/container.d index fdc66ae..acfbb07 100644 --- a/source/poodinis/container.d +++ b/source/poodinis/container.d @@ -175,8 +175,8 @@ synchronized class DependencyContainer { auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, this); newRegistration.singleInstance(); - if (!hasOption(options, persistentRegistrationOptions, RegistrationOption.doNotAddConcreteTypeRegistration)) { - static if (!is(SuperType == ConcreteType)) { + static if (!is(SuperType == ConcreteType)) { + if (!hasOption(options, persistentRegistrationOptions, RegistrationOption.doNotAddConcreteTypeRegistration)) { auto concreteTypeRegistration = register!ConcreteType; concreteTypeRegistration.linkTo(newRegistration); } From 243c02266e8f3a3b049a7558dbcdff567e6c301c Mon Sep 17 00:00:00 2001 From: Thayne McCombs Date: Sun, 26 Jun 2016 21:43:17 -0600 Subject: [PATCH 3/3] Add registerOnResolveExample to .gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 31a0a44..0f58cda 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ /arrayCompletionExample /annotationsExample /applicationContextExample +/registerOnResolveExample /.project /.idea -/*.iml \ No newline at end of file +/*.iml