invert 0.1.0-dev.1
invert: ^0.1.0-dev.1 copied to clipboard
A simple dependency injection for dart, inspired by dagger for java.
A simple dependency injection for dart, inspired by dagger for java and implemented at compile time using the source_gen package, so that it works in every platform.
The advantages of this approach are are performance (no reflection needed) and full debuggability, as the generated sources are easy to read and well formatted.
The development priciple is to keep it simple, so only the basi features are implemented.
Install #
To use this package, add invert and build_runner as a dependency in your pubspec.yaml file.
Then, run pub run build_runner build to generate the part files.
Table of contents #
Declaring dependecies #
To make a class part of the dependecy tree annotate the class with the @Component() annotation. The library satisfies the dependency by creating a new instance and injecting to the default constructor the required dependencies.
Note that the injection will work only on default constructor with positional arguments.
import 'package:invert/annotations.dart';
@Component()
class Component {
final OtherDependency dep;
Component(OtherDependency this.dep);
}
Singleton dependecies #
Using the @Singleton() annotation has the same effect as @Component() except that the instance is only created the first time. Then the same instance is returned every time
Declaring modules #
Sometimes declaring dependencies is not convenient because
- Interfaces and abstract classes can't be constructed
- External library classes can't be instantiatiated
- You have to configure the class
To declare those classes you can declare a @Provides() method in @Module() annotated class.
The method’s return type defines which dependency it satisfies.
Note that the @Module() annotation extends @Singleton(), so the module class can have it's own dependencies satisfied, and that the methods can also be async.
import 'package:invert/annotations.dart';
@Module()
class MyModule {
@Provides
Service provideService() {
return Service(
name: 'injected',
);
}
@Provides
Future<Service> provideService() async {
return Service(
name: 'async',
);
}
}
Building the injector #
Now that we created a graph of linked dependencies we can create our entry points bt declaring an @Injector interface with the declared modules classes as annotation parameters and abstract methods.
The builder_runner will generate the implementation for those methods.
@Injector(modules: [MyModule])
abstract class AppInjector {
static AppInjector create() {
return AppInjectorImpl(); // generated by processor
}
Application app();
}
Then in the part of your program where you need your dependency:
void main(List<String> arguments) {
final injector = AppInjector.create();
final app = injector.app();
// do something with "app"
app.run();
}