Skip to content

Commit

Permalink
Merge pull request #11 from Ivy-Apps/multi-bindings
Browse files Browse the repository at this point in the history
Scope affinity & API improvements
  • Loading branch information
ILIYANGERMANOV authored Dec 14, 2024
2 parents 359b132 + 19de957 commit 341b812
Show file tree
Hide file tree
Showing 11 changed files with 813 additions and 549 deletions.
48 changes: 48 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: CI

on:
push:
branches:
- main
pull_request:
workflow_call:

permissions:
contents: read

jobs:
build:
strategy:
matrix:
include:
- target: iosSimulatorArm64Test
os: macos-latest
- target: jvmTest
os: ubuntu-latest
- target: linuxX64Test
os: ubuntu-latest
- target: testDebugUnitTest
os: ubuntu-latest
- target: testReleaseUnitTest
os: ubuntu-latest
- target: jsTest
os: ubuntu-latest
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Validate Gradle Wrapper
uses: gradle/wrapper-validation-action@v3
- uses: actions/cache@v4
with:
path: |
~/.konan
key: ${{ runner.os }}-${{ hashFiles('**/.lock') }}
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Build with Gradle
uses: gradle/gradle-build-action@093dfe9d598ec5a42246855d09b49dc76803c005
with:
arguments: ${{ matrix.target }}
58 changes: 0 additions & 58 deletions .github/workflows/deploy.yml

This file was deleted.

56 changes: 0 additions & 56 deletions .github/workflows/gradle.yml

This file was deleted.

34 changes: 34 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Publish
on:
release:
types: [ released, prereleased ]

jobs:
publish:
name: Release build and publish
runs-on: macOS-latest
steps:
- uses: actions/checkout@v4
- name: Validate Gradle Wrapper

uses: gradle/wrapper-validation-action@v3
- uses: actions/cache@v4
with:
path: |
~/.konan
key: ${{ runner.os }}-${{ hashFiles('**/.lock') }}

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'

- name: Publish to Maven Central
run: ./gradlew publish --no-configuration-cache
env:
ORG_GRADLE_PROJECT_mavenCentralUsername: '${{ secrets.MAVEN_CENTRAL_USERNAME }}'
ORG_GRADLE_PROJECT_mavenCentralPassword: '${{ secrets.MAVEN_CENTRAL_PASSWORD }}'
ORG_GRADLE_PROJECT_signingInMemoryKeyId: '${{ secrets.SIGNING_KEY_ID }}'
ORG_GRADLE_PROJECT_signingInMemoryKey: '${{ secrets.SIGNING_KEY }}'
ORG_GRADLE_PROJECT_signingInMemoryKeyPassword: '${{ secrets.SIGNING_KEY_PASSWORD }}'
33 changes: 27 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,8 @@ object DataModule : Di.Module {

Di.init(
// Registers the following modules in the DI container
modules = setOf(
AppModule,
DataModule,
)
)
Di.get<LoginService>()
```
Expand All @@ -191,13 +189,13 @@ To re-use and encapsulate DI logic you can create `Di.Module`s that you can late

Ivy DI supports grouping your dependencies into scopes. This way you can manage their lifecycle
and free resources as soon as they are no longer needed. **AppScope** and **FeatureScope**
are built-in but you can easily define your own scopes using `Di.newScope("my-scope")`.
are built-in, but you can easily define your own scopes using `Di.newScope("my-scope")`.

```kotlin
data class UserInfo(val id: String, name: String)
data class UserInfo(val id: String, val name: String)

val UserScope = Di.newScope("user")
fun Di.userScope(block: Di.Scope.() -> Unit) = Di.scope(UserScope, block) // helper function (optional)
fun Di.userScope(block: Di.Scope.() -> Unit) = Di.inScope(UserScope, block) // helper function (optional)

suspend fun login() {
val userInfo = loginInternally() // UserInfo("1", "John")
Expand All @@ -221,10 +219,33 @@ suspend fun logout() {
}
```

### 2. Multibindings 🚧
Scopes are also extremely useful for defining multiple dependencies of the same type
and picking the most appropriate one based on the scope using **affinity**.

```kotlin
data class Screen(val name: String)
Di.appScope {
register<String> { "Hello from app!" }
autoWire(::Screen)
}
Di.featureScope {
register<String> { "Hello from feature!" }
autoWire(::Screen)
}

Di.get<String>(affinity = AppScope) // "Hello from app!"
Di.get<Screen>(affinity = AppScope) // Screen(name="Hello from app!")
Di.get<String>(affinity = FeatureScope) // "Hello from feature!"
Di.get<Screen>(affinity = FeatureScope) // Screen(name="Hello from feature!")
```

### 2. Multi-bindings 🚧

Currently not supported, investigating this use-case and whether we can support it nicely.

> [!WARNING]
> So far, we haven't found a nice and efficient solution.
### 3. Lazy initialization
By default, all instances in Ivy DI are lazily initialized only after `Di.get()` is called.
Expand Down
Loading

0 comments on commit 341b812

Please sign in to comment.