Skip to content

Commit

Permalink
Fix scopes issues and refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
ILIYANGERMANOV committed Aug 23, 2024
1 parent 9fb4522 commit 4170241
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 18 deletions.
30 changes: 20 additions & 10 deletions di/src/commonMain/kotlin/DiContainer.kt
Original file line number Diff line number Diff line change
@@ -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<DependencyKey, Factory>()
val singletons = mutableSetOf<KClass<*>>()
val instances = mutableMapOf<DependencyKey, Any>()
val factories = mutableMapOf<DependencyKey, () -> Any>()

fun init(modules: Set<DiModule>) {
modules.forEach(DiModule::init)
Expand All @@ -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()
}

Expand Down Expand Up @@ -57,18 +61,20 @@ object Di {
}
}

inline fun factory(
fun factory(
classKey: KClass<*>
): Pair<Scope, () -> Any> = scopedFactory(FeatureScope, classKey)
?: scopedFactory(AppScope, classKey)
?: throw DependencyInjectionError("No factory found for class $classKey")
): Pair<Scope, Factory> = 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<Scope, () -> Any>? = factories[DependencyKey(scope, classKey)]?.let {
scope to it
}
): Pair<Scope, () -> Any>? = factories[DependencyKey(scope, classKey)]
?.let { factory ->
scope to factory
}

fun clearInstances(scope: Scope) {
instances.keys.forEach {
Expand All @@ -82,6 +88,10 @@ object Di {
instances.clear()
factories.clear()
singletons.clear()
scopes.apply {
clear()
addAll(DEFAULT_SCOPES)
}
}

data class DependencyKey(
Expand Down
31 changes: 23 additions & 8 deletions di/src/commonTest/kotlin/DiContainerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -99,34 +99,49 @@ class DiContainerTest {

@Test
fun `creates a singleton in feature scope`() {
// given
// Given
Di.featureScope {
singleton { FakeStateHolder() }
}
Di.get<FakeStateHolder>().number = 42

// when
// When
val stateHolder = Di.get<FakeStateHolder>()

// 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<FakeStateHolder>().number shouldBe 0
}

@Test
fun `di module registration works`() {
// given
// Given
Di.init(setOf(FakeModule))

// when
// When
val instance = Di.get<FakeModuleDep>()

// 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<FakeStateHolder>()

// Then
instance.shouldNotBeNull()
}
}
Expand Down

0 comments on commit 4170241

Please sign in to comment.