mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-24 05:25:19 +00:00
feat(i18n): add initial Russian localization for documentation and site config
- Added full Russian translations for all main documentation sections () into . - Sections translated include: key features, installation, getting started, all core concepts, advanced features, API reference, FAQ, links, additional modules, contributing, and license. - Updated to ensure language switching is available and Russian locale is active. - Each Russian file preserves the structure and formatting of the original Markdown, with machine-aided draft translation for immediate use. - Lays the groundwork for UI language switching (en/ru) and enables further manual translation refinement and review.
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
---
|
||||
sidebar_position: 9
|
||||
---
|
||||
|
||||
# Дополнительные модули
|
||||
|
||||
CherryPick предоставляет набор официальных доп. модулей для расширенных и специфичных сценариев:
|
||||
|
||||
| Имя модуля | Описание |
|
||||
|--------------------------|--------------------------------------------------------------|
|
||||
| [**cherrypick_annotations**](https://pub.dev/packages/cherrypick_annotations) | Dart-аннотации для лаконичного DI и генерации кода. |
|
||||
| [**cherrypick_generator**](https://pub.dev/packages/cherrypick_generator) | Генератор кода для автосборки DI-привязок по аннотациям. |
|
||||
| [**cherrypick_flutter**](https://pub.dev/packages/cherrypick_flutter) | Интеграция DI с Flutter: виджеты-провайдеры, injection. |
|
||||
| [**talker_cherrypick_logger**](https://pub.dev/packages/talker_cherrypick_logger) | Продвинутый логгер событий DI CherryPick с интеграцией в [Talker](https://pub.dev/packages/talker). Позволяет визуализировать состояние, ошибки и автоматически отслеживать DI прямо в UI и консоли. |
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Обнаружение циклических зависимостей
|
||||
|
||||
CherryPick может обнаруживать циклические зависимости в вашей DI-конфигурации, помогая избежать бесконечных циклов и сложных для отладки ошибок.
|
||||
|
||||
## Как использовать:
|
||||
|
||||
### 1. Включите обнаружение во время разработки
|
||||
|
||||
**Локально (в рамках одного скоупа):**
|
||||
```dart
|
||||
final scope = CherryPick.openSafeRootScope(); // Локальное обнаружение включено по умолчанию
|
||||
// или для существующего скоупа:
|
||||
scope.enableCycleDetection();
|
||||
```
|
||||
|
||||
**Глобально (между скоупами):**
|
||||
```dart
|
||||
CherryPick.enableGlobalCrossScopeCycleDetection();
|
||||
final rootScope = CherryPick.openGlobalSafeRootScope();
|
||||
```
|
||||
|
||||
### 2. Пример ошибки
|
||||
|
||||
Если вы объявите взаимозависимые сервисы:
|
||||
```dart
|
||||
class A { A(B b); }
|
||||
class B { B(A a); }
|
||||
|
||||
scope.installModules([
|
||||
Module((bind) {
|
||||
bind<A>().to((s) => A(s.resolve<B>()));
|
||||
bind<B>().to((s) => B(s.resolve<A>()));
|
||||
}),
|
||||
]);
|
||||
|
||||
scope.resolve<A>(); // выбросит CircularDependencyException
|
||||
```
|
||||
|
||||
### 3. Общая рекомендация
|
||||
|
||||
- **Включайте обнаружение** всегда в debug и тестовой среде для максимальной безопасности.
|
||||
- **Отключайте обнаружение** в production после завершения тестирования, ради производительности.
|
||||
|
||||
```dart
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
void main() {
|
||||
if (kDebugMode) {
|
||||
CherryPick.enableGlobalCycleDetection();
|
||||
CherryPick.enableGlobalCrossScopeCycleDetection();
|
||||
}
|
||||
runApp(MyApp());
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Отладка и обработка ошибок
|
||||
|
||||
При обнаружении будет выброшено исключение `CircularDependencyException` с цепочкой зависимостей:
|
||||
```dart
|
||||
try {
|
||||
scope.resolve<MyService>();
|
||||
} on CircularDependencyException catch (e) {
|
||||
print('Цепочка зависимостей: ${e.dependencyChain}');
|
||||
}
|
||||
```
|
||||
|
||||
**Подробнее:** смотрите [cycle_detection.ru.md](doc/cycle_detection.ru.md)
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# Иерархические подскоупы
|
||||
|
||||
CherryPick поддерживает иерархическую структуру скоупов, что позволяет строить сложные и модульные графы зависимостей для профессиональных архитектур приложений. Каждый подскоуп наследует зависимости родителя и позволяет переопределять их локально.
|
||||
|
||||
## Основные моменты
|
||||
|
||||
- **Подскоупы** — дочерние скоупы, открываемые от любого существующего (в том числе root).
|
||||
- Зависимости подскоупа перекрывают родительские при разрешении.
|
||||
- Если зависимость не найдена в подскоупе, CherryPick ищет её выше по иерархии.
|
||||
- Подскоупы могут иметь собственные модули, "жизненный цикл", Disposable-объекты.
|
||||
- Можно делать вложенность любой глубины для фич, компонентов и т.д.
|
||||
|
||||
## Пример
|
||||
|
||||
```dart
|
||||
final rootScope = CherryPick.openRootScope();
|
||||
rootScope.installModules([AppModule()]);
|
||||
|
||||
// Открыть подскоуп для функции/страницы
|
||||
final userFeatureScope = rootScope.openSubScope('userFeature');
|
||||
userFeatureScope.installModules([UserFeatureModule()]);
|
||||
|
||||
// В userFeatureScope сперва ищет в своей области
|
||||
final userService = userFeatureScope.resolve<UserService>();
|
||||
|
||||
// Если не нашлось — идёт в rootScope
|
||||
final sharedService = userFeatureScope.resolve<SharedService>();
|
||||
|
||||
// Подскоупы можно вкладывать друг в друга сколь угодно глубоко
|
||||
final dialogScope = userFeatureScope.openSubScope('dialog');
|
||||
dialogScope.installModules([DialogModule()]);
|
||||
final dialogManager = dialogScope.resolve<DialogManager>();
|
||||
```
|
||||
|
||||
## Применение
|
||||
|
||||
- Модульная изоляция частей/экранов с собственными зависимостями
|
||||
- Переопределение сервисов для конкретных сценариев/навигации
|
||||
- Управление жизнью и освобождением ресурсов по группам
|
||||
|
||||
**Совет:** Всегда закрывайте подскоупы, когда они больше не нужны, чтобы освободить ресурсы.
|
||||
@@ -0,0 +1,62 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Логирование
|
||||
|
||||
CherryPick позволяет логировать все события и ошибки DI с помощью расширяемого observer-механизма.
|
||||
|
||||
## Кастомные Observer'ы
|
||||
|
||||
Вы можете передавать свою реализацию `CherryPickObserver` в root- или любой подскоуп.
|
||||
Это позволяет централизовать и настраивать логирование, направлять логи в консоль, файл, сторонние сервисы или системы как [Talker](https://pub.dev/packages/talker).
|
||||
|
||||
### Пример: вывод всех событий в консоль
|
||||
|
||||
```dart
|
||||
import 'package:cherrypick/cherrypick.dart';
|
||||
|
||||
void main() {
|
||||
// Встроенный PrintCherryPickObserver для консоли
|
||||
final observer = PrintCherryPickObserver();
|
||||
final scope = CherryPick.openRootScope(observer: observer);
|
||||
// Все события и ошибки DI будут выведены!
|
||||
}
|
||||
```
|
||||
|
||||
### Пример: расширенное логирование через Talker
|
||||
|
||||
Для более гибкого логирования или UI-оверлеев можно использовать observer наподобие [talker_cherrypick_logger](../talker_cherrypick_logger):
|
||||
|
||||
```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);
|
||||
CherryPick.openRootScope(observer: observer);
|
||||
// Все события попадают в Talker!
|
||||
}
|
||||
```
|
||||
|
||||
## Поведение по умолчанию
|
||||
- По умолчанию логирование "тихое" (SilentCherryPickObserver) для production — нет вывода без observer'а.
|
||||
- Можно назначить observer для любого скоупа.
|
||||
|
||||
## Возможности Observer'а
|
||||
|
||||
- Регистрация зависимостей
|
||||
- Получение/создание/удаление экземпляров
|
||||
- Установка/удаление модулей
|
||||
- Открытие/закрытие скоупов
|
||||
- Кэш-хиты/мимо
|
||||
- Обнаружение циклов
|
||||
- Диагностика, предупреждения, ошибки
|
||||
|
||||
## Когда применять
|
||||
|
||||
- Подробное логирование в dev/test окружениях
|
||||
- Передача логов в основную систему/аналитику
|
||||
- Отладка и профилирование DI
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# Улучшения производительности
|
||||
|
||||
> **Примечание по производительности:**
|
||||
> **Начиная с версии 3.0.0**, CherryPick использует Map-индексатор для поиска зависимостей. Это означает, что вызовы `resolve<T>()` и связанные методы работают за O(1) независимо от количества модулей/биндингов в скоупе. Ранее библиотека просматривала все модули/биндинги, что могло замедлять DI в крупных проектах.
|
||||
>
|
||||
> Эта оптимизация полностью внутренняя: интерфейс библиотеки и пользовательский код не изменились, но производительность заметно выросла на больших графах зависимостей.
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
sidebar_position: 10
|
||||
---
|
||||
|
||||
# Вклад в проект
|
||||
|
||||
Вкладывайтесь! Открывайте задачи или отправляйте pull request'ы на [GitHub](https://github.com/pese-git/cherrypick).
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# Привязка (Binding)
|
||||
|
||||
**Binding** — это конфигурация, которая определяет, как создавать или предоставлять конкретную зависимость. Binding поддерживает:
|
||||
|
||||
* Прямое присваивание экземпляра (`toInstance()`, `toInstanceAsync()`)
|
||||
* Ленивые провайдеры (синхронные/асинхронные функции)
|
||||
* Провайдеры с поддержкой динамических параметров
|
||||
* Именованные экземпляры для получения по строковому ключу
|
||||
* Необязательное управление жизненным циклом синглтона
|
||||
|
||||
## Пример
|
||||
|
||||
```dart
|
||||
// Прямое создание экземпляра
|
||||
Binding<String>().toInstance("Hello world");
|
||||
|
||||
// Асинхронное создание экземпляра
|
||||
Binding<String>().toInstanceAsync(Future.value("Hello world"));
|
||||
|
||||
// Ленивое создание экземпляра через фабрику (sync)
|
||||
Binding<String>().toProvide(() => "Hello world");
|
||||
|
||||
// Ленивое создание экземпляра через фабрику (async)
|
||||
Binding<String>().toProvideAsync(() async => "Hello async world");
|
||||
|
||||
// Экземпляр с параметрами (sync)
|
||||
Binding<String>().toProvideWithParams((params) => "Hello $params");
|
||||
|
||||
// Экземпляр с параметрами (async)
|
||||
Binding<String>().toProvideAsyncWithParams((params) async => "Hello $params");
|
||||
|
||||
// Именованный экземпляр для получения по имени
|
||||
Binding<String>().toProvide(() => "Hello world").withName("my_string");
|
||||
|
||||
// Синглтон (один экземпляр внутри скоупа)
|
||||
Binding<String>().toProvide(() => "Hello world").singleton();
|
||||
```
|
||||
@@ -0,0 +1,52 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# Disposable
|
||||
|
||||
CherryPick может автоматически очищать любые зависимости, реализующие интерфейс `Disposable`. Это упрощает управление ресурсами (контроллеры, потоки, сокеты, файлы и др.) — особенно при закрытии скоупа или приложения.
|
||||
|
||||
Если вы регистрируете объект, реализующий `Disposable`, как синглтон или через DI-контейнер, CherryPick вызовет его метод `dispose()` при закрытии или очистке скоупа.
|
||||
|
||||
## Основные моменты
|
||||
- Поддерживаются синхронная и асинхронная очистка (dispose может возвращать `void` или `Future`).
|
||||
- Все объекты `Disposable` из текущего скоупа и подскоупов будут удалены в правильном порядке.
|
||||
- Предотвращает утечки ресурсов и обеспечивает корректную очистку.
|
||||
- Не нужно вручную связывать очистку — просто реализуйте интерфейс.
|
||||
|
||||
## Минимальный синхронный пример
|
||||
```dart
|
||||
class CacheManager implements Disposable {
|
||||
void dispose() {
|
||||
cache.clear();
|
||||
print('CacheManager удалён!');
|
||||
}
|
||||
}
|
||||
|
||||
final scope = CherryPick.openRootScope();
|
||||
scope.installModules([
|
||||
Module((bind) => bind<CacheManager>().toProvide(() => CacheManager()).singleton()),
|
||||
]);
|
||||
|
||||
// ...спустя время
|
||||
await CherryPick.closeRootScope(); // выведет: CacheManager удалён!
|
||||
```
|
||||
|
||||
## Асинхронный пример
|
||||
```dart
|
||||
class MyServiceWithSocket implements Disposable {
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
await socket.close();
|
||||
print('Socket закрыт!');
|
||||
}
|
||||
}
|
||||
|
||||
scope.installModules([
|
||||
Module((bind) => bind<MyServiceWithSocket>().toProvide(() => MyServiceWithSocket()).singleton()),
|
||||
]);
|
||||
|
||||
await CherryPick.closeRootScope(); // дождётся завершения async очистки
|
||||
```
|
||||
|
||||
**Совет:** Всегда вызывайте `await CherryPick.closeRootScope()` или `await scope.closeSubScope(key)` в вашем shutdown/teardown-коде для гарантированной очистки ресурсов.
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Модуль
|
||||
|
||||
**Модуль** — это логическая точка сбора для привязок (bindings), предназначенная для группирования и инициализации связанных зависимостей. Реализуйте метод `builder`, чтобы определить, как зависимости будут связываться внутри скоупа.
|
||||
|
||||
## Пример
|
||||
|
||||
```dart
|
||||
class AppModule extends Module {
|
||||
@override
|
||||
void builder(Scope currentScope) {
|
||||
bind<ApiClient>().toInstance(ApiClientMock());
|
||||
bind<String>().toProvide(() => "Hello world!");
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Скоуп (Scope)
|
||||
|
||||
**Scope** управляет деревом модулей и экземпляров зависимостей. Скоупы могут быть вложенными (иерархия родитель-дочерний), обеспечивая модульную компоновку приложения и возможность переопределения зависимостей для отдельных контекстов.
|
||||
|
||||
Обычно вы работаете с корневым скоупом, но при необходимости можете создавать именованные подскоупы.
|
||||
|
||||
## Пример
|
||||
|
||||
```dart
|
||||
// Открыть основной/корневой скоуп
|
||||
final rootScope = CherryPick.openRootScope();
|
||||
|
||||
// Установить пользовательский модуль
|
||||
rootScope.installModules([AppModule()]);
|
||||
|
||||
// Получить зависимость синхронно
|
||||
final str = rootScope.resolve<String>();
|
||||
|
||||
// Получить зависимость асинхронно
|
||||
final result = await rootScope.resolveAsync<String>();
|
||||
|
||||
// Рекомендуется: закрывать корневой скоуп и высвобождать все ресурсы
|
||||
await CherryPick.closeRootScope();
|
||||
|
||||
// Либо вручную вызвать dispose на любом скоупе, которым вы управляете индивидуально
|
||||
// await rootScope.dispose();
|
||||
```
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# API разрешения зависимостей
|
||||
|
||||
- `resolve<T>()` — получает экземпляр зависимости или выбрасывает исключение, если не найдено.
|
||||
- `resolveAsync<T>()` — асинхронный вариант для зависимостей с асинхронной инициализацией.
|
||||
- `tryResolve<T>()` — возвращает `null`, если не найдено (синхронно).
|
||||
- `tryResolveAsync<T>()` — возвращает `null` асинхронно, если не найдено.
|
||||
|
||||
Поддерживает:
|
||||
- Синхронные и асинхронные зависимости
|
||||
- Именованные зависимости
|
||||
- Провайдеры с runtime-параметрами или без них
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
sidebar_position: 8
|
||||
---
|
||||
|
||||
# Ссылки на документацию
|
||||
|
||||
* Обнаружение циклических зависимостей [(En)](doc/cycle_detection.en.md)[(Ru)](doc/cycle_detection.ru.md)
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
---
|
||||
|
||||
# Пример приложения
|
||||
|
||||
Ниже приведён полный пример с модулями, подскоупами, асинхронными провайдерами и разрешением зависимостей.
|
||||
|
||||
```dart
|
||||
import 'dart:async';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:cherrypick/cherrypick.dart';
|
||||
|
||||
class AppModule extends Module {
|
||||
@override
|
||||
void builder(Scope currentScope) {
|
||||
bind<ApiClient>().withName("apiClientMock").toInstance(ApiClientMock());
|
||||
bind<ApiClient>().withName("apiClientImpl").toInstance(ApiClientImpl());
|
||||
}
|
||||
}
|
||||
|
||||
class FeatureModule extends Module {
|
||||
final bool isMock;
|
||||
FeatureModule({required this.isMock});
|
||||
@override
|
||||
void builder(Scope currentScope) {
|
||||
// Асинхронный провайдер DataRepository с выбором зависимости по имени
|
||||
bind<DataRepository>()
|
||||
.withName("networkRepo")
|
||||
.toProvideAsync(() async {
|
||||
final client = await Future.delayed(
|
||||
Duration(milliseconds: 100),
|
||||
() => currentScope.resolve<ApiClient>(
|
||||
named: isMock ? "apiClientMock" : "apiClientImpl",
|
||||
),
|
||||
);
|
||||
return NetworkDataRepository(client);
|
||||
})
|
||||
.singleton();
|
||||
|
||||
// Вызов асинхронного провайдера для DataBloc
|
||||
bind<DataBloc>().toProvideAsync(
|
||||
() async {
|
||||
final repo = await currentScope.resolveAsync<DataRepository>(
|
||||
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>();
|
||||
dataBloc.data.listen(
|
||||
(d) => print('Получены данные: $d'),
|
||||
onError: (e) => print('Ошибка: $e'),
|
||||
onDone: () => print('DONE'),
|
||||
);
|
||||
|
||||
await dataBloc.fetchData();
|
||||
}
|
||||
|
||||
class DataBloc {
|
||||
final DataRepository _dataRepository;
|
||||
Stream<String> get data => _dataController.stream;
|
||||
final StreamController<String> _dataController = StreamController.broadcast();
|
||||
|
||||
DataBloc(this._dataRepository);
|
||||
|
||||
Future<void> fetchData() async {
|
||||
try {
|
||||
_dataController.sink.add(await _dataRepository.getData());
|
||||
} catch (e) {
|
||||
_dataController.sink.addError(e);
|
||||
}
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
_dataController.close();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DataRepository {
|
||||
Future<String> getData();
|
||||
}
|
||||
|
||||
class NetworkDataRepository implements DataRepository {
|
||||
final ApiClient _apiClient;
|
||||
final _token = 'token';
|
||||
NetworkDataRepository(this._apiClient);
|
||||
|
||||
@override
|
||||
Future<String> 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';
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,10 @@
|
||||
---
|
||||
sidebar_position: 7
|
||||
---
|
||||
|
||||
# Часто задаваемые вопросы
|
||||
|
||||
### В: Нужно ли использовать `await` с CherryPick.closeRootScope(), CherryPick.closeScope() или scope.dispose(), если у меня нет Disposable-сервисов?
|
||||
|
||||
**О:**
|
||||
Да! Даже если ваши сервисы сейчас не реализуют `Disposable`, всегда используйте `await` при закрытии скоупов. Если вы позже добавите очистку ресурсов (реализовав dispose()), CherryPick всё обработает автоматически и ваш код останется без изменений. Это гарантирует надежное освобождение ресурсов для любого сценария.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Быстрый старт
|
||||
|
||||
Минимальный пример регистрации и получения зависимости:
|
||||
|
||||
```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); // напечатает: Hello, CherryPick!
|
||||
|
||||
await CherryPick.closeRootScope();
|
||||
```
|
||||
@@ -0,0 +1,18 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
---
|
||||
|
||||
# Установка
|
||||
|
||||
Добавьте в ваш `pubspec.yaml`:
|
||||
|
||||
```yaml
|
||||
dependencies:
|
||||
cherrypick: ^<latest_version>
|
||||
```
|
||||
|
||||
Затем выполните команду:
|
||||
|
||||
```shell
|
||||
dart pub get
|
||||
```
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
sidebar_position: 1
|
||||
---
|
||||
|
||||
# Ключевые возможности
|
||||
|
||||
- Главный скоуп и именованные подскоупы
|
||||
- Привязка и разрешение экземпляров по имени
|
||||
- Асинхронные и синхронные провайдеры
|
||||
- Провайдеры с поддержкой параметров времени выполнения
|
||||
- Управление жизненным циклом синглтонов
|
||||
- Модульная и иерархическая композиция
|
||||
- Null-safe разрешение зависимостей (tryResolve/tryResolveAsync)
|
||||
- Обнаружение циклических зависимостей (локально и глобально)
|
||||
- Подробное логирование состояния и действий DI-контейнера
|
||||
- Автоматическое освобождение ресурсов для всех зарегистрированных Disposable зависимостей
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
sidebar_position: 11
|
||||
---
|
||||
|
||||
# Лицензия
|
||||
|
||||
Проект распространяется под [лицензией Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
|
||||
|
||||
**Важно:** При отсутствии специальных договорённостей поставляется "КАК ЕСТЬ", без каких-либо гарантий. Подробности см. в самой лицензии.
|
||||
@@ -0,0 +1,102 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# Использование аннотаций и генерация кода
|
||||
|
||||
CherryPick предоставляет продвинутую эргономику и безопасный DI благодаря **аннотациям Dart** и генерации кода. Это позволяет избавить вас от рутины — просто аннотируйте классы, поля и модули, запускайте генератор и используйте полностью автосвязанный DI!
|
||||
|
||||
## Как это работает
|
||||
|
||||
1. **Аннотируйте** сервисы, провайдеры и поля с помощью `cherrypick_annotations`.
|
||||
2. **Генерируйте** код с помощью `cherrypick_generator` и `build_runner`.
|
||||
3. **Используйте** автосгенерированные модули и миксины для автоматического внедрения.
|
||||
|
||||
---
|
||||
|
||||
## Поддерживаемые аннотации
|
||||
|
||||
| Аннотация | Target | Описание |
|
||||
|---------------------|---------------|--------------------------------------------------------------|
|
||||
| `@injectable()` | класс | Включает автоподстановку полей (генерируется mixin) |
|
||||
| `@inject()` | поле | Автоподстановка через DI (работает с @injectable) |
|
||||
| `@module()` | класс | DI-модуль: методы — провайдеры и сервисы |
|
||||
| `@provide` | метод | Регистрирует как DI-провайдер (можно с параметрами) |
|
||||
| `@instance` | метод/класс | Регистрирует новый экземпляр (на каждый resolve, factory) |
|
||||
| `@singleton` | метод/класс | Регистрация как синглтон (один экземпляр на скоуп) |
|
||||
| `@named` | поле/параметр | Использование именованных экземпляров для внедрения/resolve |
|
||||
| `@scope` | поле/параметр | Внедрение/resolve из другого (именованного) скоупа |
|
||||
| `@params` | параметр | Добавляет user-defined параметры во время resolve |
|
||||
|
||||
---
|
||||
|
||||
## Пример Field Injection
|
||||
|
||||
```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;
|
||||
}
|
||||
```
|
||||
|
||||
- После запуска build_runner миксин `_ProfilePage` будет сгенерирован для внедрения.
|
||||
- Вызовите `myProfilePage.injectFields();` чтобы все зависимости были внедрены автоматически.
|
||||
|
||||
## Пример модуля/провайдера
|
||||
|
||||
```dart
|
||||
@module()
|
||||
abstract class AppModule {
|
||||
@singleton
|
||||
AuthService provideAuth(Api api) => AuthService(api);
|
||||
|
||||
@named('logging')
|
||||
@provide
|
||||
Future<Logger> provideLogger(@params Map<String, dynamic> args) async => ...;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Шаги использования
|
||||
|
||||
1. Добавьте зависимости в `pubspec.yaml`.
|
||||
2. Аннотируйте классы и модули.
|
||||
3. Генерируйте код командой build_runner.
|
||||
4. Регистрируйте модули и используйте автосвязь.
|
||||
|
||||
---
|
||||
|
||||
## Расширенные возможности
|
||||
|
||||
- Используйте `@named` для внедрения по ключу.
|
||||
- Используйте `@scope` для внедрения из разных скоупов.
|
||||
- Используйте `@params` для передачи runtime-параметров.
|
||||
|
||||
---
|
||||
|
||||
## Советы и FAQ
|
||||
|
||||
- После изменений в DI-коде запускайте build_runner заново.
|
||||
- Не редактируйте `.g.dart` вручную.
|
||||
- Ошибки некорректных аннотаций определяются автоматически.
|
||||
|
||||
---
|
||||
|
||||
## Ссылки
|
||||
|
||||
- [Подробнее про аннотации (en)](doc/annotations_en.md)
|
||||
- [cherrypick_annotations/README.md](../cherrypick_annotations/README.md)
|
||||
- [cherrypick_generator/README.md](../cherrypick_generator/README.md)
|
||||
- Полный пример: [`examples/postly`](../examples/postly)
|
||||
Reference in New Issue
Block a user