# Quick start ## Main components DI ### Binding Binding is a custom instance configurator that contains methods for configuring a dependency. There are two main methods for initializing a custom instance `toInstance ()` and `toProvide ()` and auxiliary `withName ()` and `singleton ()`. `toInstance()` - takes a initialized instance `toProvide()` -  takes a `provider` function (instance constructor) `withName()` - takes a string to name the instance. By this name, it will be possible to extract instance from the DI container `singleton()` - sets a flag in the Binding that tells the DI container that there is only one dependency. Example: ``` --- ## Advanced: Customizing Code Generation Output You can configure where generated files will be placed by updating your `build.yaml` (supports `output_dir` and `build_extensions`): ```yaml targets: $default: builders: cherrypick_generator|inject_generator: options: output_dir: lib/generated cherrypick_generator|module_generator: options: output_dir: lib/generated ``` For full control and more examples, see the "Full Tutorial" or documentation on `build_extensions`. --- // initializing a text string instance through a method toInstance() Binding().toInstance("hello world"); // or // initializing a text string instance Binding().toProvide(() => "hello world"); // initializing an instance of a string named Binding().withName("my_string").toInstance("hello world"); // or Binding().withName("my_string").toProvide(() => "hello world"); // instance initialization like singleton Binding().toInstance("hello world"); // or Binding().toProvide(() => "hello world").singleton(); ``` ### Module Module is a container of user instances, and on the basis of which the user can create their modules. The user in his module must implement the `void builder (Scope currentScope)` method. Example: ```dart class AppModule extends Module { @override void builder(Scope currentScope) { bind().toInstance(ApiClientMock()); } } ``` ### Scope Scope is a container that stores the entire dependency tree (scope, modules, instances). Through the scope, you can access the custom `instance`, for this you need to call the `resolve()` method and specify the type of the object, and you can also pass additional parameters. Example: ```dart // open main scope final rootScope = Cherrypick.openRootScope(); // initializing scope with a custom module rootScope.installModules([AppModule()]); // takes custom instance final str = rootScope.resolve(); // or final str = rootScope.tryResolve(); // close main scope Cherrypick.closeRootScope(); ``` ## Example app ```dart import 'dart:async'; import 'package:meta/meta.dart'; import 'package:cherrypick/cherrypick.dart'; class AppModule extends Module { @override void builder(Scope currentScope) { bind().withName("apiClientMock").toInstance(ApiClientMock()); bind().withName("apiClientImpl").toInstance(ApiClientImpl()); } } class FeatureModule extends Module { bool isMock; FeatureModule({required this.isMock}); @override void builder(Scope currentScope) { bind() .withName("networkRepo") .toProvide( () => NetworkDataRepository( currentScope.resolve( named: isMock ? "apiClientMock" : "apiClientImpl", ), ), ) .singleton(); bind().toProvide( () => DataBloc( currentScope.resolve(named: "networkRepo"), ), ); } } void main() async { final scope = openRootScope().installModules([ AppModule(), ]); final subScope = scope .openSubScope("featureScope") .installModules([FeatureModule(isMock: true)]); final dataBloc = subScope.resolve(); dataBloc.data.listen((d) => print('Received data: $d'), onError: (e) => print('Error: $e'), onDone: () => print('DONE')); await dataBloc.fetchData(); } class DataBloc { final DataRepository _dataRepository; Stream get data => _dataController.stream; StreamController _dataController = new StreamController.broadcast(); DataBloc(this._dataRepository); Future fetchData() async { try { _dataController.sink.add(await _dataRepository.getData()); } catch (e) { _dataController.sink.addError(e); } } void dispose() { _dataController.close(); } } abstract class DataRepository { Future getData(); } class NetworkDataRepository implements DataRepository { final ApiClient _apiClient; final _token = 'token'; NetworkDataRepository(this._apiClient); @override Future getData() async => await _apiClient.sendRequest( url: 'www.google.com', token: _token, requestBody: {'type': 'data'}); } abstract class ApiClient { Future sendRequest({@required String url, String token, Map requestBody}); } class ApiClientMock implements ApiClient { @override Future sendRequest( {@required String? url, String? token, Map? requestBody}) async { return 'Local Data'; } } class ApiClientImpl implements ApiClient { @override Future sendRequest( {@required String? url, String? token, Map? requestBody}) async { return 'Network data'; } } ```