Skip to content

Commit

Permalink
feat(tegral-di-core): add qualifier support in factories
Browse files Browse the repository at this point in the history
  • Loading branch information
utybo committed Aug 24, 2023
1 parent 097a85c commit 84c5c5d
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 7 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

- **Experimental** Fundefs whose function is annotated with `@Fundef` can now be `put()` like any other component, e.g. `put(::myFundef)` ([#87](https://github.com/utybo/Tegral/pull/87))

- Factories now support qualifiers. Add the qualifier to the `putFactory` call and use it when requesting a factory like with a regular component.

## [0.0.4] - 2023-05-14

### Added
Expand Down
12 changes: 12 additions & 0 deletions docs/docs/modules/core/di/extensions/factories.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ class INeedBar(scope: InjectionScope) {
}
```

You can also add qualifiers to factories, similarly to regular components:

```kotlin
val myEnvironment = tegralDi {
putFactory(named("BAR!")) { Bar() }
}

class INeedBar(scope: InjectionScope) {
val bar: Bar by scope(named("BAR!"))
}
```

Here is a full example using loggers:

```kotlin
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import guru.zoroark.tegral.di.environment.Identifier
import guru.zoroark.tegral.di.environment.ensureInstance

/**
* A resolver that is aliased to another identifier. Not canonical.
* A resolver that is aliased to another resolver. Not canonical.
*/
class AliasIdentifierResolver<T : Any>(private val actualIdentifier: Identifier<out T>) : IdentifierResolver<T> {
override val requirements: List<Identifier<*>> = listOf(actualIdentifier)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,15 @@ import guru.zoroark.tegral.di.environment.EnvironmentComponents
import guru.zoroark.tegral.di.environment.Identifier

/**
* A resolver is an object that helps resolve an identifier into an actual component.
* A resolver is an object that resolves an identifier into an actual component.
*
* The implementation dictates how such a component is retrieved, created, etc.
* The implementation dictates how such a component is retrieved, created, etc. Resolvers have access to all components
* available in the environment, and can use any component they require to resolve the identifier. Resolvers are an
* intermediary step between the user (or some component) asking for a component, and the retrieval of that component in
* the environment.
*
* The most commonly used implementation of this is [SimpleIdentifierResolver], that simply retrieves the corresponding
* component in the environment. For an examples of a more advanced resolver, see [AliasIdentifierResolver]
*/
interface IdentifierResolver<T : Any> {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ import guru.zoroark.tegral.core.TegralDsl
import guru.zoroark.tegral.di.InvalidDeclarationException
import guru.zoroark.tegral.di.dsl.ContextBuilderDsl
import guru.zoroark.tegral.di.dsl.put
import guru.zoroark.tegral.di.environment.EmptyQualifier
import guru.zoroark.tegral.di.environment.EnvironmentComponents
import guru.zoroark.tegral.di.environment.Identifier
import guru.zoroark.tegral.di.environment.InjectionScope
import guru.zoroark.tegral.di.environment.Qualifier
import guru.zoroark.tegral.di.environment.ResolvableDeclaration
import guru.zoroark.tegral.di.environment.invoke
import guru.zoroark.tegral.di.environment.plus
import guru.zoroark.tegral.di.environment.resolvers.IdentifierResolver
import guru.zoroark.tegral.di.environment.typed
import kotlin.properties.ReadOnlyProperty
Expand Down Expand Up @@ -90,13 +93,13 @@ class FactoryDeclaration<T : Any>(
* services (also known as a singleton), factories
*/
@TegralDsl
inline fun <reified T : Any> ContextBuilderDsl.putFactory(noinline block: (Any) -> T) {
put<InjectableFactory<T>>(typed<T>()) { InjectableFactoryImpl(block) }
inline fun <reified T : Any> ContextBuilderDsl.putFactory(qualifier: Qualifier = EmptyQualifier, noinline block: (Any) -> T) {
put<InjectableFactory<T>>(typed<T>() + qualifier) { InjectableFactoryImpl(block) }
@Suppress("UNCHECKED_CAST")
put(
FactoryDeclaration(
Identifier(T::class),
Identifier(InjectableFactory::class as KClass<InjectableFactory<T>>, typed<T>())
Identifier(T::class, qualifier),
Identifier(InjectableFactory::class as KClass<InjectableFactory<T>>, typed<T>() + qualifier)
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import guru.zoroark.tegral.di.environment.InjectionScope
import guru.zoroark.tegral.di.environment.MixedImmutableEnvironment
import guru.zoroark.tegral.di.environment.get
import guru.zoroark.tegral.di.environment.invoke
import guru.zoroark.tegral.di.environment.named
import guru.zoroark.tegral.di.extensions.factory.factory
import guru.zoroark.tegral.di.extensions.factory.putFactory
import io.mockk.mockk
Expand Down Expand Up @@ -216,4 +217,22 @@ class FactoryExtensionTest {
}
assertEquals("I am AAA's A", env.get<DeprecatedUser>().a.identity)
}

class ABUser(scope: InjectionScope) {
val factoryA: A by scope()
val factoryB: A by scope(named("BBB"))
}

@Test
fun `Putting a factory with a qualifier`() {
val env = tegralDi {
putFactory { A("AAA") }
putFactory(named("BBB")) { A("BBB") }
put(::ABUser)
}
val abUser = env.get<ABUser>()
assertEquals("I am AAA's A", abUser.factoryA.identity)
assertEquals("I am BBB's A", abUser.factoryB.identity)

}
}

0 comments on commit 84c5c5d

Please sign in to comment.