From 41702410ee1d6936176caf0f2681852b81192738 Mon Sep 17 00:00:00 2001 From: iliyangermanov Date: Fri, 23 Aug 2024 18:45:46 +0300 Subject: [PATCH] Fix scopes issues and refactor --- di/src/commonMain/kotlin/DiContainer.kt | 30 +++++++++++++------- di/src/commonTest/kotlin/DiContainerTest.kt | 31 +++++++++++++++------ 2 files changed, 43 insertions(+), 18 deletions(-) diff --git a/di/src/commonMain/kotlin/DiContainer.kt b/di/src/commonMain/kotlin/DiContainer.kt index 6beb49c..32dd296 100644 --- a/di/src/commonMain/kotlin/DiContainer.kt +++ b/di/src/commonMain/kotlin/DiContainer.kt @@ -1,15 +1,18 @@ import kotlin.jvm.JvmInline import kotlin.reflect.KClass - val AppScope = Di.Scope("app") val FeatureScope = Di.Scope("feature") +typealias Factory = () -> Any + object Di { + private val DEFAULT_SCOPES = setOf(AppScope, FeatureScope) + private val scopes = DEFAULT_SCOPES.toMutableSet() + val factories = mutableMapOf() val singletons = mutableSetOf>() val instances = mutableMapOf() - val factories = mutableMapOf Any>() fun init(modules: Set) { modules.forEach(DiModule::init) @@ -20,6 +23,7 @@ object Di { fun featureScope(block: Scope.() -> Unit) = scope(FeatureScope, block) fun scope(scope: Scope, block: Scope.() -> Unit) { + scopes.add(scope) scope.block() } @@ -57,18 +61,20 @@ object Di { } } - inline fun factory( + fun factory( classKey: KClass<*> - ): Pair Any> = scopedFactory(FeatureScope, classKey) - ?: scopedFactory(AppScope, classKey) - ?: throw DependencyInjectionError("No factory found for class $classKey") + ): Pair = scopes + .firstNotNullOfOrNull { scope -> + scopedFactoryOrNull(scope, classKey) + } ?: throw DependencyInjectionError("No factory found for class $classKey") - inline fun scopedFactory( + private fun scopedFactoryOrNull( scope: Scope, classKey: KClass<*> - ): Pair Any>? = factories[DependencyKey(scope, classKey)]?.let { - scope to it - } + ): Pair Any>? = factories[DependencyKey(scope, classKey)] + ?.let { factory -> + scope to factory + } fun clearInstances(scope: Scope) { instances.keys.forEach { @@ -82,6 +88,10 @@ object Di { instances.clear() factories.clear() singletons.clear() + scopes.apply { + clear() + addAll(DEFAULT_SCOPES) + } } data class DependencyKey( diff --git a/di/src/commonTest/kotlin/DiContainerTest.kt b/di/src/commonTest/kotlin/DiContainerTest.kt index e63c5dd..ed20f8b 100644 --- a/di/src/commonTest/kotlin/DiContainerTest.kt +++ b/di/src/commonTest/kotlin/DiContainerTest.kt @@ -99,34 +99,49 @@ class DiContainerTest { @Test fun `creates a singleton in feature scope`() { - // given + // Given Di.featureScope { singleton { FakeStateHolder() } } Di.get().number = 42 - // when + // When val stateHolder = Di.get() - // then + // Then stateHolder.number shouldBe 42 - // when the scope is reset + // When the scope is reset Di.clearInstances(FeatureScope) - // then after the reset + // Then after the reset Di.get().number shouldBe 0 } @Test fun `di module registration works`() { - // given + // Given Di.init(setOf(FakeModule)) - // when + // When val instance = Di.get() - // then + // Then + instance.shouldNotBeNull() + } + + @Test + fun `creates a new scope and dependency in it`() { + // Given + val newScope = Di.Scope("new") + + // When + Di.scope(newScope) { + register { FakeStateHolder() } + } + val instance = Di.get() + + // Then instance.shouldNotBeNull() } }