### Example App Setup with Multiple Modules and Scopes Source: https://github.com/pese-git/cherrypick/wiki/Quick-Start-Eng Demonstrates setting up an application with multiple modules, named bindings, and sub-scopes for dependency injection. ```dart import 'dart:async'; import 'package:meta/meta.dart'; import 'package:cherrypick/scope.dart'; import 'package:cherrypick/module.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", ), ), ) .singeltone(); 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'; } } ``` -------------------------------- ### Complete CherryPick Example Application Source: https://github.com/pese-git/cherrypick/blob/master/cherrypick/README.md This example demonstrates module installation, subscope creation, and asynchronous dependency resolution with named client selection. It includes definitions for modules, data repositories, API clients (mock and implementation), and a main execution flow. ```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 { final bool isMock; FeatureModule({required this.isMock}); @override void builder(Scope currentScope) { // Async provider for DataRepository with named dependency selection bind() .withName("networkRepo") .toProvideAsync(() async { final client = await Future.delayed( Duration(milliseconds: 100), () => currentScope.resolve( named: isMock ? "apiClientMock" : "apiClientImpl", ), ); return NetworkDataRepository(client); }) .singleton(); // Chained async provider for DataBloc bind().toProvideAsync( () async { final repo = await currentScope.resolveAsync( named: "networkRepo"); return DataBloc(repo); }, ); } } void main() async { final scope = CherryPick.openRootScope().installModules([AppModule()]); final featureScope = scope.openSubScope("featureScope") ..installModules([FeatureModule(isMock: true)]); final dataBloc = await featureScope.resolveAsync(); 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; final StreamController _dataController = 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'; } } ``` -------------------------------- ### Extended Integration Example Source: https://github.com/pese-git/cherrypick/blob/master/talker_cherrypick_logger/README.md A complete example demonstrating the setup of Talker, the observer, and CherryPick, including optional Talker customization. All container events will be logged. ```dart import 'package:cherrypick/cherrypick.dart'; import 'package:talker/talker.dart'; import 'package:talker_cherrypick_logger/talker_cherrypick_logger.dart'; void main() { final talker = Talker(); final observer = TalkerCherryPickObserver(talker); // Optionally: customize Talker output or filtering // talker.settings.logLevel = TalkerLogLevel.debug; CherryPick.openRootScope(observer: observer); // ...setup your DI modules as usual // All container events will appear in Talker logs for easy debugging! } ``` -------------------------------- ### Start Local Development Server Source: https://github.com/pese-git/cherrypick/blob/master/website/README.md Starts a local development server for live preview. Changes are reflected without server restart. ```bash yarn start ``` -------------------------------- ### Install Dependencies Source: https://github.com/pese-git/cherrypick/blob/master/benchmark_di/README.md Run this command to install project dependencies. ```shell dart pub get ``` -------------------------------- ### Open Root Scope and Install Modules Source: https://context7.com/pese-git/cherrypick/llms.txt Opens the singleton root scope for the application and installs modules. Use this as the entry point for setting up CherryPick DI. All modules installed on the root scope are available globally. ```dart import 'package:cherrypick/cherrypick.dart'; // Define services abstract class ApiClient { Future fetch(String url); } class RestApiClient implements ApiClient { @override Future fetch(String url) async => 'response from $url'; } // Define a module class AppModule extends Module { @override void builder(Scope currentScope) { bind().toProvide(() => RestApiClient()).singleton(); bind().toInstance('https://api.example.com'); } } void main() async { final rootScope = CherryPick.openRootScope(); rootScope.installModules([AppModule()]); final apiClient = rootScope.resolve(); final baseUrl = rootScope.resolve(); print('Base URL: $baseUrl'); // Base URL: https://api.example.com final response = await apiClient.fetch(baseUrl); print(response); // response from https://api.example.com await CherryPick.closeRootScope(); // disposes all resources } ``` -------------------------------- ### Dart Dependency Injection Example Source: https://github.com/pese-git/cherrypick/blob/master/doc/quick_start_en.md This example shows how to define and install modules for dependency injection. It includes binding interfaces to implementations and resolving dependencies in sub-scopes. ```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'; } } ``` -------------------------------- ### Full Example Application with CherryPick Source: https://github.com/pese-git/cherrypick/blob/master/website/docs/example-application.md This Dart code demonstrates a complete application structure using CherryPick for dependency injection. It includes module setup, async providers, named dependency resolution, and scope management. ```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 { final bool isMock; FeatureModule({required this.isMock}); @override void builder(Scope currentScope) { // Async provider for DataRepository with named dependency selection bind() .withName("networkRepo") .toProvideAsync(() async { final client = await Future.delayed( Duration(milliseconds: 100), () => currentScope.resolve( named: isMock ? "apiClientMock" : "apiClientImpl", ), ); return NetworkDataRepository(client); }) .singleton(); // Chained async provider for DataBloc bind().toProvideAsync( () async { final repo = await currentScope.resolveAsync( named: "networkRepo"); return DataBloc(repo); }, ); } } void main() async { final scope = CherryPick.openRootScope().installModules([AppModule()]); final featureScope = scope.openSubScope("featureScope") ..installModules([FeatureModule(isMock: true)]); final dataBloc = await featureScope.resolveAsync(); 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; final StreamController _dataController = 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'; } } ``` -------------------------------- ### Open Root Scope and Install Modules Source: https://github.com/pese-git/cherrypick/wiki/Quick-Start-Eng Open the main scope using `openRootScope()` and install custom modules using `installModules()`. ```dart // open main scope final rootScope = Cherrypick.openRootScope(); // initializing scope with a custom module rootScope.installModules([AppModule()]); ``` -------------------------------- ### Run Universal Scenarios for Specific DI Source: https://github.com/pese-git/cherrypick/blob/master/benchmark_di/README.md Command-line examples to run all universal benchmark scenarios for cherrypick, getit, and riverpod DI implementations. ```shell dart run bin/main.dart --di=cherrypick --benchmark=all ``` ```shell dart run bin/main.dart --di=getit --benchmark=all ``` ```shell dart run bin/main.dart --di=riverpod --benchmark=all ``` -------------------------------- ### Install and Resolve Dependencies Source: https://github.com/pese-git/cherrypick/blob/master/README.md Open a root scope, install your generated modules, and then resolve dependencies. This demonstrates how to access instances like DataRepository and the parameterized greeting. ```dart final scope = CherryPick.openRootScope() ..installModules([$MyModule()]); final repo = scope.resolve(); final greeting = scope.resolve(params: 'John'); // 'Hello, John!' ``` -------------------------------- ### Pubspec Configuration for Cherrypick Example Source: https://github.com/pese-git/cherrypick/blob/master/cherrypick/example/README.md This is the pubspec.yaml file for the example project. It defines the project's name, version, SDK constraints, and dependencies, including the local path to the cherrypick package. ```yaml name: example version: 1.0.0 environment: sdk: ">=2.12.0 <3.0.0" dependencies: cherrypick: path: ../ dev_dependencies: test: ^1.16.8 ``` -------------------------------- ### Install Dependencies Source: https://github.com/pese-git/cherrypick/blob/master/website/README.md Installs project dependencies using Yarn. ```bash yarn ``` -------------------------------- ### Install CherryPick Dependency Source: https://github.com/pese-git/cherrypick/blob/master/cherrypick/README.md Add the CherryPick package to your pubspec.yaml file and run dart pub get to install it. ```yaml dependencies: cherrypick: ^ ``` ```shell dart pub get ``` -------------------------------- ### Register and Resolve Dependencies Source: https://github.com/pese-git/cherrypick/blob/master/website/docs/getting-started.md This example shows how to set up a module to bind dependencies and then resolve them from the root scope. Ensure you await the closing of the scope. ```dart import 'package:cherrypick/cherrypick.dart'; class AppModule extends Module { @override void builder(Scope currentScope) { bind().toInstance(ApiClientMock()); bind().toProvide(() => "Hello, CherryPick!"); } } final rootScope = CherryPick.openRootScope(); rootScope.installModules([AppModule()]); final greeting = rootScope.resolve(); print(greeting); // prints: Hello, CherryPick! await CherryPick.closeRootScope(); ``` -------------------------------- ### Universal DI Registration Example Source: https://github.com/pese-git/cherrypick/blob/master/benchmark_di/README.md Demonstrates how to set up dependencies using the universal registration method within a DI adapter, specifying scenario, chain count, nesting depth, and binding mode. ```dart final di = CherrypickDIAdapter(); // or GetItAdapter(), RiverpodAdapter(), etc di.setupDependencies( di.universalRegistration( scenario: UniversalScenario.chain, chainCount: 10, nestingDepth: 5, bindingMode: UniversalBindingMode.singletonStrategy, ), ); ``` -------------------------------- ### Register Modules with CherryPick Source: https://github.com/pese-git/cherrypick/blob/master/doc/annotations_en.md Initialize the DI container by opening a root scope and installing your defined modules. Ensure generated module files (e.g., `$AppModule()`) are imported. ```dart final scope = openRootScope() ..installModules([$AppModule()]); ``` -------------------------------- ### Dynamic Module Installation and Removal in CherryPick Source: https://context7.com/pese-git/cherrypick/llms.txt Use `installModules` to register `Module` instances and make bindings available. `dropModules` removes all installed modules and their bindings, useful for runtime configuration changes or testing. ```dart import 'package:cherrypick/cherrypick.dart'; class MockApiClient { String fetch() => 'mock response'; } class RealApiClient { String fetch() => 'real response'; } class MockModule extends Module { @override void builder(Scope s) { bind().toProvide(() => MockApiClient()); } } class RealModule extends Module { @override void builder(Scope s) { bind().toProvide(() => RealApiClient()); } } void main() async { final scope = CherryPick.openRootScope()..installModules([MockModule()]); final mock = scope.resolve(); print(mock.fetch()); // mock response // Swap modules at runtime scope.dropModules(); scope.installModules([RealModule()]); final real = scope.resolve(); print(real.fetch()); // real response await CherryPick.closeRootScope(); } ``` -------------------------------- ### Open and Configure Root Scope Source: https://github.com/pese-git/cherrypick/blob/master/doc/quick_start_en.md Initialize the main dependency injection scope using `openRootScope()`. Install custom modules into this scope to register your dependencies. ```dart final rootScope = Cherrypick.openRootScope(); rootScope.installModules([AppModule()]); ``` -------------------------------- ### Binding Examples in Dart Source: https://github.com/pese-git/cherrypick/blob/master/website/docs/core-concepts/binding.md Demonstrates various ways to bind dependencies, including direct instances, lazy providers, parameterized providers, named instances, and singleton lifecycles. ```dart void builder(Scope scope) { // Provide a direct instance bind().toInstance("Hello world"); // Provide an async direct instance bind().toInstanceAsync(Future.value("Hello world")); // Provide a lazy sync instance using a factory bind().toProvide(() => "Hello world"); // Provide a lazy async instance using a factory bind().toProvideAsync(() async => "Hello async world"); // Provide an instance with dynamic parameters (sync) bind().toProvideWithParams((params) => "Hello $params"); // Provide an instance with dynamic parameters (async) bind().toProvideAsyncWithParams((params) async => "Hello $params"); // Named instance for retrieval by name bind().toProvide(() => "Hello world").withName("my_string"); // Mark as singleton (only one instance within the scope) bind().toProvide(() => "Hello world").singleton(); } ``` -------------------------------- ### Basic Talker and CherryPick Integration Source: https://github.com/pese-git/cherrypick/blob/master/talker_cherrypick_logger/README.md Initialize a Talker instance and create a TalkerCherryPickObserver. Pass this observer to CherryPick when opening the root scope to start logging DI events. ```dart final talker = Talker(); final observer = TalkerCherryPickObserver(talker); // On DI setup, pass observer when opening (or re-opening) root or any custom scope CherryPick.openRootScope(observer: observer); ``` -------------------------------- ### Example of Scope Creation and Closing Source: https://github.com/pese-git/cherrypick/blob/master/doc/full_tutorial_en.md Illustrates opening a multi-level scope hierarchy and then closing a parent scope, which also removes its children. ```dart // Opens scopes by hierarchy: app -> module -> page final scope = CherryPick.openScope(scopeName: 'app.module.page'); // Closes 'module' and all nested subscopes CherryPick.closeScope(scopeName: 'app.module'); ``` -------------------------------- ### DI Module with Annotations Source: https://github.com/pese-git/cherrypick/blob/master/doc/full_tutorial_en.md Define DI modules using annotations for cleaner setup. Methods annotated with @provide become DI factories, and @singleton ensures a single instance. ```dart import 'package:cherrypick_annotations/cherrypick_annotations.dart'; @module() abstract class AppModule extends Module { @singleton() @provide() ApiClient apiClient() => ApiClient(); @provide() UserService userService(ApiClient api) => UserService(api); @singleton() @provide() @named('mock') ApiClient mockApiClient() => ApiClientMock(); } ``` -------------------------------- ### Registering Modules and Using Auto-Injection Source: https://github.com/pese-git/cherrypick/blob/master/website/docs/using-annotations.md Open a root scope, install your generated modules, and then instantiate your annotated classes. Call `injectFields()` on your instances to automatically inject all marked dependencies. ```dart final scope = CherryPick.openRootScope() ..installModules([$AppModule()]); final profile = ProfilePage(); profile.injectFields(); // injects all @inject fields ``` -------------------------------- ### Opening and Using Hierarchical Subscopes Source: https://github.com/pese-git/cherrypick/blob/master/website/docs/advanced-features/hierarchical-subscopes.md Demonstrates opening a root scope, installing modules, opening a feature-specific subscope, resolving dependencies within it, and nesting further subscopes. Dependencies in subscopes override parent scopes. ```dart final rootScope = CherryPick.openRootScope(); rootScope.installModules([AppModule()]); // Open a hierarchical subscope for a feature or page final userFeatureScope = rootScope.openSubScope('userFeature'); userFeatureScope.installModules([UserFeatureModule()]); // Dependencies defined in UserFeatureModule will take precedence final userService = userFeatureScope.resolve(); // If not found in the subscope, lookup continues in the parent (rootScope) final sharedService = userFeatureScope.resolve(); // You can nest subscopes final dialogScope = userFeatureScope.openSubScope('dialog'); dialogScope.installModules([DialogModule()]); final dialogManager = dialogScope.resolve(); ``` -------------------------------- ### Implement Custom CherryPickObserver Source: https://context7.com/pese-git/cherrypick/llms.txt Implement the CherryPickObserver interface to create a custom observer for logging DI events. This example shows how to collect events in a list and print specific lifecycle events. ```dart import 'package:cherrypick/cherrypick.dart'; class AppMetricsObserver implements CherryPickObserver { final List events = []; @override void onBindingRegistered(String name, Type type, {String? scopeName}) { events.add('registered: $name'); } @override void onInstanceCreated(String name, Type type, Object instance, {String? scopeName}) { events.add('created: $name'); print('[DI] Created $name in scope: $scopeName'); } @override void onScopeOpened(String name) => print('[DI] Scope opened: $name'); @override void onScopeClosed(String name) => print('[DI] Scope closed: $name'); @override void onCycleDetected(List chain, {String? scopeName}) => print('[DI] CYCLE: ${chain.join(' -> ')}'); @override void onError(String message, Object? error, StackTrace? stackTrace) => print('[DI] ERROR: $message'); @override void onInstanceRequested(String name, Type type, {String? scopeName}) {} @override void onInstanceDisposed(String name, Type type, Object instance, {String? scopeName}) {} @override void onModulesInstalled(List moduleNames, {String? scopeName}) {} @override void onModulesRemoved(List moduleNames, {String? scopeName}) {} @override void onCacheHit(String name, Type type, {String? scopeName}) {} @override void onCacheMiss(String name, Type type, {String? scopeName}) {} @override void onDiagnostic(String message, {Object? details}) {} @override void onWarning(String message, {Object? details}) {} } class MyService {} class ServiceModule extends Module { @override void builder(Scope s) { bind().toProvide(() => MyService()).singleton(); } } void main() async { final observer = AppMetricsObserver(); CherryPick.setGlobalObserver(observer); // or: PrintCherryPickObserver() CherryPick.openRootScope().installModules([ServiceModule()]); CherryPick.openRootScope().resolve(); // [DI] Scope opened: scope_... // [DI] Created MyService in scope: scope_... print(observer.events); // [registered: Binding, created: MyService] await CherryPick.closeRootScope(); } ``` -------------------------------- ### Define a DI Module with Annotations Source: https://github.com/pese-git/cherrypick/blob/master/README.md Create a DI module using annotations for defining singletons, providers, and parameterized instances. This example shows ApiClient, DataRepository, and a parameterized greeting. ```dart import 'package:cherrypick_annotations/cherrypick_annotations.dart'; import 'package:cherrypick/cherrypick.dart'; @module() abstract class MyModule extends Module { @singleton() ApiClient apiClient() => ApiClient(); @provide() DataRepository dataRepo(ApiClient client) => DataRepository(client); @provide() String greeting(@params() String name) => 'Hello, $name!'; } ``` -------------------------------- ### Example Circular Dependencies Between Scopes Source: https://github.com/pese-git/cherrypick/blob/master/doc/cycle_detection.en.md Demonstrates a circular dependency where services in different scopes depend on each other. ```dart // In parent scope class ParentService { final ChildService childService; ParentService(this.childService); // Gets from child scope } // In child scope class ChildService { final ParentService parentService; ChildService(this.parentService); // Gets from parent scope } ``` -------------------------------- ### Import cherrypick_flutter Package Source: https://github.com/pese-git/cherrypick/blob/master/cherrypick_flutter/README.md Import the cherrypick_flutter package into your Dart files to start using its functionalities. ```dart import 'package:cherrypick_flutter/cherrypick_flutter.dart'; ``` -------------------------------- ### Global Cycle Detection Settings Source: https://github.com/pese-git/cherrypick/blob/master/doc/cycle_detection.en.md Provides API examples for globally enabling, disabling, and checking the status of local and global cycle detection. ```dart // Enable/disable local detection globally CherryPick.enableGlobalCycleDetection(); CherryPick.disableGlobalCycleDetection(); // Enable/disable global cross-scope detection CherryPick.enableGlobalCrossScopeCycleDetection(); CherryPick.disableGlobalCrossScopeCycleDetection(); // Check current settings bool localEnabled = CherryPick.isGlobalCycleDetectionEnabled; bool globalEnabled = CherryPick.isGlobalCrossScopeCycleDetectionEnabled; ``` -------------------------------- ### Example Circular Dependencies within a Scope Source: https://github.com/pese-git/cherrypick/blob/master/doc/cycle_detection.en.md Illustrates a direct circular dependency between two services within the same scope. ```dart class UserService { final OrderService orderService; UserService(this.orderService); } class OrderService { final UserService userService; OrderService(this.userService); } ``` -------------------------------- ### Example Usage of CherryPickProvider in MyApp Source: https://github.com/pese-git/cherrypick/blob/master/cherrypick_flutter/README.md Illustrates how CherryPickProvider can be used in the main application widget to access the root scope and resolve dependencies for routing. ```dart class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { final rootScope = CherryPickProvider.of(context).openRootScope(); return MaterialApp.router( routerDelegate: rootScope.resolve().delegate(), routeInformationParser: rootScope.resolve().defaultRouteParser(), ); } } ``` -------------------------------- ### Main Dart Application with Cherrypick Modules Source: https://github.com/pese-git/cherrypick/blob/master/cherrypick/example/README.md This Dart code sets up the main application using cherrypick for dependency injection. It defines modules for application-wide bindings and feature-specific bindings, demonstrating how to open scopes, install modules, and resolve dependencies. ```dart import 'dart:async'; import 'package:meta/meta.dart'; import 'package:cherrypick/scope.dart'; import 'package:cherrypick/module.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'; } } ``` -------------------------------- ### Scope.installModules / Scope.dropModules Source: https://context7.com/pese-git/cherrypick/llms.txt `installModules` registers one or more `Module` instances into a scope, immediately making their bindings available. `dropModules` removes all installed modules and clears bindings. Useful for hot-swapping configurations or resetting in tests. ```APIDOC ## Scope.installModules / Scope.dropModules `installModules` registers one or more `Module` instances into a scope, immediately making their bindings available. `dropModules` removes all installed modules and clears bindings (does not call `dispose` on tracked disposables). Useful for hot-swapping configurations or resetting in tests. ### Method Signature - `void installModules(List modules)` - `void dropModules()` ### Parameters - `modules` (List): A list of Module instances to install. ### Example ```dart scope.installModules([MockModule()]); scope.dropModules(); scope.installModules([RealModule()]); ``` ``` -------------------------------- ### Minimal Synchronous Disposable Example Source: https://github.com/pese-git/cherrypick/blob/master/website/docs/core-concepts/disposable.md Implement the `Disposable` interface for synchronous cleanup. CherryPick will automatically call `dispose()` when the scope is closed. Ensure your class implements `Disposable` and register it as a singleton. ```dart class CacheManager implements Disposable { void dispose() { cache.clear(); print('CacheManager disposed!'); } } final scope = CherryPick.openRootScope(); scope.installModules([ Module((bind) => bind().toProvide(() => CacheManager()).singleton()), ]); // ...later await CherryPick.closeRootScope(); // prints: CacheManager disposed! ``` -------------------------------- ### Asynchronous Disposable Example Source: https://github.com/pese-git/cherrypick/blob/master/website/docs/core-concepts/disposable.md Implement the `Disposable` interface for asynchronous cleanup using `Future`. CherryPick will await the completion of the `dispose()` method before proceeding with scope closure. Register your service as a singleton. ```dart class MyServiceWithSocket implements Disposable { @override Future dispose() async { await socket.close(); print('Socket closed!'); } } scope.installModules([ Module((bind) => bind().toProvide(() => MyServiceWithSocket()).singleton()), ]); await CherryPick.closeRootScope(); // awaits async disposal ``` -------------------------------- ### Managing the Root Scope in Dart Source: https://github.com/pese-git/cherrypick/blob/master/website/docs/core-concepts/scope.md Open the main/root scope, install modules, resolve dependencies synchronously and asynchronously, and finally close the scope to release resources. Alternatively, manually dispose of individual scopes. ```dart // Open the main/root scope final rootScope = CherryPick.openRootScope(); // Install a custom module rootScope.installModules([AppModule()]); // Resolve a dependency synchronously final str = rootScope.resolve(); // Resolve a dependency asynchronously final result = await rootScope.resolveAsync(); // Recommended: Close the root scope and release all resources await CherryPick.closeRootScope(); // Alternatively, you may manually call dispose on any scope you manage individually // await rootScope.dispose(); ``` -------------------------------- ### Show CLI Help Source: https://github.com/pese-git/cherrypick/blob/master/benchmark_di/README.md Display all available command-line interface options for the benchmark suite. ```shell dart run bin/main.dart --help ``` -------------------------------- ### Run All Benchmarks (Default) Source: https://github.com/pese-git/cherrypick/blob/master/benchmark_di/README.md Execute all benchmark scenarios with default settings (2 warmup, 2 repeats) and output in Markdown format. ```shell dart run bin/main.dart --benchmark=all --format=markdown ``` -------------------------------- ### Async Dependency Resolution with CherryPick Source: https://context7.com/pese-git/cherrypick/llms.txt Use `resolveAsync` to get an instance of an asynchronously provided dependency, or `tryResolveAsync` to get `null` if not found. Ensure the scope is closed afterwards. ```dart import 'package:cherrypick/cherrypick.dart'; class RemoteConfig { final Map settings; RemoteConfig(this.settings); } class ConfigModule extends Module { @override void builder(Scope currentScope) { bind().toProvide(() async { // Simulate async fetch await Future.delayed(Duration(milliseconds: 100)); return RemoteConfig({'theme': 'dark', 'version': '3.0'}); }).singleton(); } } void main() async { final scope = CherryPick.openRootScope()..installModules([ConfigModule()]); final config = await scope.resolveAsync(); print(config.settings['theme']); // dark print(config.settings['version']); // 3.0 // tryResolveAsync: returns null instead of throwing final opt = await scope.tryResolveAsync(); print('Optional: $opt'); // Optional: null await CherryPick.closeRootScope(); } ``` -------------------------------- ### Generated Module Code Source: https://github.com/pese-git/cherrypick/blob/master/cherrypick_annotations/README.md This is an example of the code generated by cherrypick_generator based on the AppModule annotations. ```dart final class $AppModule extends AppModule { @override void builder(Scope currentScope) { bind().toProvide(() => dio()).singleton(); bind().toProvide(() => baseUrl()).withName('baseUrl'); bind().toInstance(foo()); bind().toProvide(() => bar(currentScope.resolve())); bind().toProvideWithParams((args) => greet(args)); } } ``` -------------------------------- ### Run All Cherrypick Benchmarks Source: https://github.com/pese-git/cherrypick/blob/master/benchmark_di/README.md Execute all benchmark scenarios using the cherrypick DI implementation, with Markdown output. ```shell dart run bin/main.dart --di=cherrypick --benchmark=all --format=markdown ``` -------------------------------- ### Registering Dependencies with CherryPick Source: https://github.com/pese-git/cherrypick/blob/master/doc/full_tutorial_en.md Demonstrates various ways to register dependencies using sync, async, and parameterized providers, as well as singletons and instances. ```dart bind().toProvide(() => MyServiceImpl()); bind().toProvideAsync(() async => await initRepo()); bind().toProvideWithParams((id) => UserService(id)); // Singleton bind().toProvide(() => MyApi()).singleton(); // Register an already created object final config = AppConfig.dev(); bind().toInstance(config); // Register an already running Future/async value final setupFuture = loadEnvironment(); bind().toInstanceAsync(setupFuture); ``` -------------------------------- ### Generated Field Injection Mixin Source: https://github.com/pese-git/cherrypick/blob/master/cherrypick_annotations/README.md This is a simplified example of the mixin generated by cherrypick_generator for field injection. ```dart mixin _$ProfileView { void _inject(ProfileView instance) { instance.auth = CherryPick.openRootScope().resolve(); instance.manager = CherryPick.openScope(scopeName: 'profile').resolve(); instance.adminUserService = CherryPick.openRootScope().resolve(named: 'admin'); } } ``` -------------------------------- ### Generated DI Module Code Source: https://github.com/pese-git/cherrypick/blob/master/doc/full_tutorial_en.md This is an example of the code generated by CherryPick based on the annotated AppModule. It shows how bindings are created. ```dart class $AppModule extends AppModule { @override void builder(Scope currentScope) { bind().toProvide(() => apiClient()).singleton(); bind().toProvide(() => userService(currentScope.resolve())); bind().toProvide(() => mockApiClient()).withName('mock').singleton(); } } ``` -------------------------------- ### Generated Field Injection Code Source: https://github.com/pese-git/cherrypick/blob/master/doc/full_tutorial_en.md Example of generated code for field injection. The mixin automatically resolves and injects dependencies into fields. ```dart mixin $ProfileBloc { @override void _inject(ProfileBloc instance) { instance.auth = CherryPick.openRootScope().resolve(); instance.adminUser = CherryPick.openRootScope().resolve(named: 'admin'); } } ``` -------------------------------- ### Circular Dependency Error Example Source: https://github.com/pese-git/cherrypick/blob/master/website/docs/advanced-features/circular-dependency-detection.md Demonstrates how mutually dependent services cause a `CircularDependencyException` when resolved. Ensure you have the necessary classes and module bindings. ```dart class A { A(B b); } class B { B(A a); } scope.installModules([ Module((bind) { bind().to((s) => A(s.resolve())); bind().to((s) => B(s.resolve())); }), ]); scope.resolve(); // Throws CircularDependencyException ``` -------------------------------- ### Run Benchmarks for get_it Source: https://github.com/pese-git/cherrypick/blob/master/benchmark_di/README.md Execute all benchmark scenarios specifically for the get_it DI container, outputting results in Markdown. ```shell dart run bin/main.dart --di=getit --benchmark=all --format=markdown ``` -------------------------------- ### Initialize Singleton Instance with toProvide() Source: https://github.com/pese-git/cherrypick/wiki/Quick-Start-Eng Bind a provider function as a singleton using `toProvide().singeltone()`. This ensures only one instance is created. ```dart Binding().toProvide(() => "hello world").singeltone(); ``` -------------------------------- ### Build Static Content Source: https://github.com/pese-git/cherrypick/blob/master/website/README.md Generates static website content into the 'build' directory for hosting. ```bash yarn build ``` -------------------------------- ### Initialize String Instance with toProvide() Source: https://github.com/pese-git/cherrypick/wiki/Quick-Start-Eng Use `toProvide()` to bind a provider function that creates an instance, like a string. ```dart Binding().toProvide(() => "hello world"); ``` -------------------------------- ### Module Registration with Cherrypick Annotations Source: https://github.com/pese-git/cherrypick/blob/master/cherrypick_generator/README.md Define DI modules by annotating classes with `@module()`. Use annotations like `@singleton`, `@instance`, `@provide`, `@named`, and `@params` on methods and parameters to configure service registration. ```dart import 'package:cherrypick_annotations/cherrypick_annotations.dart'; @module() class MyModule { @singleton @instance AuthService provideAuth(Api api); @provide @named('logging') Future provideLogger(@params Map args); } ``` -------------------------------- ### Define a Module with Dependency Bindings Source: https://github.com/pese-git/cherrypick/blob/master/website/docs/core-concepts/module.md Implement the `builder` method to define how dependencies are bound within the module's scope. This example shows binding an `ApiClient` instance and a string. ```dart class AppModule extends Module { @override void builder(Scope currentScope) { bind().toInstance(ApiClientMock()); bind().toProvide(() => "Hello world!"); } } ``` -------------------------------- ### Connecting DI Modules and Field Injection Source: https://github.com/pese-git/cherrypick/blob/master/doc/full_tutorial_en.md Demonstrates how to connect the DI modules and use field-injected dependencies in your application's entry point. ```dart void main() async { final scope = CherryPick.openRootScope(); scope.installModules([ $AppModule(), ]); // DI via field injection final bloc = ProfileBloc(); runApp(MyApp(bloc: bloc)); } ``` -------------------------------- ### Specify Benchmark Matrix Source: https://github.com/pese-git/cherrypick/blob/master/benchmark_di/README.md Run the chainSingleton benchmark with a specified matrix of chain counts and nesting depths, repeating measurements 3 times, and outputting in CSV format. ```shell dart run bin/main.dart --benchmark=chainSingleton --chainCount=10,100 --nestingDepth=5,10 --repeat=3 --format=csv ``` -------------------------------- ### Deploy Website (No SSH) Source: https://github.com/pese-git/cherrypick/blob/master/website/README.md Deploys the website without using SSH. Requires specifying the GitHub username. ```bash GIT_USER= yarn deploy ``` -------------------------------- ### Initialize String Instance with Binding Source: https://github.com/pese-git/cherrypick/blob/master/doc/quick_start_en.md Configure a dependency binding for a String instance using either `toInstance()` with a pre-initialized value or `toProvide()` with a constructor function. ```dart Binding().toInstance("hello world"); ``` ```dart Binding().toProvide(() => "hello world"); ``` -------------------------------- ### Use Safe Scope Creation Source: https://github.com/pese-git/cherrypick/blob/master/doc/cycle_detection.en.md Recommends using `CherryPick.openGlobalSafeRootScope()` over manual `Scope` instantiation for safer dependency management. ```dart // Instead of final scope = Scope(null); // Use final scope = CherryPick.openGlobalSafeRootScope(); ``` -------------------------------- ### Resolve Dependencies Safely (Dart) Source: https://context7.com/pese-git/cherrypick/llms.txt Use `resolve()` to get a dependency, which throws `StateError` if not found. For safe retrieval, use `tryResolve()`, which returns `null` instead of throwing. Both methods support `named` and `params` arguments and search parent scopes if the dependency is not found locally. ```dart import 'package:cherrypick/cherrypick.dart'; class FeatureFlag { final bool isEnabled; FeatureFlag(this.isEnabled); } class FeatureModule extends Module { @override void builder(Scope currentScope) { bind().toInstance(FeatureFlag(true)); } } void main() async { final scope = CherryPick.openRootScope()..installModules([FeatureModule()]); // resolve throws if not found final flag = scope.resolve(); print('Feature enabled: ${flag.isEnabled}'); // Feature enabled: true // tryResolve returns null safely final missing = scope.tryResolve(); print('Missing: $missing'); // Missing: null // Named resolution final namedFlag = scope.tryResolve(named: 'experimental'); print('Experimental flag: $namedFlag'); // Experimental flag: null await CherryPick.closeRootScope(); } ``` -------------------------------- ### Running Code Generation Source: https://github.com/pese-git/cherrypick/blob/master/website/docs/using-annotations.md Execute the `build_runner` command to generate the necessary DI code based on your annotations. Use `--delete-conflicting-outputs` to ensure a clean build. ```shell dart run build_runner build --delete-conflicting-outputs # or in Flutter: flutter pub run build_runner build --delete-conflicting-outputs ``` -------------------------------- ### Singleton with Parameterized Providers Source: https://github.com/pese-git/cherrypick/blob/master/doc/full_tutorial_en.md Demonstrates the behavior of `.singleton()` when used with parameterized providers. Note that only the first set of parameters is used for caching. ```dart bind().toProvideWithParams((params) => Service(params)).singleton(); final a = scope.resolve(params: 1); // Creates Service(1) final b = scope.resolve(params: 2); // Returns Service(1) print(identical(a, b)); // true ``` -------------------------------- ### Initialize Named String Instance with toProvide() Source: https://github.com/pese-git/cherrypick/wiki/Quick-Start-Eng Use `withName()` to assign a name to an instance bound with `toProvide()`, enabling retrieval by name. ```dart Binding().withName("my_string").toProvide(() => "hello world"); ``` -------------------------------- ### Initialize Singleton String Instance with Binding Source: https://github.com/pese-git/cherrypick/blob/master/doc/quick_start_en.md Configure a String binding to be a singleton using `singleton()`. This ensures only one instance of the dependency is ever created and reused. ```dart Binding().toInstance("hello world").singleton(); ``` ```dart Binding().toProvide(() => "hello world").singleton(); ``` -------------------------------- ### Initialize String Instance with toInstance() Source: https://github.com/pese-git/cherrypick/wiki/Quick-Start-Eng Use `toInstance()` to bind a pre-initialized instance, such as a string. ```dart Binding().toInstance("hello world"); ``` -------------------------------- ### Run CherryPick Code Generator Source: https://github.com/pese-git/cherrypick/blob/master/doc/annotations_en.md Execute the build runner to generate DI code based on annotations. Ensure you have build_runner and cherrypick_generator in your dev_dependencies. ```sh dart run build_runner build --delete-conflicting-outputs ```