mirror of
https://github.com/pese-git/cherrypick.git
synced 2026-01-23 21:13:35 +00:00
refactored di library.
This commit is contained in:
247
README.md
247
README.md
@@ -1,250 +1,13 @@
|
||||
# dart_di
|
||||
|
||||
Экспериментальная разработка DI на ЯП Dart
|
||||
Experimental development of DI in the Dart language
|
||||
|
||||
- [New Api ENG](/doc/quick_start_en.md)
|
||||
- [New Api RU](/doc/quick_start_ru.md)
|
||||
|
||||
## Документация
|
||||
|
||||
### Быстрый старт
|
||||
### Features
|
||||
|
||||
Основным классом для всех операций является `DiContainer`. Вы можете зарегистрировать свои зависимости,
|
||||
получив `ResolvingContext` через метод `bind<T>()` и используя его различные методы регистрации зависимостей.
|
||||
Далее вы можете получить зависимости с помощью `resolve<T>()`.
|
||||
|
||||
Пример:
|
||||
|
||||
```dart
|
||||
final container = DiContainer();
|
||||
container.bind<SomeService>().toValue(SomeServiceImpl());
|
||||
/*
|
||||
...
|
||||
*/
|
||||
|
||||
// Метод `resolve` просто возвращает зарегистрированный ранее экземпляр
|
||||
final someService = container.resolve<SomeService>();
|
||||
```
|
||||
|
||||
### Ленивая инициализация
|
||||
|
||||
Если вам нужно создать объект в момент резолвинга, вы можете использовать ленивую (другими словами, по запросу) инициализацию объекта
|
||||
с помощью метода `toFactoryN()`.
|
||||
|
||||
Пример:
|
||||
|
||||
```dart
|
||||
final container = DiContainer();
|
||||
// В методе `toFactory` вы просто определяете, как построить экземпляр через фабричную лямбду
|
||||
container.bind<SomeService>().toFactory( () => SomeServiceImpl() );
|
||||
/*
|
||||
...
|
||||
*/
|
||||
// Метод `resolve()` будет создавать экземпляр через зарегистрированную фабричную лямбду каждый раз, когда вы вызываете его
|
||||
final someService = container.resolve<SomeService>();
|
||||
final anotherSomeService = container.resolve<SomeService>();
|
||||
assert(someService != anotherSomeService);
|
||||
```
|
||||
|
||||
Но обычно у вас есть много типов с разными зависимостями, которые образуют граф зависимостей.
|
||||
|
||||
Пример:
|
||||
|
||||
```dart
|
||||
class A {}
|
||||
class B {}
|
||||
|
||||
class C {
|
||||
final A a;
|
||||
final B b;
|
||||
|
||||
C(this.a, this.b);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
Если вам нужно зарегистрировать некоторый тип, зависящий от других типов из контейнера,
|
||||
вы можете использовать методы `toFactory1<T1>` - `toFactory8<T1 ... T8>`, где число в конце,
|
||||
является количеством запрошенных через аргументы типов зависимостей.
|
||||
(Обратите внимание, что вам нужно определить все зависимости в аргументах - `toFactory2<A1, A2>`).
|
||||
|
||||
|
||||
Пример:
|
||||
|
||||
```dart
|
||||
class SomeService {
|
||||
final A a;
|
||||
final B b;
|
||||
|
||||
SomeService(this.a, this.b);
|
||||
}
|
||||
|
||||
final container = DiContainer();
|
||||
container.bind<A>(A::class).toFactory (() => A());
|
||||
container.bind<B>(B::class).toFactory (() => B());
|
||||
|
||||
/// В фабричной лямбде вы определяете, как построить зависимость от других зависимостей
|
||||
/// (Порядок разрешенных экземпляров соответствует порядку типов аргументов)
|
||||
container.bind<SomeService>().toFactory2<A, B>((a, b) => SomeService(a, b));
|
||||
|
||||
/*
|
||||
...
|
||||
*/
|
||||
|
||||
/// Получаем экземпляр `SomeService` через resolve своих зависимостей.
|
||||
/// В нашем случае - это resolve A и B
|
||||
/// Внимание!!! То, что он будет создавать новые экземпляры A и B каждый раз, когда вы вызываете `resolve` SomeService
|
||||
final someService = container.resolve<SomeService>();
|
||||
```
|
||||
|
||||
### Время жизни экземпляров и контроль области видимости
|
||||
|
||||
Если вы хотите создать экземпляр зарегистрированной зависимости только один раз,
|
||||
и вам нужно получить/разрешить зависимость много раз в контейнере, то вы можете зарегистрировать
|
||||
свою зависимость с добавлением `asSingeton()`. Например:
|
||||
|
||||
```dart
|
||||
final container = DiContainer();
|
||||
container.bind<A>()
|
||||
.toFactory(() => A())
|
||||
.asSingleton();
|
||||
|
||||
container
|
||||
.bind<B>()
|
||||
.toFactory(() => B());
|
||||
.asSingleton();
|
||||
|
||||
container.bind<SomeService>().toFactory2<A, B>((a, b) -> SomeService(a, b));
|
||||
|
||||
// Код выше означает: Контейнер, регистрирует создание A и B только в первый раз, когда оно будет запрошен,
|
||||
// и регистрирует создание SomeService каждый раз, когда оно будет запрошен.
|
||||
|
||||
final a = container.resolve<A>();
|
||||
final b = container.resolve<B>();
|
||||
final anotherA = container.resolve<A>();
|
||||
final anotherB = container.resolve<B>();
|
||||
|
||||
assert(a == anotherA && b == anotherB);
|
||||
|
||||
final someService = container.resolve<SomeService>();
|
||||
final anotherSomeService = container.resolve<SomeService>();
|
||||
|
||||
assert(someService != anotherSomeService);
|
||||
```
|
||||
|
||||
Если вы хотите сразу создать свой зарегистрированный экземпляр, вы можете вызвать `resolve()`. Например:
|
||||
|
||||
|
||||
```dart
|
||||
final container = DiContainer();
|
||||
// Это заставит создать зависимость после регистрации
|
||||
container.bind <SomeService>()
|
||||
.toFactory(() => SomeService())
|
||||
.asSingleton()
|
||||
.resolve();
|
||||
```
|
||||
|
||||
Когда вы работаете со сложным приложением, в большинстве случаев вы можете работать со многими модулями с собственными зависимостями.
|
||||
Эти модули могут быть настроены различными `DiContainer`-ми. И вы можете прикрепить контейнер к другому, как родительский.
|
||||
В этом случае родительские зависимости будут видны для дочернего контейнера,
|
||||
и через него вы можете формировать различные области видимости зависимостей. Например:
|
||||
|
||||
```dart
|
||||
final parentContainer = DiContainer();
|
||||
parentContainer.bind<A>().toFactory(() => A())
|
||||
|
||||
final childContainer = DiContainer(parentContainer);
|
||||
// Обратите внимание, что родительская зависимость A видна для дочернего контейнера
|
||||
final a = childContainer.resolve<A>();
|
||||
|
||||
/*
|
||||
// Но следующий код потерпит неудачу с ошибкой, потому что родитель не знает о своем потомке.
|
||||
final parentContainer = DiContainer();
|
||||
final childContainer = DiContainer();
|
||||
childContainer.bind<A>().toFactory(() => A());
|
||||
|
||||
// Выдает ошибку
|
||||
final a = parentContainer.resolve<A>();
|
||||
*/
|
||||
```
|
||||
|
||||
### Структура библиотеки
|
||||
|
||||
Библиотека состоит из DiContainer и Resolver.
|
||||
DiContainer - это контейнер со всеми Resolver для разных типов. А `Resolver` - это просто объект, который знает, как разрешить данный тип.
|
||||
Многие из resolver-ов обернуты другими, поэтому они могут быть составлены для разных вариантов использования.
|
||||
Resolver - интерфейс, поэтому он имеет много реализаций. Основным является ResolvingContext.
|
||||
Вы можете думать об этом как об объекте контекста, который имеет вспомогательные методы для создания различных вариантов resolver-ов (`toFactory`,` toValue`, `asSingleton`).
|
||||
Но все они просто используют метод `toResolver` для определения некоторого корневого resolver в контексте.
|
||||
Когда вы запрашиваете тип из контейнера с помощью метода `resolve<T>()`, он просто находит контекст для типа и вызывает корневой resolver, который может вызывать другие resolver-ы.
|
||||
|
||||
|
||||
Пример (из ```example```):
|
||||
|
||||
```dart
|
||||
import 'dart:async';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:dart_di/dart_di.dart';
|
||||
|
||||
void main() async {
|
||||
final dataModule = new DiContainer()
|
||||
..bind<ApiClient>().toValue(new ApiClientMock())
|
||||
..bind<DataRepository>()
|
||||
.toFactory1<ApiClient>((c) => new NetworkDataRepository(c))
|
||||
..bind<DataBloc>().toFactory1<DataRepository>((s) => new DataBloc(s));
|
||||
|
||||
final dataBloc = dataModule.resolve<DataBloc>();
|
||||
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<String> get data => _dataController.stream;
|
||||
StreamController<String> _dataController = new 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 'hello world';
|
||||
}
|
||||
}
|
||||
```
|
||||
- [x] Scope
|
||||
- [x] Sub scope
|
||||
- [x] Initialization instance with name
|
||||
|
||||
@@ -1,15 +1,51 @@
|
||||
import 'dart:async';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:dart_di/dart_di.dart';
|
||||
import 'package:dart_di/scope.dart';
|
||||
import 'package:dart_di/module.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 {
|
||||
bool isMock;
|
||||
|
||||
FeatureModule({required this.isMock});
|
||||
|
||||
@override
|
||||
void builder(Scope currentScope) {
|
||||
bind<DataRepository>()
|
||||
.withName("networkRepo")
|
||||
.toProvide(
|
||||
() => NetworkDataRepository(
|
||||
currentScope.resolve<ApiClient>(
|
||||
named: isMock ? "apiClientMock" : "apiClientImpl",
|
||||
),
|
||||
),
|
||||
)
|
||||
.singeltone();
|
||||
bind<DataBloc>().toProvide(
|
||||
() => DataBloc(
|
||||
currentScope.resolve<DataRepository>(named: "networkRepo"),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void main() async {
|
||||
final dataModule = new DiContainer()
|
||||
..bind<ApiClient>().toValue(new ApiClientMock())
|
||||
..bind<DataRepository>()
|
||||
.toFactory1<ApiClient>((c) => new NetworkDataRepository(c))
|
||||
..bind<DataBloc>().toFactory1<DataRepository>((s) => new DataBloc(s));
|
||||
final scope = openRootScope().installModules([
|
||||
AppModule(),
|
||||
]);
|
||||
|
||||
final dataBloc = dataModule.resolve<DataBloc>();
|
||||
final subScope = scope
|
||||
.openSubScope("featureScope")
|
||||
.installModules([FeatureModule(isMock: true)]);
|
||||
|
||||
final dataBloc = subScope.resolve<DataBloc>();
|
||||
dataBloc.data.listen((d) => print('Received data: $d'),
|
||||
onError: (e) => print('Error: $e'), onDone: () => print('DONE'));
|
||||
|
||||
@@ -60,6 +96,14 @@ class ApiClientMock implements ApiClient {
|
||||
@override
|
||||
Future sendRequest(
|
||||
{@required String? url, String? token, Map? requestBody}) async {
|
||||
return 'hello world';
|
||||
return 'Local Data';
|
||||
}
|
||||
}
|
||||
|
||||
class ApiClientImpl implements ApiClient {
|
||||
@override
|
||||
Future sendRequest(
|
||||
{@required String? url, String? token, Map? requestBody}) async {
|
||||
return 'Network data';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
import 'dart:async';
|
||||
import 'package:meta/meta.dart';
|
||||
import 'package:dart_di/experimental/scope.dart';
|
||||
import 'package:dart_di/experimental/module.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 {
|
||||
bool isMock;
|
||||
|
||||
FeatureModule({required this.isMock});
|
||||
|
||||
@override
|
||||
void builder(Scope currentScope) {
|
||||
bind<DataRepository>()
|
||||
.withName("networkRepo")
|
||||
.toProvide(
|
||||
() => NetworkDataRepository(
|
||||
currentScope.resolve<ApiClient>(
|
||||
named: isMock ? "apiClientMock" : "apiClientImpl",
|
||||
),
|
||||
),
|
||||
)
|
||||
.singeltone();
|
||||
bind<DataBloc>().toProvide(
|
||||
() => DataBloc(
|
||||
currentScope.resolve<DataRepository>(named: "networkRepo"),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void main() async {
|
||||
final scope = openRootScope().installModules([
|
||||
AppModule(),
|
||||
]);
|
||||
|
||||
final subScope = scope
|
||||
.openSubScope("featureScope")
|
||||
.installModules([FeatureModule(isMock: true)]);
|
||||
|
||||
final dataBloc = subScope.resolve<DataBloc>();
|
||||
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<String> get data => _dataController.stream;
|
||||
StreamController<String> _dataController = new 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';
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
library dart_di;
|
||||
|
||||
export 'package:dart_di/di_container.dart';
|
||||
export 'package:dart_di/resolvers/resolvers.dart';
|
||||
export 'package:dart_di/resolvers/resolving_context.dart';
|
||||
export 'package:dart_di/scope.dart';
|
||||
export 'package:dart_di/module.dart';
|
||||
export 'package:dart_di/binding.dart';
|
||||
export 'package:dart_di/di.dart';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:dart_di/experimental/scope.dart';
|
||||
import 'package:dart_di/scope.dart';
|
||||
|
||||
Scope? _rootScope = null;
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
import 'package:dart_di/resolvers/resolving_context.dart';
|
||||
|
||||
/**
|
||||
* Контейнер - это объект, которой хранит все резолверы зависимостей.
|
||||
*/
|
||||
class DiContainer {
|
||||
final DiContainer? _parent;
|
||||
|
||||
final _resolvers = <Type, ResolvingContext>{};
|
||||
|
||||
DiContainer([this._parent]);
|
||||
|
||||
/**
|
||||
* Добавляет resolver зависимостей типа [T] в контейнер.
|
||||
* Обратите внимание, что перезапись значений внутри одного контейнера запрещена.
|
||||
* @return - возвращает [ResolvingContext] или [StateError]
|
||||
*/
|
||||
ResolvingContext<T> bind<T>() {
|
||||
var context = ResolvingContext<T>(this);
|
||||
if (hasInTree<T>()) {
|
||||
throw StateError(
|
||||
'Dependency of type `$T` is already exist in containers tree');
|
||||
}
|
||||
|
||||
_resolvers[T] = context;
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает разрешенную зависимость, определенную параметром типа [T].
|
||||
* Выдает [StateError], если зависимость не может быть разрешена.
|
||||
* Если вы хотите получить [null], если зависимость не может быть разрешена,
|
||||
* то используйте вместо этого [tryResolve]
|
||||
* @return - возвращает объект типа [T] или [StateError]
|
||||
*/
|
||||
T resolve<T>() {
|
||||
var resolved = tryResolve<T>();
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
} else {
|
||||
throw StateError(
|
||||
'Can\'t resolve dependency `$T`. Maybe you forget register it?');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает разрешенную зависимость типа [T] или null, если она не может быть разрешена.
|
||||
*/
|
||||
T? tryResolve<T>() {
|
||||
var resolver = _resolvers[T];
|
||||
if (resolver != null) {
|
||||
return resolver.resolve();
|
||||
} else {
|
||||
return _parent?.tryResolve<T>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает true, если у этого контейнера есть средство разрешения зависимостей для типа [T].
|
||||
* Если вы хотите проверить его для всего дерева контейнеров, используйте вместо него [hasInTree].
|
||||
* @return - возвращает булево значение
|
||||
*/
|
||||
bool has<T>() {
|
||||
return _resolvers.containsKey(T);
|
||||
}
|
||||
|
||||
/**
|
||||
* Возвращает true, если контейнер или его родители содержат средство разрешения зависимостей для типа [T].
|
||||
* Если вы хотите проверить его только для этого контейнера, используйте вместо него [has].
|
||||
* @return - возвращает булево значение
|
||||
*/
|
||||
bool hasInTree<T>() {
|
||||
return has<T>() || (_parent != null && _parent!.hasInTree<T>());
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:dart_di/experimental/scope.dart';
|
||||
import 'package:dart_di/scope.dart';
|
||||
|
||||
abstract class Factory<T> {
|
||||
T createInstance(Scope scope);
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:dart_di/experimental/binding.dart';
|
||||
import 'package:dart_di/experimental/scope.dart';
|
||||
import 'package:dart_di/binding.dart';
|
||||
import 'package:dart_di/scope.dart';
|
||||
|
||||
/// RU: Класс Module является основой для пользовательских модулей.
|
||||
/// Этот класс нужен для инициализации [Scope].
|
||||
@@ -1,15 +0,0 @@
|
||||
import 'package:dart_di/resolvers/resolver.dart';
|
||||
|
||||
/**
|
||||
* Разрешает зависимость для фабричной функции
|
||||
*/
|
||||
class FactoryResolver<T> extends Resolver<T> {
|
||||
final T Function() _factory;
|
||||
|
||||
FactoryResolver(this._factory);
|
||||
|
||||
@override
|
||||
T resolve() {
|
||||
return _factory();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
/**
|
||||
* Resolver - это абстракция, которая определяет,
|
||||
* как контейнер будет разрешать зависимость
|
||||
*/
|
||||
abstract class Resolver<T> {
|
||||
/**
|
||||
* Разрешает зависимость типа [T]
|
||||
* @return - возвращает объект типа [T]
|
||||
*/
|
||||
T? resolve();
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
/// Resolvers определяет, как разрешить зависимость для контейнера
|
||||
library resolvers;
|
||||
|
||||
export 'resolver.dart';
|
||||
export 'factory_resolver.dart';
|
||||
export 'value_resolver.dart';
|
||||
export 'singelton_resolver.dart';
|
||||
@@ -1,172 +0,0 @@
|
||||
import 'package:dart_di/di_container.dart';
|
||||
import 'package:dart_di/resolvers/factory_resolver.dart';
|
||||
import 'package:dart_di/resolvers/resolver.dart';
|
||||
import 'package:dart_di/resolvers/singelton_resolver.dart';
|
||||
import 'package:dart_di/resolvers/value_resolver.dart';
|
||||
|
||||
class ResolvingContext<T> extends Resolver {
|
||||
/// Корневой резолвер
|
||||
Resolver<T> get resolver {
|
||||
return _resolver as Resolver<T>;
|
||||
}
|
||||
|
||||
DiContainer _container;
|
||||
|
||||
late Resolver _resolver;
|
||||
|
||||
ResolvingContext(this._container);
|
||||
|
||||
/**
|
||||
* Разрешает зависимость типа [T]
|
||||
* @return - возвращает объект типа [T]
|
||||
*/
|
||||
@override
|
||||
T resolve() {
|
||||
_verify();
|
||||
return _resolver.resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* Добавляет резолвер в качестве корневого резолвера
|
||||
* С помощью этого метода вы можете добавить любой
|
||||
* пользовательский резолвер
|
||||
*/
|
||||
ResolvingContext<T> toResolver<TImpl extends T>(Resolver<TImpl> resolver) {
|
||||
_resolver = resolver;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать резолвер значения
|
||||
*/
|
||||
ResolvingContext<T> toValue<TImpl extends T>(T value) {
|
||||
Resolver<TImpl> resolver = ValueResolver(value as TImpl);
|
||||
return toResolver<TImpl>(resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразователь в сингелтон
|
||||
*/
|
||||
ResolvingContext<T> asSingleton() {
|
||||
return toResolver(SingletonResolver<T>(resolver));
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать фабричный resolver без каких-либо зависимостей
|
||||
*/
|
||||
ResolvingContext<T> toFactory<TImpl extends T>(TImpl Function() factory) {
|
||||
Resolver<TImpl> resolver = FactoryResolver<TImpl>(factory);
|
||||
return toResolver(resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать фабричный resolver с 1 зависимостью от контейнера
|
||||
*/
|
||||
ResolvingContext<T> toFactory1<T1>(T Function(T1) factory) {
|
||||
Resolver<T> resolver =
|
||||
FactoryResolver<T>(() => factory(_container.resolve<T1>()));
|
||||
return toResolver(resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать фабричный resolver с 2 зависимостями от контейнера
|
||||
*/
|
||||
ResolvingContext<T> toFactory2<T1, T2>(T Function(T1, T2) factory) {
|
||||
Resolver<T> resolver = FactoryResolver<T>(
|
||||
() => factory(_container.resolve<T1>(), _container.resolve<T2>()));
|
||||
return toResolver(resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать фабричный resolver с 3 зависимостями от контейнера
|
||||
*/
|
||||
ResolvingContext<T> toFactory3<T1, T2, T3>(T Function(T1, T2, T3) factory) {
|
||||
Resolver<T> resolver = FactoryResolver<T>(() => factory(
|
||||
_container.resolve<T1>(),
|
||||
_container.resolve<T2>(),
|
||||
_container.resolve<T3>()));
|
||||
return toResolver(resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать фабричный resolver с 4 зависимостями от контейнера
|
||||
*/
|
||||
ResolvingContext<T> toFactory4<T1, T2, T3, T4>(
|
||||
T Function(T1, T2, T3, T4) factory) {
|
||||
Resolver<T> resolver = FactoryResolver<T>(() => factory(
|
||||
_container.resolve<T1>(),
|
||||
_container.resolve<T2>(),
|
||||
_container.resolve<T3>(),
|
||||
_container.resolve<T4>()));
|
||||
return toResolver(resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать фабричный resolver с 5 зависимостями от контейнера
|
||||
*/
|
||||
ResolvingContext<T> toFactory5<T1, T2, T3, T4, T5>(
|
||||
T Function(T1, T2, T3, T4, T5) factory) {
|
||||
Resolver<T> resolver = FactoryResolver<T>(() => factory(
|
||||
_container.resolve<T1>(),
|
||||
_container.resolve<T2>(),
|
||||
_container.resolve<T3>(),
|
||||
_container.resolve<T4>(),
|
||||
_container.resolve<T5>()));
|
||||
return toResolver(resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать фабричный resolver с 6 зависимостями от контейнера
|
||||
*/
|
||||
ResolvingContext<T> toFactory6<T1, T2, T3, T4, T5, T6>(
|
||||
T Function(T1, T2, T3, T4, T5, T6) factory) {
|
||||
Resolver<T> resolver = FactoryResolver<T>(() => factory(
|
||||
_container.resolve<T1>(),
|
||||
_container.resolve<T2>(),
|
||||
_container.resolve<T3>(),
|
||||
_container.resolve<T4>(),
|
||||
_container.resolve<T5>(),
|
||||
_container.resolve<T6>()));
|
||||
return toResolver(resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать фабричный resolver с 7 зависимостями от контейнера
|
||||
*/
|
||||
ResolvingContext<T> toFactory7<T1, T2, T3, T4, T5, T6, T7>(
|
||||
T Function(T1, T2, T3, T4, T5, T6, T7) factory) {
|
||||
Resolver<T> resolver = FactoryResolver<T>(() => factory(
|
||||
_container.resolve<T1>(),
|
||||
_container.resolve<T2>(),
|
||||
_container.resolve<T3>(),
|
||||
_container.resolve<T4>(),
|
||||
_container.resolve<T5>(),
|
||||
_container.resolve<T6>(),
|
||||
_container.resolve<T7>()));
|
||||
return toResolver(resolver);
|
||||
}
|
||||
|
||||
/**
|
||||
* Создать фабричный resolver с 8 зависимостями от контейнера
|
||||
*/
|
||||
ResolvingContext<T> toFactory8<T1, T2, T3, T4, T5, T6, T7, T8>(
|
||||
T Function(T1, T2, T3, T4, T5, T6, T7, T8) factory) {
|
||||
Resolver<T> resolver = FactoryResolver<T>(() => factory(
|
||||
_container.resolve<T1>(),
|
||||
_container.resolve<T2>(),
|
||||
_container.resolve<T3>(),
|
||||
_container.resolve<T4>(),
|
||||
_container.resolve<T5>(),
|
||||
_container.resolve<T6>(),
|
||||
_container.resolve<T7>(),
|
||||
_container.resolve<T8>()));
|
||||
return toResolver(resolver);
|
||||
}
|
||||
|
||||
void _verify() {
|
||||
if (_resolver == null) {
|
||||
throw StateError("Can\'t resolve T without any resolvers. " +
|
||||
"Please check, may be you didn\'t do anything after bind()");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
import 'package:dart_di/resolvers/resolver.dart';
|
||||
|
||||
class SingletonResolver<T> extends Resolver<T> {
|
||||
Resolver<T> _decoratedResolver;
|
||||
T? _value = null;
|
||||
|
||||
SingletonResolver(this._decoratedResolver);
|
||||
|
||||
@override
|
||||
T? resolve() {
|
||||
if (_value == null) {
|
||||
_value = _decoratedResolver.resolve();
|
||||
}
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
import 'package:dart_di/resolvers/resolver.dart';
|
||||
|
||||
/**
|
||||
* Разрешает зависимость для значения
|
||||
*/
|
||||
class ValueResolver<T> extends Resolver<T> {
|
||||
T _value;
|
||||
|
||||
ValueResolver(this._value);
|
||||
|
||||
@override
|
||||
T resolve() {
|
||||
return _value;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:dart_di/experimental/binding.dart';
|
||||
import 'package:dart_di/experimental/module.dart';
|
||||
import 'package:dart_di/binding.dart';
|
||||
import 'package:dart_di/module.dart';
|
||||
|
||||
Scope openRootScope() => Scope(null);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: dart_di
|
||||
description: Experimental Dependency Injection library.
|
||||
version: 0.0.2
|
||||
version: 0.1.0
|
||||
author: Sergey Penkovsky <sergey.penkovsky@gmail.com>
|
||||
homepage: locahost
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:dart_di/experimental/binding.dart';
|
||||
import 'package:dart_di/binding.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
@@ -1,458 +0,0 @@
|
||||
import 'package:dart_di/di_container.dart';
|
||||
import 'package:dart_di/resolvers/resolver.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:mockito/mockito.dart';
|
||||
|
||||
void main() {
|
||||
group('Without parent', () {
|
||||
test('Container bind<T> throws state error if it\'s already has resolver',
|
||||
() {
|
||||
final container = new DiContainer();
|
||||
container.bind<int>().toResolver(_makeResolver(5));
|
||||
|
||||
expect(() => container.bind<int>().toResolver(_makeResolver(3)),
|
||||
throwsA(isA<StateError>()));
|
||||
});
|
||||
|
||||
test("Container resolves value after adding a dependency", () {
|
||||
final expectedValue = 3;
|
||||
final container = new DiContainer();
|
||||
container.bind<int>().toResolver(_makeResolver(expectedValue));
|
||||
expect(container.resolve<int>(), expectedValue);
|
||||
});
|
||||
|
||||
test("Container throws state error if the value can't be resolved", () {
|
||||
final container = DiContainer();
|
||||
expect(() => container.resolve<int>(), throwsA(isA<StateError>()));
|
||||
});
|
||||
|
||||
test("Container has() returns true if it has resolver", () {
|
||||
final expectedValue = 5;
|
||||
final container = new DiContainer();
|
||||
container.bind<int>().toResolver(_makeResolver(expectedValue));
|
||||
expect(container.has<int>(), true);
|
||||
});
|
||||
|
||||
test("Container has() returns false if it hasn't resolver", () {
|
||||
final container = new DiContainer();
|
||||
expect(container.has<int>(), false);
|
||||
});
|
||||
|
||||
test("Container hasInTree() returns true if it has resolver", () {
|
||||
final expectedValue = 5;
|
||||
final container = DiContainer();
|
||||
container.bind<int>().toResolver(_makeResolver(expectedValue));
|
||||
expect(container.hasInTree<int>(), true);
|
||||
});
|
||||
|
||||
test("Container hasInTree() returns true if it hasn`t resolver", () {
|
||||
final container = DiContainer();
|
||||
expect(container.hasInTree<int>(), false);
|
||||
});
|
||||
});
|
||||
|
||||
group('With parent', () {
|
||||
test(
|
||||
"Container bind() throws state error (if it's parent already has a resolver)",
|
||||
() {
|
||||
final parentContainer = new DiContainer();
|
||||
final container = new DiContainer(parentContainer);
|
||||
|
||||
parentContainer.bind<int>().toResolver(_makeResolver(5));
|
||||
|
||||
expect(() => container.bind<int>().toResolver(_makeResolver(3)),
|
||||
throwsA(isA<StateError>()));
|
||||
});
|
||||
|
||||
test("Container resolve() returns a value from parent container", () {
|
||||
final expectedValue = 5;
|
||||
final parentContainer = DiContainer();
|
||||
final container = DiContainer(parentContainer);
|
||||
|
||||
parentContainer.bind<int>().toResolver(_makeResolver(expectedValue));
|
||||
|
||||
expect(container.resolve<int>(), expectedValue);
|
||||
});
|
||||
|
||||
test("Container resolve() returns a several value from parent container",
|
||||
() {
|
||||
final expectedIntValue = 5;
|
||||
final expectedStringValue = "Hello world";
|
||||
final parentContainer = DiContainer();
|
||||
final container = DiContainer(parentContainer);
|
||||
|
||||
parentContainer.bind<int>().toResolver(_makeResolver(expectedIntValue));
|
||||
parentContainer
|
||||
.bind<String>()
|
||||
.toResolver(_makeResolver(expectedStringValue));
|
||||
|
||||
expect(container.resolve<int>(), expectedIntValue);
|
||||
expect(container.resolve<String>(), expectedStringValue);
|
||||
});
|
||||
|
||||
test("Container resolve() throws a state error if parent hasn't value too",
|
||||
() {
|
||||
final parentContainer = DiContainer();
|
||||
final container = DiContainer(parentContainer);
|
||||
expect(() => container.resolve<int>(), throwsA(isA<StateError>()));
|
||||
});
|
||||
|
||||
test("Container has() returns false if parent has a resolver", () {
|
||||
final parentContainer = DiContainer();
|
||||
final container = DiContainer(parentContainer);
|
||||
|
||||
parentContainer.bind<int>().toResolver(_makeResolver(5));
|
||||
|
||||
expect(container.has<int>(), false);
|
||||
});
|
||||
|
||||
test("Container has() returns false if parent hasn't a resolver", () {
|
||||
final parentContainer = DiContainer();
|
||||
final container = DiContainer(parentContainer);
|
||||
|
||||
expect(container.has<int>(), false);
|
||||
});
|
||||
|
||||
test("Container hasInTree() returns true if parent has a resolver", () {
|
||||
final parentContainer = DiContainer();
|
||||
final container = DiContainer(parentContainer);
|
||||
|
||||
parentContainer.bind<int>().toResolver(_makeResolver(5));
|
||||
|
||||
expect(container.hasInTree<int>(), true);
|
||||
});
|
||||
|
||||
test("Test asSingelton", () {
|
||||
final expectedIntValue = 10;
|
||||
final containerA = DiContainer();
|
||||
final containerB = DiContainer(containerA);
|
||||
|
||||
containerA.bind<int>().toValue(expectedIntValue).asSingleton();
|
||||
|
||||
expect(containerB.resolve<int>(), expectedIntValue);
|
||||
});
|
||||
|
||||
test("Child container can resolve parent container's value", () {
|
||||
final containerA = DiContainer();
|
||||
final a = AA();
|
||||
containerA.bind<A>().toValue(a);
|
||||
|
||||
final containerB = DiContainer(containerA);
|
||||
final containerC = DiContainer(containerB);
|
||||
expect(containerC.resolve<A>(), a);
|
||||
});
|
||||
});
|
||||
|
||||
test("Bind to the factory resolves with value", () {
|
||||
final container = DiContainer();
|
||||
final a = AA();
|
||||
container.bind<A>().toFactory(() => a);
|
||||
|
||||
expect(container.resolve<A>(), a);
|
||||
});
|
||||
|
||||
test("Bind to the factory resolves with value", () {
|
||||
final container = DiContainer();
|
||||
final a = AA();
|
||||
container.bind<A>().toValue(a);
|
||||
container.bind<DependOnA>().toFactory1<A>((a) => DependOnA(a));
|
||||
|
||||
expect(container.resolve<DependOnA>().a, a);
|
||||
});
|
||||
|
||||
test("Bind to the factory resolves with 2 value", () {
|
||||
final container = DiContainer();
|
||||
final a = AA();
|
||||
final b = BB();
|
||||
container.bind<A>().toValue(a);
|
||||
container.bind<B>().toValue(b);
|
||||
container.bind<DependOnAB>().toFactory2<A, B>((a, b) => DependOnAB(a, b));
|
||||
|
||||
expect(container.resolve<DependOnAB>().a, a);
|
||||
expect(container.resolve<DependOnAB>().b, b);
|
||||
});
|
||||
|
||||
test("Bind to the factory resolves with 3 value", () {
|
||||
final container = DiContainer();
|
||||
final a = AA();
|
||||
final b = BB();
|
||||
final c = CC();
|
||||
container.bind<A>().toValue(a);
|
||||
container.bind<B>().toValue(b);
|
||||
container.bind<C>().toValue(c);
|
||||
container
|
||||
.bind<DependOnABC>()
|
||||
.toFactory3<A, B, C>((a, b, c) => DependOnABC(a, b, c));
|
||||
|
||||
expect(container.resolve<DependOnABC>().a, a);
|
||||
expect(container.resolve<DependOnABC>().b, b);
|
||||
expect(container.resolve<DependOnABC>().c, c);
|
||||
});
|
||||
|
||||
test("Bind to the factory resolves with 4 value", () {
|
||||
final container = DiContainer();
|
||||
final a = AA();
|
||||
final b = BB();
|
||||
final c = CC();
|
||||
final d = DD();
|
||||
container.bind<A>().toValue(a);
|
||||
container.bind<B>().toValue(b);
|
||||
container.bind<C>().toValue(c);
|
||||
container.bind<D>().toValue(d);
|
||||
container
|
||||
.bind<DependOnABCD>()
|
||||
.toFactory4<A, B, C, D>((a, b, c, d) => DependOnABCD(a, b, c, d));
|
||||
|
||||
expect(container.resolve<DependOnABCD>().a, a);
|
||||
expect(container.resolve<DependOnABCD>().b, b);
|
||||
expect(container.resolve<DependOnABCD>().c, c);
|
||||
expect(container.resolve<DependOnABCD>().d, d);
|
||||
});
|
||||
|
||||
test("Bind to the factory resolves with 5 value", () {
|
||||
final container = DiContainer();
|
||||
final a = AA();
|
||||
final b = BB();
|
||||
final c = CC();
|
||||
final d = DD();
|
||||
final e = EE();
|
||||
container.bind<A>().toValue(a);
|
||||
container.bind<B>().toValue(b);
|
||||
container.bind<C>().toValue(c);
|
||||
container.bind<D>().toValue(d);
|
||||
container.bind<E>().toValue(e);
|
||||
container.bind<DependOnABCDE>().toFactory5<A, B, C, D, E>(
|
||||
(a, b, c, d, e) => DependOnABCDE(a, b, c, d, e));
|
||||
|
||||
expect(container.resolve<DependOnABCDE>().a, a);
|
||||
expect(container.resolve<DependOnABCDE>().b, b);
|
||||
expect(container.resolve<DependOnABCDE>().c, c);
|
||||
expect(container.resolve<DependOnABCDE>().d, d);
|
||||
expect(container.resolve<DependOnABCDE>().e, e);
|
||||
});
|
||||
|
||||
test("Bind to the factory resolves with 6 value", () {
|
||||
final container = DiContainer();
|
||||
final a = AA();
|
||||
final b = BB();
|
||||
final c = CC();
|
||||
final d = DD();
|
||||
final e = EE();
|
||||
final f = FF();
|
||||
container.bind<A>().toValue(a);
|
||||
container.bind<B>().toValue(b);
|
||||
container.bind<C>().toValue(c);
|
||||
container.bind<D>().toValue(d);
|
||||
container.bind<E>().toValue(e);
|
||||
container.bind<F>().toValue(f);
|
||||
container.bind<DependOnABCDEF>().toFactory6<A, B, C, D, E, F>(
|
||||
(a, b, c, d, e, f) => DependOnABCDEF(a, b, c, d, e, f));
|
||||
|
||||
expect(container.resolve<DependOnABCDEF>().a, a);
|
||||
expect(container.resolve<DependOnABCDEF>().b, b);
|
||||
expect(container.resolve<DependOnABCDEF>().c, c);
|
||||
expect(container.resolve<DependOnABCDEF>().d, d);
|
||||
expect(container.resolve<DependOnABCDEF>().e, e);
|
||||
expect(container.resolve<DependOnABCDEF>().f, f);
|
||||
});
|
||||
|
||||
test("Bind to the factory resolves with 7 value", () {
|
||||
final container = DiContainer();
|
||||
final a = AA();
|
||||
final b = BB();
|
||||
final c = CC();
|
||||
final d = DD();
|
||||
final e = EE();
|
||||
final f = FF();
|
||||
final g = GG();
|
||||
container.bind<A>().toValue(a);
|
||||
container.bind<B>().toValue(b);
|
||||
container.bind<C>().toValue(c);
|
||||
container.bind<D>().toValue(d);
|
||||
container.bind<E>().toValue(e);
|
||||
container.bind<F>().toValue(f);
|
||||
container.bind<G>().toValue(g);
|
||||
container.bind<DependOnABCDEFG>().toFactory7<A, B, C, D, E, F, G>(
|
||||
(a, b, c, d, e, f, g) => DependOnABCDEFG(a, b, c, d, e, f, g));
|
||||
|
||||
expect(container.resolve<DependOnABCDEFG>().a, a);
|
||||
expect(container.resolve<DependOnABCDEFG>().b, b);
|
||||
expect(container.resolve<DependOnABCDEFG>().c, c);
|
||||
expect(container.resolve<DependOnABCDEFG>().d, d);
|
||||
expect(container.resolve<DependOnABCDEFG>().e, e);
|
||||
expect(container.resolve<DependOnABCDEFG>().f, f);
|
||||
expect(container.resolve<DependOnABCDEFG>().g, g);
|
||||
});
|
||||
|
||||
test("Bind to the factory resolves with 8 value", () {
|
||||
final container = DiContainer();
|
||||
final a = AA();
|
||||
final b = BB();
|
||||
final c = CC();
|
||||
final d = DD();
|
||||
final e = EE();
|
||||
final f = FF();
|
||||
final g = GG();
|
||||
final h = HH();
|
||||
container.bind<A>().toValue(a);
|
||||
container.bind<B>().toValue(b);
|
||||
container.bind<C>().toValue(c);
|
||||
container.bind<D>().toValue(d);
|
||||
container.bind<E>().toValue(e);
|
||||
container.bind<F>().toValue(f);
|
||||
container.bind<G>().toValue(g);
|
||||
container.bind<H>().toValue(h);
|
||||
container.bind<DependOnABCDEFGH>().toFactory8<A, B, C, D, E, F, G, H>(
|
||||
(a, b, c, d, e, f, g, h) => DependOnABCDEFGH(a, b, c, d, e, f, g, h));
|
||||
|
||||
expect(container.resolve<DependOnABCDEFGH>().a, a);
|
||||
expect(container.resolve<DependOnABCDEFGH>().b, b);
|
||||
expect(container.resolve<DependOnABCDEFGH>().c, c);
|
||||
expect(container.resolve<DependOnABCDEFGH>().d, d);
|
||||
expect(container.resolve<DependOnABCDEFGH>().e, e);
|
||||
expect(container.resolve<DependOnABCDEFGH>().f, f);
|
||||
expect(container.resolve<DependOnABCDEFGH>().g, g);
|
||||
expect(container.resolve<DependOnABCDEFGH>().h, h);
|
||||
});
|
||||
}
|
||||
|
||||
ResolverMock<T> _makeResolver<T>(T expectedValue) {
|
||||
final resolverMock = new ResolverMock<T>();
|
||||
when(resolverMock.resolve()).thenReturn(expectedValue);
|
||||
return resolverMock;
|
||||
}
|
||||
|
||||
class ResolverMock<T> extends Mock implements Resolver<T> {}
|
||||
|
||||
abstract class A {}
|
||||
|
||||
class AA implements A {}
|
||||
|
||||
abstract class B {}
|
||||
|
||||
class BB implements B {}
|
||||
|
||||
abstract class C {}
|
||||
|
||||
class CC implements C {}
|
||||
|
||||
abstract class D {}
|
||||
|
||||
class DD implements D {}
|
||||
|
||||
abstract class E {}
|
||||
|
||||
class EE implements E {}
|
||||
|
||||
abstract class F {}
|
||||
|
||||
class FF implements F {}
|
||||
|
||||
abstract class G {}
|
||||
|
||||
class GG implements G {}
|
||||
|
||||
abstract class H {}
|
||||
|
||||
class HH implements H {}
|
||||
|
||||
class DependOnA {
|
||||
final A a;
|
||||
|
||||
DependOnA(this.a) : assert(a != null);
|
||||
}
|
||||
|
||||
class DependOnAB {
|
||||
final A a;
|
||||
final B b;
|
||||
|
||||
DependOnAB(this.a, this.b) : assert(a != null && b != null);
|
||||
}
|
||||
|
||||
class DependOnABC {
|
||||
final A a;
|
||||
final B b;
|
||||
final C c;
|
||||
|
||||
DependOnABC(this.a, this.b, this.c)
|
||||
: assert(a != null && b != null && c != null);
|
||||
}
|
||||
|
||||
class DependOnABCD {
|
||||
final A a;
|
||||
final B b;
|
||||
final C c;
|
||||
final D d;
|
||||
|
||||
DependOnABCD(this.a, this.b, this.c, this.d)
|
||||
: assert(a != null && b != null && c != null && d != null);
|
||||
}
|
||||
|
||||
class DependOnABCDE {
|
||||
final A a;
|
||||
final B b;
|
||||
final C c;
|
||||
final D d;
|
||||
final E e;
|
||||
|
||||
DependOnABCDE(this.a, this.b, this.c, this.d, this.e)
|
||||
: assert(a != null && b != null && c != null && d != null && e != null);
|
||||
}
|
||||
|
||||
class DependOnABCDEF {
|
||||
final A a;
|
||||
final B b;
|
||||
final C c;
|
||||
final D d;
|
||||
final E e;
|
||||
final F f;
|
||||
|
||||
DependOnABCDEF(this.a, this.b, this.c, this.d, this.e, this.f)
|
||||
: assert(a != null &&
|
||||
b != null &&
|
||||
c != null &&
|
||||
d != null &&
|
||||
e != null &&
|
||||
f != null);
|
||||
}
|
||||
|
||||
class DependOnABCDEFG {
|
||||
final A a;
|
||||
final B b;
|
||||
final C c;
|
||||
final D d;
|
||||
final E e;
|
||||
final F f;
|
||||
final G g;
|
||||
|
||||
DependOnABCDEFG(this.a, this.b, this.c, this.d, this.e, this.f, this.g)
|
||||
: assert(a != null &&
|
||||
b != null &&
|
||||
c != null &&
|
||||
d != null &&
|
||||
e != null &&
|
||||
f != null &&
|
||||
g != null);
|
||||
}
|
||||
|
||||
class DependOnABCDEFGH {
|
||||
final A a;
|
||||
final B b;
|
||||
final C c;
|
||||
final D d;
|
||||
final E e;
|
||||
final F f;
|
||||
final G g;
|
||||
final H h;
|
||||
|
||||
DependOnABCDEFGH(
|
||||
this.a, this.b, this.c, this.d, this.e, this.f, this.g, this.h)
|
||||
: assert(a != null &&
|
||||
b != null &&
|
||||
c != null &&
|
||||
d != null &&
|
||||
e != null &&
|
||||
f != null &&
|
||||
g != null &&
|
||||
h != null);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import 'package:dart_di/resolvers/factory_resolver.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:mockito/mockito.dart' as mockito;
|
||||
|
||||
void main() {
|
||||
test('Factory resolver resolves with factory', () {
|
||||
const expected = 3;
|
||||
final factoryResolver = new FactoryResolver(() => expected);
|
||||
|
||||
expect(factoryResolver.resolve(), expected);
|
||||
});
|
||||
|
||||
test('Factory creates value only after resolve() call', () {
|
||||
final spy = new SpyMock();
|
||||
final factoryResolver = new FactoryResolver(() => spy.onFactory());
|
||||
|
||||
mockito.verifyNever(spy.onFactory());
|
||||
factoryResolver.resolve();
|
||||
mockito.verify(spy.onFactory());
|
||||
});
|
||||
}
|
||||
|
||||
abstract class Spy {
|
||||
void onFactory();
|
||||
}
|
||||
|
||||
class SpyMock extends mockito.Mock implements Spy {}
|
||||
@@ -1,36 +0,0 @@
|
||||
import 'package:dart_di/resolvers/factory_resolver.dart';
|
||||
import 'package:dart_di/resolvers/singelton_resolver.dart';
|
||||
import 'package:test/test.dart';
|
||||
import 'package:mockito/mockito.dart' as mockito;
|
||||
|
||||
void main() {
|
||||
test(
|
||||
'Not singleton resolver resolves different values after multiple resolve() calls',
|
||||
() {
|
||||
const callCount = 3;
|
||||
final spy = new SpyMock();
|
||||
final factoryResolver = new FactoryResolver(() => spy..onFactory());
|
||||
|
||||
for (var i = 0; i < callCount; i++) factoryResolver.resolve();
|
||||
|
||||
mockito.verify(spy.onFactory()).called(callCount);
|
||||
});
|
||||
|
||||
test('Singleton resolver resolves same value after multiple resolve() calls',
|
||||
() {
|
||||
const callCount = 3;
|
||||
final spy = new SpyMock();
|
||||
final singletonResolver =
|
||||
new SingletonResolver(new FactoryResolver(() => spy..onFactory()));
|
||||
|
||||
for (var i = 0; i < callCount; i++) singletonResolver.resolve();
|
||||
|
||||
mockito.verify(spy.onFactory()).called(1);
|
||||
});
|
||||
}
|
||||
|
||||
abstract class Spy {
|
||||
void onFactory();
|
||||
}
|
||||
|
||||
class SpyMock extends mockito.Mock implements Spy {}
|
||||
@@ -1,11 +0,0 @@
|
||||
import 'package:dart_di/resolvers/value_resolver.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
test('Value resolver resolves with selected value', () {
|
||||
var a = 3;
|
||||
final valResolver = new ValueResolver(a);
|
||||
|
||||
expect(valResolver.resolve(), a);
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:dart_di/experimental/module.dart';
|
||||
import 'package:dart_di/experimental/scope.dart';
|
||||
import 'package:dart_di/module.dart';
|
||||
import 'package:dart_di/scope.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
Reference in New Issue
Block a user