2021-04-28 09:30:32 +03:00
|
|
|
///
|
|
|
|
|
/// Copyright 2021 Sergey Penkovsky <sergey.penkovsky@gmail.com>
|
|
|
|
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
/// 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
|
|
|
|
|
/// Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
/// See the License for the specific language governing permissions and
|
|
|
|
|
/// limitations under the License.
|
|
|
|
|
///
|
2021-04-26 10:40:27 +03:00
|
|
|
|
2021-04-21 08:05:38 +03:00
|
|
|
import 'dart:collection';
|
|
|
|
|
|
2021-04-26 14:56:09 +03:00
|
|
|
import 'package:cherrypick/binding.dart';
|
|
|
|
|
import 'package:cherrypick/module.dart';
|
2021-04-21 08:05:38 +03:00
|
|
|
|
|
|
|
|
Scope openRootScope() => Scope(null);
|
|
|
|
|
|
|
|
|
|
class Scope {
|
|
|
|
|
final Scope? _parentScope;
|
|
|
|
|
|
2021-04-22 10:25:38 +03:00
|
|
|
/// RU: Метод возвращает родительский [Scope].
|
|
|
|
|
///
|
|
|
|
|
/// ENG: The method returns the parent [Scope].
|
|
|
|
|
///
|
|
|
|
|
/// return [Scope]
|
2021-04-21 08:05:38 +03:00
|
|
|
Scope? get parentScope => _parentScope;
|
|
|
|
|
|
|
|
|
|
final Map<String, Scope> _scopeMap = HashMap();
|
|
|
|
|
|
|
|
|
|
Scope(this._parentScope);
|
|
|
|
|
|
|
|
|
|
final Set<Module> _modulesList = HashSet();
|
|
|
|
|
|
2021-04-22 10:25:38 +03:00
|
|
|
/// RU: Метод открывает дочерний (дополнительный) [Scope].
|
|
|
|
|
///
|
|
|
|
|
/// ENG: The method opens child (additional) [Scope].
|
|
|
|
|
///
|
|
|
|
|
/// return [Scope]
|
2021-04-21 08:05:38 +03:00
|
|
|
Scope openSubScope(String name) {
|
|
|
|
|
if (!_scopeMap.containsKey(name)) {
|
2021-04-23 10:34:33 +03:00
|
|
|
_scopeMap[name] = Scope(this);
|
2021-04-21 08:05:38 +03:00
|
|
|
}
|
|
|
|
|
return _scopeMap[name]!;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 10:25:38 +03:00
|
|
|
/// RU: Метод закрывает дочерний (дополнительный) [Scope].
|
|
|
|
|
///
|
|
|
|
|
/// ENG: The method closes child (additional) [Scope].
|
|
|
|
|
///
|
|
|
|
|
/// return [Scope]
|
2021-04-21 08:05:38 +03:00
|
|
|
void closeSubScope(String name) {
|
|
|
|
|
_scopeMap.remove(name);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 10:25:38 +03:00
|
|
|
/// RU: Метод инициализирует пользовательские модули в [Scope].
|
|
|
|
|
///
|
|
|
|
|
/// ENG: The method initializes custom modules in [Scope].
|
|
|
|
|
///
|
|
|
|
|
/// return [Scope]
|
2021-04-21 08:05:38 +03:00
|
|
|
Scope installModules(List<Module> modules) {
|
|
|
|
|
_modulesList.addAll(modules);
|
|
|
|
|
modules.forEach((module) => module.builder(this));
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 10:25:38 +03:00
|
|
|
/// RU: Метод удаляет пользовательские модули из [Scope].
|
|
|
|
|
///
|
|
|
|
|
/// ENG: This method removes custom modules from [Scope].
|
|
|
|
|
///
|
|
|
|
|
/// return [Scope]
|
2021-04-21 08:05:38 +03:00
|
|
|
Scope dropModules() {
|
|
|
|
|
_modulesList.removeAll(_modulesList);
|
|
|
|
|
return this;
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 10:25:38 +03:00
|
|
|
/// RU: Возвращает найденную зависимость, определенную параметром типа [T].
|
|
|
|
|
/// Выдает [StateError], если зависимость не может быть разрешена.
|
|
|
|
|
/// Если вы хотите получить [null], если зависимость не может быть найдена,
|
|
|
|
|
/// то используйте вместо этого [tryResolve]
|
|
|
|
|
/// return - возвращает объект типа [T] или [StateError]
|
|
|
|
|
///
|
|
|
|
|
/// ENG: Returns the found dependency specified by the type parameter [T].
|
|
|
|
|
/// Throws [StateError] if the dependency cannot be resolved.
|
|
|
|
|
/// If you want to get [null] if the dependency cannot be found then use [tryResolve] instead
|
|
|
|
|
/// return - returns an object of type [T] or [StateError]
|
|
|
|
|
///
|
2021-04-21 08:05:38 +03:00
|
|
|
T resolve<T>({String? named}) {
|
|
|
|
|
var resolved = tryResolve<T>(named: named);
|
|
|
|
|
if (resolved != null) {
|
|
|
|
|
return resolved;
|
|
|
|
|
} else {
|
|
|
|
|
throw StateError(
|
|
|
|
|
'Can\'t resolve dependency `$T`. Maybe you forget register it?');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-22 10:25:38 +03:00
|
|
|
/// RU: Возвращает найденную зависимость типа [T] или null, если она не может быть найдена.
|
|
|
|
|
/// ENG: Returns found dependency of type [T] or null if it cannot be found.
|
|
|
|
|
///
|
2021-04-21 08:05:38 +03:00
|
|
|
T? tryResolve<T>({String? named}) {
|
|
|
|
|
// 1 Поиск зависимости по всем модулям текущего скоупа
|
|
|
|
|
if (_modulesList.isNotEmpty) {
|
2021-04-29 10:02:32 +03:00
|
|
|
for (var module in _modulesList) {
|
|
|
|
|
for (var binding in module.bindingSet) {
|
2021-04-21 08:05:38 +03:00
|
|
|
if (binding.key == T &&
|
|
|
|
|
((!binding.isNamed && named == null) ||
|
|
|
|
|
(binding.isNamed && named == binding.name))) {
|
|
|
|
|
switch (binding.mode) {
|
|
|
|
|
case Mode.INSTANCE:
|
|
|
|
|
return binding.instance;
|
|
|
|
|
case Mode.PROVIDER_INSTANCE:
|
|
|
|
|
return binding.isSingeltone
|
|
|
|
|
? binding.instance
|
|
|
|
|
: binding.provider;
|
|
|
|
|
default:
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2 Поиск зависимостей в родительском скоупе
|
2021-04-21 08:25:55 +03:00
|
|
|
return _parentScope != null ? _parentScope!.tryResolve(named: named) : null;
|
2021-04-21 08:05:38 +03:00
|
|
|
}
|
|
|
|
|
}
|