From 8f4a64cf4c8456acfa30d9a0b1ee26b36a900a6f Mon Sep 17 00:00:00 2001 From: Mike Bierlee Date: Thu, 29 Apr 2021 01:11:34 +0300 Subject: [PATCH] Move injection initializer to registration scope --- CHANGES.md | 3 ++ TUTORIAL.md | 12 ++++++-- example/injectioninitializer/app.d | 2 +- source/poodinis/container.d | 46 ------------------------------ source/poodinis/registration.d | 11 +++++++ test/poodinis/containertest.d | 11 +++++++ 6 files changed, 35 insertions(+), 50 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 719242a..338dd97 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,8 @@ Poodinis Changelog ================== +**Version 8.1.0-beta.3** +* CHANGE injection initializers to be defined as a registration scope instead of via Container.register(). See initializedBy(). + **Version 8.1.0-beta.2** * FIX inheritance type template in custom instance creator (PR #29) diff --git a/TUTORIAL.md b/TUTORIAL.md index 0ace491..a102c90 100644 --- a/TUTORIAL.md +++ b/TUTORIAL.md @@ -50,22 +50,28 @@ Dependency Creation Behaviour You can control how a dependency is resolved by specifying a creation scope during registration. The scope determines which instance is returned, be it the same each time or a new one. The following scopes are available: * Resolve a dependency using a single instance (default): - ```d dependencies.register!ExampleClass.singleInstance(); ``` -* Resolve a dependency with a new instance each time it is resolved: +* Resolve a dependency with a new instance each time it is resolved: ```d dependencies.register!ExampleClass.newInstance(); ``` -* Resolve a dependency using a pre-existing instance +* Resolve a dependency using a pre-existing instance: ```d auto preExistingInstance = new ExampleClass(); dependencies.register!ExampleClass.existingInstance(preExistingInstance); ``` +* Resolve a dependency using a custom initializer delegate: +```d +dependencies.register!ExampleClass.initializedBy({ + return new ExampleClass(); +}); +``` + Automatic Injection ---------- The real value of any dependency injection framework comes from its ability to automatically inject dependencies. Poodinis supports automatic injection either through autowiring members annotated with the `@Autowire` UDA or through constructor injection. diff --git a/example/injectioninitializer/app.d b/example/injectioninitializer/app.d index 1e2b3f5..90f7d3e 100644 --- a/example/injectioninitializer/app.d +++ b/example/injectioninitializer/app.d @@ -15,7 +15,7 @@ class Doohickey void main() { auto dependencies = new shared DependencyContainer(); - dependencies.register!Doohickey({ + dependencies.register!Doohickey.initializedBy({ writeln("Creating Doohickey via initializer delegate."); return new Doohickey(); }); diff --git a/source/poodinis/container.d b/source/poodinis/container.d index 6bafd77..4a78da4 100644 --- a/source/poodinis/container.d +++ b/source/poodinis/container.d @@ -30,8 +30,6 @@ debug { import std.stdio; } -alias InjectionInitializer(T) = T delegate(); - /** * Exception thrown when errors occur while resolving a type in a dependency container. */ @@ -149,11 +147,6 @@ synchronized class DependencyContainer { return register!(ConcreteType, ConcreteType)(options); } - Registration register(ConcreteType)(InjectionInitializer!ConcreteType initializer, - RegistrationOption options = RegistrationOption.none) { - return register!(ConcreteType, ConcreteType)(initializer, options); - } - /** * Register a dependency by super type. * @@ -201,45 +194,6 @@ synchronized class DependencyContainer { return newRegistration; } - /** - * TODO: Deduplicate code - */ - Registration register(SuperType, ConcreteType : SuperType)(InjectionInitializer!SuperType initializer, - RegistrationOption options = RegistrationOption.none) - if (is(ConcreteType == class)) { - - TypeInfo registeredType = typeid(SuperType); - TypeInfo_Class concreteType = typeid(ConcreteType); - - debug(poodinisVerbose) { - writeln(format("DEBUG: Register type %s (as %s)", concreteType.toString(), registeredType.toString())); - } - - auto existingRegistration = getExistingRegistration(registeredType, concreteType); - if (existingRegistration) { - return existingRegistration; - } - - InstanceFactory instanceFactory = new class InstanceFactory { - protected override Object createInstance() { - return cast(Object)initializer(); - } - }; - - auto newRegistration = new AutowiredRegistration!ConcreteType(registeredType, instanceFactory, this); - newRegistration.singleInstance(); - - static if (!is(SuperType == ConcreteType)) { - if (!hasOption(options, persistentRegistrationOptions, RegistrationOption.doNotAddConcreteTypeRegistration)) { - auto concreteTypeRegistration = register!ConcreteType; - concreteTypeRegistration.linkTo(newRegistration); - } - } - - registrations[registeredType] ~= cast(shared(Registration)) newRegistration; - return newRegistration; - } - private bool hasOption(OptionType)(OptionType options, OptionType persistentOptions, OptionType option) { return ((options | persistentOptions) & option) != 0; } diff --git a/source/poodinis/registration.d b/source/poodinis/registration.d index 73a5004..95d8004 100644 --- a/source/poodinis/registration.d +++ b/source/poodinis/registration.d @@ -105,6 +105,17 @@ public Registration existingInstance(Registration registration, Object instance) return registration; } +/** + * Scopes registrations to create instances using the given initializer delegate. + */ +public Registration initializedBy(T : Object)(Registration registration, T delegate() initializer) { + registration.instanceFactory.factoryParameters = InstanceFactoryParameters(registration.instanceType, CreatesSingleton.no, null, { + return cast(Object) initializer(); + }); + + return registration; +} + public string toConcreteTypeListString(Registration[] registrations) { auto concreteTypeListString = ""; foreach (registration ; registrations) { diff --git a/test/poodinis/containertest.d b/test/poodinis/containertest.d index 60ce741..a86062a 100644 --- a/test/poodinis/containertest.d +++ b/test/poodinis/containertest.d @@ -80,6 +80,17 @@ version(unittest) { assert(expectedInstance is actualInstance, "Resolved instance from existing instance scope is not the same as the registered instance"); } + // Test creating instance via customer initializer on resolve + unittest { + auto container = new shared DependencyContainer(); + auto expectedInstance = new TestClass(); + container.register!TestClass.initializedBy({ + return expectedInstance; + }); + auto actualInstance = container.resolve!TestClass; + assert(expectedInstance is actualInstance, "Resolved instance does not come from the custom initializer"); + } + // Test autowire resolved instances unittest { auto container = new shared DependencyContainer();