Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup #12

Merged
merged 5 commits into from
Dec 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -401,3 +401,13 @@ dependencies on the main thread.

The library will be maintained as long as Ivy Apps Ltd has an interest in using it.
Given that Ivy DI currently has no community, the project may be abandoned in the future.

> **Disclaimer**
>
> _Ivy DI is provided "as is" under the [Apache 2.0 License](LICENSE),
without warranties of any kind, including but not limited to
fitness for a particular purpose or security.
Use it at your own risk. The authors are not liable for
any issues, defects, security vulnerabilities,
or damages arising from its use.
Maintenance, updates, and support are not guaranteed._
78 changes: 41 additions & 37 deletions di/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,51 +1,55 @@
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl

plugins {
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidLibrary)
alias(libs.plugins.publish)
alias(libs.plugins.kotlinMultiplatform)
alias(libs.plugins.androidLibrary)
alias(libs.plugins.publish)
}

kotlin {
jvm()
androidTarget {
publishLibraryVariants("release")
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_1_8)
}
jvm()
androidTarget {
publishLibraryVariants("release")
@OptIn(ExperimentalKotlinGradlePluginApi::class)
compilerOptions {
jvmTarget.set(JvmTarget.JVM_1_8)
}
iosX64()
iosArm64()
iosSimulatorArm64()
linuxX64()
js(IR) {
browser()
nodejs()
}
@OptIn(ExperimentalWasmDsl::class) wasmJs()
}
iosX64()
iosArm64()
iosSimulatorArm64()
linuxX64()
js(IR) {
browser()
nodejs()
}
@OptIn(org.jetbrains.kotlin.gradle.ExperimentalWasmDsl::class)
wasmJs {
browser()
nodejs()
d8()
}

sourceSets {
val commonMain by getting {
dependencies {
//put your multiplatform dependencies here
}
}
val commonTest by getting {
dependencies {
implementation(libs.kotlin.test)
implementation(libs.bundles.test)
}
}
sourceSets {
val commonMain by getting {
dependencies {
//put your multiplatform dependencies here
}
}
val commonTest by getting {
dependencies {
implementation(libs.kotlin.test)
implementation(libs.bundles.test)
}
}
}
}

android {
namespace = "com.ivy_apps.di"
compileSdk = libs.versions.android.compileSdk.get().toInt()
defaultConfig {
minSdk = libs.versions.android.minSdk.get().toInt()
}
namespace = "com.ivy_apps.di"
compileSdk = libs.versions.android.compileSdk.get().toInt()
defaultConfig {
minSdk = libs.versions.android.minSdk.get().toInt()
}
}
49 changes: 46 additions & 3 deletions di/src/commonMain/kotlin/ivy/di/DiContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@ import kotlin.reflect.KClass

typealias Factory = () -> Any

/**
* Built-in [Di.Scope] for registering dependencies for the lifetime of the application.
* __Note:__ you need to manually manage the lifecycle by clearing when no longer needed
* via [Di.clear].
*/
val AppScope = Di.newScope("app")

/**
* Same like [AppScope] but for the lifetime of a feature.
*/
val FeatureScope = Di.newScope("feature")

object Di {
Expand All @@ -30,12 +39,14 @@ object Di {
}

/**
* Scope used to register dependencies for the entire lifetime of the application.
* Scope used to register dependencies in [AppScope],
* intended for the entire lifetime of the application.
*/
fun appScope(block: Scope.() -> Unit) = AppScope.block()

/**
* Scope used to register dependencies for a feature.
* Scope used to register dependencies in [FeatureScope]
* intended for the lifetime of the feature for a feature.
*/
fun featureScope(block: Scope.() -> Unit) = FeatureScope.block()

Expand All @@ -47,7 +58,8 @@ object Di {
fun newScope(name: String): Scope = Scope(name).also(scopes::add)

/**
* Utility function for registering dependencies in a specific scope.
* Utility function for registering dependencies in a specific [scope].
* @param scope the [Di.Scope] in which the dependencies will be registered
*/
fun inScope(scope: Scope, block: Scope.() -> Unit) = scope.block()

Expand Down Expand Up @@ -244,6 +256,37 @@ object Di {
* Di.get<String>(affinity = FeatureScope) // "world"
* Di.get<String>() // not deterministic
* ```
*
* An example for managing lifecycle using DI scopes:
*
* ```kotlin
* data class UserInfo(val id: String, val name: String)
*
* val UserScope = Di.newScope("user")
* fun Di.userScope(block: Di.Scope.() -> Unit) = Di.inScope(UserScope, block) // helper function (optional)
*
* suspend fun login() {
* val userInfo = loginInternally() // UserInfo("1", "John")
* Di.userScope {
* // Register dependencies for the lifecycle of a user
* singleton { userInfo }
* }
* }
*
* // Note: This function must be called only for logged-in users,
* // otherwise Di.get() will throw an exception.
* suspend fun dashboard() {
* // Use user related dependencies
* val userInfo = Di.get<UserInfo>()
* println("Hello, ${userInfo.name}") // "Hello, John"
* }
*
* suspend fun logout() {
* logoutInternally()
* // Frees all dependencies in UserScope
* Di.clear(UserScope) // UserInfo("1", "John") gets cleared
* }
* ```
*/
@JvmInline
value class Scope internal constructor(val value: String)
Expand Down
21 changes: 12 additions & 9 deletions di/src/commonMain/kotlin/ivy/di/autowire/Autowire.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,21 @@ import kotlin.jvm.JvmName
* Make sure to **import [R] before** calling `autoWire(::R)`,
* otherwise your IDE might not recognize the function.
*
* @param constructor A function reference to the constructor of the dependency like `::R`.
* [R] must be imported before calling this function.
*
* The affinity of the dependencies of [R] will be set to the receiver scope.
* ```
* class Repository(val a: A, val b: B, val c: C)
*class Repository(val a: A, val b: B)
*
* Di.appScope {
* autoWire(::Repository)
* // equivalent to:
* // register { Repository(Di.get(), Di.get(), Di.get()) }
* }
*Di.appScope {
* autoWire(::Repository)
* // equivalent to:
* // register { Repository(Di.get(affinity = AppScope), Di.get(affinity = AppScope)) }
*}
* ```
*
* @receiver the [Scope] in which to wire the [R] dependency.
* [R]'s dependencies will have affinity for the receiver [Scope].
* @param constructor A function reference to the constructor of the dependency like `::R`.
* [R] must be imported before calling this function.
*/
inline fun <reified R : Any> Scope.autoWire(
crossinline constructor: () -> R,
Expand Down
19 changes: 1 addition & 18 deletions di/src/commonMain/kotlin/ivy/di/autowire/AutowireSingleton.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,7 @@ import ivy.di.Di.singleton
import kotlin.jvm.JvmName

/**
* Automatically registers a singleton factory for a dependency [R] with the given constructor.
* [ivy.di.Di.get] will be called for each constructor parameter of [R].
*
* Make sure to **import [R] before** calling `autoWireSingleton(::R)`,
* otherwise your IDE might not recognize the function.
*
* @param constructor A function reference to the constructor of the dependency like `::R`.
* [R] must be imported before calling this function.
*
* ```
* class Repository(val a: A, val b: B, val c: C)
*
* Di.appScope {
* autoWireSingleton(::Repository)
* // equivalent to:
* // singleton { Repository(Di.get(), Di.get(), Di.get()) }
* }
* ```
* Same as [autoWire] but for [singleton]s.
*/
inline fun <reified R : Any> Scope.autoWireSingleton(
crossinline constructor: () -> R,
Expand Down
Loading