mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-23 21:13:35 +00:00
Compare commits
12 Commits
cherrypick
...
cherrypick
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d93d4173a2 | ||
|
|
85aa23d7ed | ||
|
|
51cf4a0dc0 | ||
|
|
8f980ff111 | ||
|
|
4d872d7c25 | ||
|
|
450f4231cb | ||
|
|
cd1b9cf49d | ||
|
|
33775f5748 | ||
|
|
e5848784ac | ||
|
|
a4b0ddfa54 | ||
|
|
547a15fa4e | ||
|
|
a9c95f6a89 |
43
CHANGELOG.md
43
CHANGELOG.md
@@ -3,6 +3,49 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## 2025-08-11
|
||||
|
||||
### Changes
|
||||
|
||||
---
|
||||
|
||||
Packages with breaking changes:
|
||||
|
||||
- [`cherrypick` - `v3.0.0-dev.7`](#cherrypick---v300-dev7)
|
||||
|
||||
Packages with other changes:
|
||||
|
||||
- [`cherrypick_annotations` - `v1.1.1`](#cherrypick_annotations---v111)
|
||||
- [`cherrypick_flutter` - `v1.1.3-dev.7`](#cherrypick_flutter---v113-dev7)
|
||||
- [`cherrypick_generator` - `v1.1.1`](#cherrypick_generator---v111)
|
||||
|
||||
---
|
||||
|
||||
#### `cherrypick` - `v3.0.0-dev.7`
|
||||
|
||||
- **FIX**(comment): fix warnings.
|
||||
- **FIX**(license): correct urls.
|
||||
- **FEAT**: add Disposable interface source and usage example.
|
||||
- **DOCS**(readme): add comprehensive section on annotations and DI code generation.
|
||||
- **DOCS**(readme): add detailed section and examples for automatic Disposable resource cleanup\n\n- Added a dedicated section with English description and code samples on using Disposable for automatic resource management.\n- Updated Features to include automatic resource cleanup for Disposable dependencies.\n\nHelps developers understand and implement robust DI resource management practices.
|
||||
- **DOCS**(faq): add best practice FAQ about using await with scope disposal.
|
||||
- **DOCS**(faq): add best practice FAQ about using await with scope disposal.
|
||||
- **BREAKING** **REFACTOR**(core): make closeRootScope async and await dispose.
|
||||
- **BREAKING** **DOCS**(disposable): add detailed English documentation and usage examples for Disposable interface; chore: update binding_resolver and add explanatory comment in scope_test for deprecated usage.\n\n- Expanded Disposable interface docs, added sync & async example classes, and CherryPick integration sample.\n- Clarified how to implement and use Disposable in DI context.\n- Updated binding_resolver for internal improvements.\n- Added ignore for deprecated member use in scope_test for clarity and future upgrades.\n\nBREAKING CHANGE: Documentation style enhancement and clearer API usage for Disposable implementations.
|
||||
|
||||
#### `cherrypick_annotations` - `v1.1.1`
|
||||
|
||||
- **FIX**(license): correct urls.
|
||||
|
||||
#### `cherrypick_flutter` - `v1.1.3-dev.7`
|
||||
|
||||
- **FIX**(license): correct urls.
|
||||
|
||||
#### `cherrypick_generator` - `v1.1.1`
|
||||
|
||||
- **FIX**(license): correct urls.
|
||||
|
||||
|
||||
## 2025-08-08
|
||||
|
||||
### Changes
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -192,7 +192,7 @@
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
||||
@@ -47,7 +47,7 @@ packages:
|
||||
path: "../cherrypick"
|
||||
relative: true
|
||||
source: path
|
||||
version: "3.0.0-dev.3"
|
||||
version: "3.0.0-dev.5"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
## 3.0.0-dev.7
|
||||
|
||||
> Note: This release has breaking changes.
|
||||
|
||||
- **FIX**(comment): fix warnings.
|
||||
- **FIX**(license): correct urls.
|
||||
- **FEAT**: add Disposable interface source and usage example.
|
||||
- **DOCS**(readme): add comprehensive section on annotations and DI code generation.
|
||||
- **DOCS**(readme): add detailed section and examples for automatic Disposable resource cleanup\n\n- Added a dedicated section with English description and code samples on using Disposable for automatic resource management.\n- Updated Features to include automatic resource cleanup for Disposable dependencies.\n\nHelps developers understand and implement robust DI resource management practices.
|
||||
- **DOCS**(faq): add best practice FAQ about using await with scope disposal.
|
||||
- **DOCS**(faq): add best practice FAQ about using await with scope disposal.
|
||||
- **BREAKING** **REFACTOR**(core): make closeRootScope async and await dispose.
|
||||
- **BREAKING** **DOCS**(disposable): add detailed English documentation and usage examples for Disposable interface; chore: update binding_resolver and add explanatory comment in scope_test for deprecated usage.\n\n- Expanded Disposable interface docs, added sync & async example classes, and CherryPick integration sample.\n- Clarified how to implement and use Disposable in DI context.\n- Updated binding_resolver for internal improvements.\n- Added ignore for deprecated member use in scope_test for clarity and future upgrades.\n\nBREAKING CHANGE: Documentation style enhancement and clearer API usage for Disposable implementations.
|
||||
|
||||
## 3.0.0-dev.6
|
||||
|
||||
> Note: This release has breaking changes.
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
https://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
||||
@@ -1,8 +1,92 @@
|
||||
# CherryPick
|
||||
|
||||
`cherrypick` is a flexible and lightweight dependency injection library for Dart and Flutter. It provides an easy-to-use system for registering, scoping, and resolving dependencies using modular bindings and hierarchical scopes. The design enables cleaner architecture, testability, and modular code in your applications.
|
||||
`cherrypick` is a flexible and lightweight dependency injection library for Dart and Flutter.
|
||||
It provides an easy-to-use system for registering, scoping, and resolving dependencies using modular bindings and hierarchical scopes. The design enables cleaner architecture, testability, and modular code in your applications.
|
||||
|
||||
## Key Concepts
|
||||
---
|
||||
|
||||
## Table of Contents
|
||||
- [Key Features](#key-features)
|
||||
- [Installation](#installation)
|
||||
- [Getting Started](#getting-started)
|
||||
- [Core Concepts](#core-concepts)
|
||||
- [Binding](#binding)
|
||||
- [Module](#module)
|
||||
- [Scope](#scope)
|
||||
- [Automatic Resource Cleanup with Disposable](#automatic-resource-cleanup-with-disposable)
|
||||
- [Dependency Resolution API](#dependency-resolution-api)
|
||||
- [Using Annotations & Code Generation](#using-annotations--code-generation)
|
||||
- [Advanced Features](#advanced-features)
|
||||
- [Hierarchical Subscopes](#hierarchical-subscopes)
|
||||
- [Logging](#logging)
|
||||
- [Circular Dependency Detection](#circular-dependency-detection)
|
||||
- [Performance Improvements](#performance-improvements)
|
||||
- [Example Application](#example-application)
|
||||
- [FAQ](#faq)
|
||||
- [Documentation Links](#documentation-links)
|
||||
- [Contributing](#contributing)
|
||||
- [License](#license)
|
||||
|
||||
---
|
||||
|
||||
## Key Features
|
||||
- Main Scope and Named Subscopes
|
||||
- Named Instance Binding and Resolution
|
||||
- Asynchronous and Synchronous Providers
|
||||
- Providers Supporting Runtime Parameters
|
||||
- Singleton Lifecycle Management
|
||||
- Modular and Hierarchical Composition
|
||||
- Null-safe Resolution (tryResolve/tryResolveAsync)
|
||||
- Circular Dependency Detection (Local and Global)
|
||||
- Comprehensive logging of dependency injection state and actions
|
||||
- Automatic resource cleanup for all registered Disposable dependencies
|
||||
|
||||
---
|
||||
|
||||
## Installation
|
||||
|
||||
Add to your `pubspec.yaml`:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
cherrypick: ^<latest_version>
|
||||
```
|
||||
|
||||
Then run:
|
||||
|
||||
```shell
|
||||
dart pub get
|
||||
```
|
||||
---
|
||||
|
||||
## Getting Started
|
||||
|
||||
Here is a minimal example that registers and resolves a dependency:
|
||||
|
||||
```dart
|
||||
import 'package:cherrypick/cherrypick.dart';
|
||||
|
||||
|
||||
class AppModule extends Module {
|
||||
@override
|
||||
void builder(Scope currentScope) {
|
||||
bind<ApiClient>().toInstance(ApiClientMock());
|
||||
bind<String>().toProvide(() => "Hello, CherryPick!");
|
||||
}
|
||||
}
|
||||
|
||||
final rootScope = CherryPick.openRootScope();
|
||||
rootScope.installModules([AppModule()]);
|
||||
|
||||
final greeting = rootScope.resolve<String>();
|
||||
print(greeting); // prints: Hello, CherryPick!
|
||||
|
||||
await CherryPick.closeRootScope();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### Binding
|
||||
|
||||
@@ -79,8 +163,108 @@ final str = rootScope.resolve<String>();
|
||||
// Resolve a dependency asynchronously
|
||||
final result = await rootScope.resolveAsync<String>();
|
||||
|
||||
// Close the root scope once done
|
||||
CherryPick.closeRootScope();
|
||||
// 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();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Automatic Resource Cleanup with Disposable
|
||||
|
||||
CherryPick can automatically clean up any dependency that implements the `Disposable` interface. This makes resource management (for controllers, streams, sockets, files, etc.) easy and reliable—especially when scopes or the app are shut down.
|
||||
|
||||
If you bind an object implementing `Disposable` as a singleton or provide it via the DI container, CherryPick will call its `dispose()` method when the scope is closed or cleaned up.
|
||||
|
||||
#### Key Points
|
||||
- Supports both synchronous and asynchronous cleanup (dispose may return `void` or `Future`).
|
||||
- All `Disposable` instances from the current scope and subscopes will be disposed in the correct order.
|
||||
- Prevents resource leaks and enforces robust cleanup.
|
||||
- No manual wiring needed once your class implements `Disposable`.
|
||||
|
||||
#### Minimal Sync Example
|
||||
```dart
|
||||
class CacheManager implements Disposable {
|
||||
void dispose() {
|
||||
cache.clear();
|
||||
print('CacheManager disposed!');
|
||||
}
|
||||
}
|
||||
|
||||
final scope = CherryPick.openRootScope();
|
||||
scope.installModules([
|
||||
Module((bind) => bind<CacheManager>().toProvide(() => CacheManager()).singleton()),
|
||||
]);
|
||||
|
||||
// ...later
|
||||
await CherryPick.closeRootScope(); // prints: CacheManager disposed!
|
||||
```
|
||||
|
||||
#### Async Example
|
||||
```dart
|
||||
class MyServiceWithSocket implements Disposable {
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
await socket.close();
|
||||
print('Socket closed!');
|
||||
}
|
||||
}
|
||||
|
||||
scope.installModules([
|
||||
Module((bind) => bind<MyServiceWithSocket>().toProvide(() => MyServiceWithSocket()).singleton()),
|
||||
]);
|
||||
|
||||
await CherryPick.closeRootScope(); // awaits async disposal
|
||||
```
|
||||
|
||||
**Tip:** Always call `await CherryPick.closeRootScope()` or `await scope.closeSubScope(key)` in your shutdown/teardown logic to ensure all resources are released automatically.
|
||||
|
||||
---
|
||||
|
||||
### Automatic resource management (`Disposable`, `dispose`)
|
||||
|
||||
CherryPick automatically manages the lifecycle of any object registered via DI that implements the `Disposable` interface.
|
||||
|
||||
**Best practice:**
|
||||
Always finish your work with `await CherryPick.closeRootScope()` (for the root scope) or `await scope.closeSubScope('key')` (for subscopes).
|
||||
These methods will automatically await `dispose()` on all resolved objects (e.g., singletons) that implement `Disposable`, ensuring proper and complete resource cleanup—sync or async.
|
||||
|
||||
Manual `await scope.dispose()` may be useful if you manually manage custom scopes.
|
||||
|
||||
#### Example
|
||||
|
||||
```dart
|
||||
class MyService implements Disposable {
|
||||
@override
|
||||
FutureOr<void> dispose() async {
|
||||
// release resources, close streams, perform async shutdown, etc.
|
||||
print('MyService disposed!');
|
||||
}
|
||||
}
|
||||
|
||||
final scope = openRootScope();
|
||||
scope.installModules([
|
||||
ModuleImpl(),
|
||||
]);
|
||||
|
||||
final service = scope.resolve<MyService>();
|
||||
|
||||
// ... use service
|
||||
|
||||
// Recommended completion:
|
||||
await CherryPick.closeRootScope(); // will print: MyService disposed!
|
||||
|
||||
// Or, to close and clean up a subscope and its resources:
|
||||
await scope.closeSubScope('feature');
|
||||
|
||||
class ModuleImpl extends Module {
|
||||
@override
|
||||
void builder(Scope scope) {
|
||||
bind<MyService>().toProvide(() => MyService()).singleton();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Working with Subscopes
|
||||
@@ -101,6 +285,144 @@ final dataBloc = await subScope.resolveAsync<DataBloc>();
|
||||
>
|
||||
> This optimization is internal and does not change any library APIs or usage patterns, but it significantly improves resolution speed in larger applications.
|
||||
|
||||
---
|
||||
|
||||
## Using Annotations & Code Generation
|
||||
|
||||
CherryPick provides best-in-class developer ergonomics and type safety through **Dart annotations** and code generation. This lets you dramatically reduce boilerplate: simply annotate your classes, fields, and modules, run the code generator, and enjoy auto-wired dependency injection!
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Annotate** your services, providers, and fields using `cherrypick_annotations`.
|
||||
2. **Generate** code using `cherrypick_generator` with `build_runner`.
|
||||
3. **Use** generated modules and mixins for fully automated DI (dependency injection).
|
||||
|
||||
---
|
||||
|
||||
### Supported Annotations
|
||||
|
||||
| Annotation | Target | Description |
|
||||
|-------------------|---------------|--------------------------------------------------------------------------------|
|
||||
| `@injectable()` | class | Enables automatic field injection for this class (mixin will be generated) |
|
||||
| `@inject()` | field | Field will be injected using DI (works with @injectable classes) |
|
||||
| `@module()` | class | Declares a DI module; its methods can provide services/providers |
|
||||
| `@provide` | method | Registers as a DI provider method (may have dependencies as parameters) |
|
||||
| `@instance` | method/class | Registers an instance (new object on each resolution, i.e. factory) |
|
||||
| `@singleton` | method/class | Registers as a singleton (one instance per scope) |
|
||||
| `@named` | field/param | Use named instance (bind/resolve by name or apply to field/param) |
|
||||
| `@scope` | field/param | Inject or resolve from a specific named scope |
|
||||
| `@params` | param | Marks method parameter as filled by user-supplied runtime params at resolution |
|
||||
|
||||
You can easily **combine** these annotations for advanced scenarios!
|
||||
|
||||
---
|
||||
|
||||
### Field Injection Example
|
||||
|
||||
```dart
|
||||
import 'package:cherrypick_annotations/cherrypick_annotations.dart';
|
||||
|
||||
@injectable()
|
||||
class ProfilePage with _\$ProfilePage {
|
||||
@inject()
|
||||
late final AuthService auth;
|
||||
|
||||
@inject()
|
||||
@scope('profile')
|
||||
late final ProfileManager manager;
|
||||
|
||||
@inject()
|
||||
@named('admin')
|
||||
late final UserService adminUserService;
|
||||
}
|
||||
```
|
||||
|
||||
- After running build_runner, the mixin `_ | ||||