From 9e4bb9d6780b890a981021f8a26622b7f52a47d5 Mon Sep 17 00:00:00 2001 From: InsanusMokrassar Date: Wed, 22 Feb 2023 10:20:15 +0600 Subject: [PATCH] add readme to generator and add several fixes in processor --- CHANGELOG.md | 3 + koin/generator/README.md | 100 ++++++++++++++++++ koin/generator/src/main/kotlin/Processor.kt | 15 +++ .../kotlin/GeneratedDefinitionsTest.kt | 12 +++ .../annotations/GenerateKoinDefinition.kt | 14 +++ 5 files changed, 144 insertions(+) create mode 100644 koin/generator/README.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 19dc0e3b0e4..8795d05b210 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ * `Repos`: * `Exposed`: * `CommonExposedRepo.selectByIds` uses `foldRight` by default instead of raw foreach +* `Koin`: + * `Generator`: + * Module has been created ## 0.16.11 diff --git a/koin/generator/README.md b/koin/generator/README.md new file mode 100644 index 00000000000..b714bc31616 --- /dev/null +++ b/koin/generator/README.md @@ -0,0 +1,100 @@ +# Koin generator + +It is Kotlin Symbol Processing generator for `Koin` module in `MicroUtils`. + +1. [What may do this generator](#what-may-do-this-generator) +2. [How to add generator](#how-to-add-generator) + +## What may do this generator + +Let's imagine you want to have shortcuts in koin, to get something easily: + +```kotlin +val koin: Koin// some initialization + +val someUrl = koin.serverUrl +``` + +So, in that case you may mark containing file with next annotation (in the beginning of file): + +```kotlin +@file:GenerateKoinDefinition("serverUrl", String::class, nullable = false) +``` + +If file is called like `Sample.kt`, will be generated file `GeneratedDefinitionsSample.kt` with next content: + +```kotlin +public val Scope.serverUrl: String + get() = get(named("serverUrl")) + +public val Koin.serverUrl: String + get() = get(named("serverUrl")) + +public fun Module.serverUrlSingle(createdAtStart: Boolean = false, + definition: Definition): KoinDefinition = + single(named("serverUrl"), createdAtStart = createdAtStart, definition = definition) + +public fun Module.serverUrlFactory(definition: Definition): + KoinDefinition = factory(named("serverUrl"), definition = definition) +``` + +Besides, you may use the generics: + +```kotlin +@file:GenerateKoinDefinition("sampleInfo", Sample::class, G1::class, G2::class, nullable = false) +``` + +Will generate: + +```kotlin +public val Scope.sampleInfo: Sample + get() = get(named("sampleInfo")) + +public val Koin.sampleInfo: Sample + get() = get(named("sampleInfo")) + +public fun Module.sampleInfoSingle(createdAtStart: Boolean = false, + definition: Definition>): KoinDefinition> = + single(named("sampleInfo"), createdAtStart = createdAtStart, definition = definition) + +public fun Module.sampleInfoFactory(definition: Definition>): + KoinDefinition> = factory(named("sampleInfo"), definition = definition) +``` + +In case you wish not to generate single: + +```kotlin +@file:GenerateKoinDefinition("sampleInfo", Sample::class, G1::class, G2::class, nullable = false, generateSingle = false) +``` + +And you will take next code: + +```kotlin +public val Scope.sampleInfo: Sample + get() = get(named("sampleInfo")) + +public val Koin.sampleInfo: Sample + get() = get(named("sampleInfo")) + +public fun Module.sampleInfoFactory(definition: Definition>): + KoinDefinition> = factory(named("sampleInfo"), definition = definition) +``` + +## How to add generator + +**Note: $ksp_version in the samples above is equal to supported `ksp` version presented in `/gradle/libs.versions.toml` of project** + +**Note: $microutils_version in the version of MicroUtils library in your project** + +1. Add `classpath` in `build.gradle` (`classpath "com.google.devtools.ksp:symbol-processing-gradle-plugin:$ksp_version"`) +2. Add plugin to the plugins list of your module: `id "com.google.devtools.ksp"` +3. In `dependencies` block add to the required target/compile the dependency `dev.inmo:micro_utils.koin.generator:$microutils_version`: + ```groovy + dependencies { + add("kspCommonMainMetadata", "dev.inmo:micro_utils.koin.generator:$microutils_version") // will work in commonMain of your multiplatform module + add("kspJvm", "dev.inmo:micro_utils.koin.generator:$microutils_version") // will work in main of your JVM module + } + + ksp { // this generator do not require any arguments and we should left `ksp` empty + } + ``` diff --git a/koin/generator/src/main/kotlin/Processor.kt b/koin/generator/src/main/kotlin/Processor.kt index bfe6f0336b1..225db7794e0 100644 --- a/koin/generator/src/main/kotlin/Processor.kt +++ b/koin/generator/src/main/kotlin/Processor.kt @@ -80,6 +80,11 @@ class Processor( it.name, targetType, ).apply { + addKdoc( + """ + @return Definition by key "${it.name}" + """.trimIndent() + ) getter( FunSpec.getterBuilder().apply { addCode( @@ -102,6 +107,11 @@ class Processor( if (it.generateSingle) { addFunction( FunSpec.builder("${it.name}Single").apply { + addKdoc( + """ + Will register [definition] with [org.koin.core.module.Module.single] and key "${it.name}" + """.trimIndent() + ) receiver(Module::class) addParameter( ParameterSpec.builder( @@ -128,6 +138,11 @@ class Processor( if (it.generateFactory) { addFunction( FunSpec.builder("${it.name}Factory").apply { + addKdoc( + """ + Will register [definition] with [org.koin.core.module.Module.factory] and key "${it.name}" + """.trimIndent() + ) receiver(Module::class) addParameter( ParameterSpec.builder( diff --git a/koin/generator/test/src/commonMain/kotlin/GeneratedDefinitionsTest.kt b/koin/generator/test/src/commonMain/kotlin/GeneratedDefinitionsTest.kt index 52f94b499db..811fada75fa 100644 --- a/koin/generator/test/src/commonMain/kotlin/GeneratedDefinitionsTest.kt +++ b/koin/generator/test/src/commonMain/kotlin/GeneratedDefinitionsTest.kt @@ -12,15 +12,27 @@ import org.koin.core.module.Module import org.koin.core.qualifier.named import org.koin.core.scope.Scope +/** + * @return Definition by key "sampleInfo" + */ public val Scope.sampleInfo: Test get() = get(named("sampleInfo")) +/** + * @return Definition by key "sampleInfo" + */ public val Koin.sampleInfo: Test get() = get(named("sampleInfo")) +/** + * Will register [definition] with [org.koin.core.module.Module.single] and key "sampleInfo" + */ public fun Module.sampleInfoSingle(createdAtStart: Boolean = false, definition: Definition>): KoinDefinition> = single(named("sampleInfo"), createdAtStart = createdAtStart, definition = definition) +/** + * Will register [definition] with [org.koin.core.module.Module.factory] and key "sampleInfo" + */ public fun Module.sampleInfoFactory(definition: Definition>): KoinDefinition> = factory(named("sampleInfo"), definition = definition) diff --git a/koin/src/commonMain/kotlin/annotations/GenerateKoinDefinition.kt b/koin/src/commonMain/kotlin/annotations/GenerateKoinDefinition.kt index f4035f1d68b..4a4b25cc648 100644 --- a/koin/src/commonMain/kotlin/annotations/GenerateKoinDefinition.kt +++ b/koin/src/commonMain/kotlin/annotations/GenerateKoinDefinition.kt @@ -2,6 +2,20 @@ package dev.inmo.micro_utils.koin.annotations import kotlin.reflect.KClass +/** + * Use this annotation to mark files near to which generator should place generated extensions for koin [org.koin.core.scope.Scope] + * and [org.koin.core.Koin] + * + * @param name Name for definitions. This name will be available as extension for [org.koin.core.scope.Scope] and [org.koin.core.Koin] + * @param type Type of extensions. It is base star-typed class + * @param typeArgs Generic types for [type]. For example, if [type] == `Something::class` and [typeArgs] == `G1::class, + * G2::class`, the result type will be `Something` + * @param nullable In case when true, extension will not throw error when definition has not been registered in koin + * @param generateSingle Generate definition factory with [org.koin.core.module.Module.single]. You will be able to use + * the extension [org.koin.core.module.Module].[name]Single(createdAtStart/* default false */) { /* your definition */ } + * @param generateFactory Generate definition factory with [org.koin.core.module.Module.factory]. You will be able to use + * the extension [org.koin.core.module.Module].[name]Factory { /* your definition */ } + */ @Target(AnnotationTarget.FILE) @Repeatable annotation class GenerateKoinDefinition(