GithubHelp home page GithubHelp logo

wannabelikeyoda / dikt Goto Github PK

View Code? Open in Web Editor NEW

This project forked from sergeshustoff/dikt

0.0 0.0 0.0 475 KB

Simple and powerful DI for kotlin multiplatform

License: MIT License

Kotlin 99.49% HTML 0.16% Java 0.36%

dikt's Introduction

Maven Central gradle plugin IDEA plugin Kotlin version

DI.kt

Simple DI with compile-time dependency graph validation for kotlin multiplatform. It uses IR to create method's bodies with dependency injection.

Limitations: all annotations required for generating functions should be available in the same file as generated function. It can use methods and constructors from outside, but not annotations, because adding and removing annotations in other files would not trigger recompilation for generated function and combined with incremental compilation it would cause errors.

Why another DI?

DI.kt is smaller and simpler than some solutions, but it verifies dependency graph in compile time like a serious DI framework.

DI.kt does not generate files during compilation, which makes compilation faster (presumably, not tested).

Because of its simplicity it might be useful for minimalistic DI in libraries and feature-modules, but it can be used in big project too.

Other solutions:

Kotlin-inject - incredibly powerful DI framework with Dagger-like api;

Koin, Kodein-DI and PopKorn - service locators with great versatility, but without compile time error detection that we used to have in Dagger;

Dagger - most popular DI framework for Android, but it doesn't support multiplatform yet.

Sample

I forked kotlin multiplatform sample here and replaced di with DI.kt. It's clumsy, but it shows that library works on different platforms.

Articles

DI.kt, One of the First Kotlin Multiplatform DI Libraries

Installation

Gradle plugin:

In build.gradle file in module add plugin:

plugins {
    ...
    id 'io.github.sergeshustoff.dikt' version '1.0.0-alpha8'
}

IDEA plugin

Install idea plugin, it will remove errors from ide for methods with generated body.

Usage

Create module and declare provided dependencies. Use @Create, @Provide, @CreateSingle and @ProvideSingle to generate function's bodies. Use @UseModules and @UseConstructors to control how dependencies are provided and what classes can be created by primary constructors.

class SomethingModule(
    val externalDependency: Something,
) {
    @CreateSingle fun someSingleton(): SomeSingleton
    @Create fun provideSomethingElse(): SomethingElse
}

Under the hood primary constructor will be called for SomethingElse and SomeSingleton. If constructor requires some parameters - they will be retrieved form module's properties and functions.

Module

Any class or object that has a function marked with @Create, @Provide, @CreateSingle or @ProvideSingle is essentially a module. We don't need additional annotation for it, but if you need content of another 'module' provided as dependency in generated functions, you need to mark that type as module using annotation @UseModules on function, its containing class or file.

Singleton

There are no true singletons in DI.kt, but instead you can use @CreateSingle or @ProvideSingle annotations to generate functions backed by lazy properties. Such function will return the same instance each time they called as long as they called for the same instance of containing class. Effectively it gives each module a scope of their own and makes the scoping more understandable.

Annotations

@Create

Magical annotation that tells compiler plugin to generate method body using returned type's primary constructor. Values for constructor parameters will be retrieved from function parameters and from functions and properties of containing class.

Code generated by this annotation always uses returned type's primary constructor, even if dependency of returned type is available in parameters or in containing class.

Example:

class Something(val name: String)

@Create fun provideSomething(name: String): Something

Code above will be transformed into

fun provideSomething(name: String) = Something(name)

@Provide

Tells compiler plugin to generate method body that returns value of specified type retrieved from dependencies. For example from containing class properties or functions.

It's useful for elevating dependencies from nested modules. Doesn't call constructor for returned type unless it's listed in @UseConstructors.

Example:

class Something(val name: String)

class ExternalModule(
    val something: Something
)

@UseModules(ExternalModule::class)
class MyModule(val external: ExternalModule) {
    @Provide fun provideSomething(): Something
}

@CreateSingle and @ProvideSingle

Same as @Create and @Provide, but each annotation tells compiler to create a lazy property in containing class and return value from that property. Functions marked with @CreateSingle and @ProvideSingle don't support parameters.

@UseConstructors

Dependencies of types listed in this annotation parameters will be provided by constructor when required.

Might be applied to file, class, or @Create or @Provide function.

When constructor called for returned type of @Create function requires parameter of type listed in @UseConstructors it's constructor will be called instead of looking for provided dependency of that type.

Example:

class SomeDependency

class Something(val dependency: SomeDependency)

@UseConstructors(SomeDependency::class)
class MyModule {
    @Create fun provideSomething(): Something
}

@UseModules

Marks types that should provide all visible properties and functions as dependencies. Such dependencies can be used in @Create function as constructor parameters or in @Provide function as returned type.

Listed type should be available from DI function in order to provide type's properties and functions.

WARNING: This annotation doesn't work recursively. It means that function can only use modules listed in its own annotation or in its class annotation or in its file annotation.

Example:

class ExternalModule(val name: String)

class Something(val name: String)

@UseModules(ExternalModule::class)
class MyModule(
    private val external: ExternalModule
) {
    @Create fun provideSomething(): Something // will call constructor using external.name as parameter
}

dikt's People

Contributors

sergeshustoff avatar goregius avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.