From b511d5007c4da601270cc4e374649a186cdf4d62 Mon Sep 17 00:00:00 2001 From: Nick Cipollo Date: Wed, 16 Oct 2024 11:20:04 -0400 Subject: [PATCH] Update inject macro to support containers (#17) --- Sources/WhoopDIKit/Container/Container.swift | 2 +- Sources/WhoopDIKit/Injectable/Injectable.swift | 2 +- Sources/WhoopDIKitMacros/InjectableMacro.swift | 4 ++-- .../Container/ContainerTests.swift | 13 +++++++++---- .../Injectable/InjectableTests.swift | 16 ++++++++-------- Tests/WhoopDIKitTests/Module/TestModules.swift | 11 +++++++++-- Tests/WhoopDIKitTests/WhoopDITests.swift | 4 ++-- 7 files changed, 32 insertions(+), 20 deletions(-) diff --git a/Sources/WhoopDIKit/Container/Container.swift b/Sources/WhoopDIKit/Container/Container.swift index c10bc2c..3ad4955 100644 --- a/Sources/WhoopDIKit/Container/Container.swift +++ b/Sources/WhoopDIKit/Container/Container.swift @@ -87,7 +87,7 @@ public final class Container { if let value = try definition?.get(params: params) as? T { return value } else if let injectable = T.self as? any Injectable.Type { - return try injectable.inject() as! T + return try injectable.inject(container: self) as! T } else { throw DependencyError.missingDependecy(ServiceKey(T.self, name: name)) } diff --git a/Sources/WhoopDIKit/Injectable/Injectable.swift b/Sources/WhoopDIKit/Injectable/Injectable.swift index 7aba078..c6749be 100644 --- a/Sources/WhoopDIKit/Injectable/Injectable.swift +++ b/Sources/WhoopDIKit/Injectable/Injectable.swift @@ -3,5 +3,5 @@ import Foundation /// This protocol is used to create a detached injectable component without needing a dependency module. /// This is most likely used with the `@Injectable` macro, which will create the inject function and define it for you public protocol Injectable { - static func inject() throws -> Self + static func inject(container: Container) throws -> Self } diff --git a/Sources/WhoopDIKitMacros/InjectableMacro.swift b/Sources/WhoopDIKitMacros/InjectableMacro.swift index 1b2085c..104c36a 100644 --- a/Sources/WhoopDIKitMacros/InjectableMacro.swift +++ b/Sources/WhoopDIKitMacros/InjectableMacro.swift @@ -25,7 +25,7 @@ struct InjectableMacro: ExtensionMacro, MemberMacro { // Creates the whoopdi calls in the `inject` func let injectingVariables: String = allVariables.map { variable in - "\(variable.name): WhoopDI.inject(\(variable.injectedName.map { "\"\($0)\"" } ?? "nil"))" + "\(variable.name): container.inject(\(variable.injectedName.map { "\"\($0)\"" } ?? "nil"))" }.joined(separator: ", ") let accessLevel = self.accessLevel(declaration: declaration) ?? "internal" @@ -37,7 +37,7 @@ struct InjectableMacro: ExtensionMacro, MemberMacro { /// } """ - \(raw: accessLevel) static func inject() -> Self { + \(raw: accessLevel) static func inject(container: Container) -> Self { Self.init(\(raw: injectingVariables)) } """, diff --git a/Tests/WhoopDIKitTests/Container/ContainerTests.swift b/Tests/WhoopDIKitTests/Container/ContainerTests.swift index f2ec039..495d317 100644 --- a/Tests/WhoopDIKitTests/Container/ContainerTests.swift +++ b/Tests/WhoopDIKitTests/Container/ContainerTests.swift @@ -45,11 +45,16 @@ class ContainerTests: XCTestCase { } XCTAssertTrue(dependency is DependencyB) } + + func test_injectableWithDependency() throws { + container.registerModules(modules: [FakeTestModuleForInjecting()]) + let testInjecting: InjectableWithDependency = container.inject() + XCTAssertEqual(testInjecting, InjectableWithDependency(dependency: DependencyA())) + } - func test_injecting() throws { - throw XCTSkip("TODO: implement once WhoopDI uses a DI container") + func test_injectableWithNamedDependency() throws { container.registerModules(modules: [FakeTestModuleForInjecting()]) - let testInjecting: TestInjectingThing = container.inject() - XCTAssertEqual(testInjecting, TestInjectingThing(name: 1)) + let testInjecting: InjectableWithNamedDependency = container.inject() + XCTAssertEqual(testInjecting, InjectableWithNamedDependency(name: 1)) } } diff --git a/Tests/WhoopDIKitTests/Injectable/InjectableTests.swift b/Tests/WhoopDIKitTests/Injectable/InjectableTests.swift index a21676f..45f16b9 100644 --- a/Tests/WhoopDIKitTests/Injectable/InjectableTests.swift +++ b/Tests/WhoopDIKitTests/Injectable/InjectableTests.swift @@ -26,8 +26,8 @@ final class InjectableTests: XCTestCase { var newerThing: String { "not again" } let bestThing: Int - internal static func inject() -> Self { - Self.init(bestThing: WhoopDI.inject("Test")) + internal static func inject(container: Container) -> Self { + Self.init(bestThing: container.inject("Test")) } internal init(bestThing: Int) { @@ -64,8 +64,8 @@ final class InjectableTests: XCTestCase { lazy var lazyVar: Double = 100 let otherStringType: String.Type - public static func inject() -> Self { - Self.init(bestThing: WhoopDI.inject(nil), otherStringType: WhoopDI.inject(nil)) + public static func inject(container: Container) -> Self { + Self.init(bestThing: container.inject(nil), otherStringType: container.inject(nil)) } public init(bestThing: Int, otherStringType: String.Type) { @@ -95,8 +95,8 @@ final class InjectableTests: XCTestCase { var newerThing: String { "not again" } var bestThing: Int = 1 - private static func inject() -> Self { - Self.init(bestThing: WhoopDI.inject(nil)) + private static func inject(container: Container) -> Self { + Self.init(bestThing: container.inject(nil)) } private init(bestThing: Int = 1) { @@ -121,8 +121,8 @@ final class InjectableTests: XCTestCase { struct ClosureHolder { let closure: () -> String - internal static func inject() -> Self { - Self.init(closure: WhoopDI.inject(nil)) + internal static func inject(container: Container) -> Self { + Self.init(closure: container.inject(nil)) } internal init(closure: @escaping () -> String) { diff --git a/Tests/WhoopDIKitTests/Module/TestModules.swift b/Tests/WhoopDIKitTests/Module/TestModules.swift index 28596e5..2c812a8 100644 --- a/Tests/WhoopDIKitTests/Module/TestModules.swift +++ b/Tests/WhoopDIKitTests/Module/TestModules.swift @@ -49,7 +49,7 @@ class NilSingletonModule: DependencyModule { protocol Dependency { } -class DependencyA: Dependency { } +struct DependencyA: Dependency, Equatable { } class DependencyB: Dependency { private let param: String @@ -81,12 +81,19 @@ struct GenericDependency: Dependency { class FakeTestModuleForInjecting: DependencyModule { override func defineDependencies() { + factory { DependencyA() } factory(name: "FakeName", factory: { 1 }) } } @Injectable -struct TestInjectingThing: Equatable { +struct InjectableWithDependency: Equatable { + private let dependency: DependencyA +} + +@Injectable +struct InjectableWithNamedDependency: Equatable { @InjectableName(name: "FakeName") let name: Int } + diff --git a/Tests/WhoopDIKitTests/WhoopDITests.swift b/Tests/WhoopDIKitTests/WhoopDITests.swift index fadc871..c1c0622 100644 --- a/Tests/WhoopDIKitTests/WhoopDITests.swift +++ b/Tests/WhoopDIKitTests/WhoopDITests.swift @@ -112,7 +112,7 @@ class WhoopDITests: XCTestCase { func test_injecting() { WhoopDI.registerModules(modules: [FakeTestModuleForInjecting()]) - let testInjecting: TestInjectingThing = WhoopDI.inject() - XCTAssertEqual(testInjecting, TestInjectingThing(name: 1)) + let testInjecting: InjectableWithNamedDependency = WhoopDI.inject() + XCTAssertEqual(testInjecting, InjectableWithNamedDependency(name: 1)) } }