Updated Angel Container to Null Safety

This commit is contained in:
thomashii 2021-03-18 08:21:42 +08:00
parent 5a1782efba
commit aefe1f1ab8
12 changed files with 79 additions and 78 deletions

View file

@ -3,10 +3,11 @@
* Updated pretty_logging to 3.0.0
* Updated angel_http_exception to 3.0.0
* Moved angel_cli to https://github.com/dukefirehawk/cli
* Added code_buffer 2.0.0
* Added combinator 2.0.0
* Added code_buffer and updated to 2.0.0
* Added combinator and updated to 2.0.0
* Updated angel_route to 5.0.0
* Updated angel_model to 3.0.0
* Updated angel_container to 3.0.0
# 3.0.0 (Non NNBD)
* Changed Dart SDK requirements for all packages to ">=2.10.0 <3.0.0"

View file

@ -21,14 +21,14 @@ Future<void> main() async {
});
// Use `make` to create an instance.
var truck = container.make<Truck>();
var truck = container.make<Truck>()!;
// You can also resolve injections asynchronously.
container.registerFactory<Future<int>>((_) async => 24);
print(await container.makeAsync<int>());
// Asynchronous resolution also works for plain objects.
await container.makeAsync<Truck>().then((t) => t.drive());
await container.makeAsync<Truck>()!.then((t) => t.drive());
// Register a named singleton.
container.registerNamedSingleton('the_truck', truck);
@ -37,7 +37,7 @@ Future<void> main() async {
truck.drive();
// Should print the same.
container.findByName<Truck>('the_truck').drive();
container.findByName<Truck>('the_truck')!.drive();
// We can make a child container with its own factory.
var childContainer = container.createChild();
@ -47,10 +47,10 @@ Future<void> main() async {
});
// Make a truck with 5666 HP.
childContainer.make<Truck>().drive();
childContainer.make<Truck>()!.drive();
// However, calling `make<Engine>` will return the Engine singleton we created above.
print(childContainer.make<Engine>().horsePower);
print(childContainer.make<Engine>()!.horsePower);
}
abstract class Truck {
@ -64,12 +64,12 @@ class Engine {
}
class _TruckImpl implements Truck {
final Engine engine;
final Engine? engine;
_TruckImpl(this.engine);
@override
void drive() {
print('Vroom! I have ${engine.horsePower} horsepower in my engine.');
print('Vroom! I have ${engine!.horsePower} horsepower in my engine.');
}
}

View file

@ -7,11 +7,11 @@ class Container {
final Map<Type, dynamic> _singletons = {};
final Map<Type, dynamic Function(Container)> _factories = {};
final Map<String, dynamic> _namedSingletons = {};
final Container _parent;
final Container? _parent;
Container(this.reflector) : _parent = null;
Container._child(this._parent) : reflector = _parent.reflector;
Container._child(Container this._parent) : reflector = _parent.reflector;
bool get isRoot => _parent == null;
@ -23,8 +23,8 @@ class Container {
}
/// Determines if the container has an injection of the given type.
bool has<T>([Type t]) {
var search = this;
bool has<T>([Type? t]) {
Container? search = this;
t ??= T == dynamic ? t : T;
while (search != null) {
@ -42,7 +42,7 @@ class Container {
/// Determines if the container has a named singleton with the given [name].
bool hasNamed(String name) {
var search = this;
Container? search = this;
while (search != null) {
if (search._namedSingletons.containsKey(name)) {
@ -59,9 +59,9 @@ class Container {
///
/// It is similar to [make], but resolves an injection of either
/// `Future<T>` or `T`.
Future<T> makeAsync<T>([Type type]) {
Future<T>? makeAsync<T>([Type? type]) {
type ??= T;
Type futureType; //.Future<T>.value(null).runtimeType;
Type? futureType; //.Future<T>.value(null).runtimeType;
if (T == dynamic) {
try {
@ -87,18 +87,18 @@ class Container {
///
/// In contexts where a static generic type cannot be used, use
/// the [type] argument, instead of [T].
T make<T>([Type type]) {
T? make<T>([Type? type]) {
type ??= T;
var search = this;
Container? search = this;
while (search != null) {
if (search._singletons.containsKey(type)) {
// Find a singleton, if any.
return search._singletons[type] as T;
return search._singletons[type] as T?;
} else if (search._factories.containsKey(type)) {
// Find a factory, if any.
return search._factories[type](this) as T;
return search._factories[type]!(this) as T?;
} else {
search = search._parent;
}
@ -115,8 +115,8 @@ class Container {
var constructor = reflectedType.constructors.firstWhere(
(c) => isDefault(c.name),
orElse: () => throw ReflectionException(
'${reflectedType.name} has no default constructor, and therefore cannot be instantiated.'));
orElse: (() => throw ReflectionException(
'${reflectedType.name} has no default constructor, and therefore cannot be instantiated.')) as ReflectedFunction Function()?);
for (var param in constructor.parameters) {
var value = make(param.type.reflectedType);
@ -131,7 +131,7 @@ class Container {
return reflectedType.newInstance(
isDefault(constructor.name) ? '' : constructor.name,
positional,
named, []).reflectee as T;
named, []).reflectee as T?;
} else {
throw ReflectionException(
'$type is not a class, and therefore cannot be instantiated.');
@ -144,7 +144,7 @@ class Container {
///
/// Returns [f].
T Function(Container) registerLazySingleton<T>(T Function(Container) f,
{Type as}) {
{Type? as}) {
return registerFactory<T>(
(container) {
var r = f(container);
@ -159,7 +159,7 @@ class Container {
/// type within *this* container will return the result of [f].
///
/// Returns [f].
T Function(Container) registerFactory<T>(T Function(Container) f, {Type as}) {
T Function(Container) registerFactory<T>(T Function(Container) f, {Type? as}) {
as ??= T;
if (_factories.containsKey(as)) {
@ -174,7 +174,7 @@ class Container {
/// type within *this* container will return [object].
///
/// Returns [object].
T registerSingleton<T>(T object, {Type as}) {
T registerSingleton<T>(T object, {Type? as}) {
as ??= T == dynamic ? as : T;
if (_singletons.containsKey(as ?? object.runtimeType)) {
@ -192,11 +192,11 @@ class Container {
///
/// [findByName] is best reserved for internal logic that end users of code should
/// not see.
T findByName<T>(String name) {
T? findByName<T>(String name) {
if (_namedSingletons.containsKey(name)) {
return _namedSingletons[name] as T;
return _namedSingletons[name] as T?;
} else if (_parent != null) {
return _parent.findByName<T>(name);
return _parent!.findByName<T>(name);
} else {
throw StateError(
'This container does not have a singleton named "$name".');

View file

@ -1,6 +1,6 @@
import '../../angel_container.dart';
final Map<Symbol, String> _symbolNames = <Symbol, String>{};
final Map<Symbol, String?> _symbolNames = <Symbol, String?>{};
/// A [Reflector] implementation that performs no actual reflection,
/// instead returning empty objects on every invocation.
@ -13,9 +13,9 @@ class EmptyReflector extends Reflector {
const EmptyReflector();
@override
String getName(Symbol symbol) {
String? getName(Symbol symbol) {
return _symbolNames.putIfAbsent(
symbol, () => symbolRegex.firstMatch(symbol.toString()).group(1));
symbol, () => symbolRegex.firstMatch(symbol.toString())!.group(1));
}
@override
@ -52,13 +52,13 @@ class _EmptyReflectedClass extends ReflectedClass {
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
[Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
throw UnsupportedError(
'Classes reflected via an EmptyReflector cannot be instantiated.');
}
@override
bool isAssignableTo(ReflectedType other) {
bool isAssignableTo(ReflectedType? other) {
return other == this;
}
@ -75,13 +75,13 @@ class _EmptyReflectedType extends ReflectedType {
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
[Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
throw UnsupportedError(
'Types reflected via an EmptyReflector cannot be instantiated.');
}
@override
bool isAssignableTo(ReflectedType other) {
bool isAssignableTo(ReflectedType? other) {
return other == this;
}

View file

@ -85,7 +85,7 @@ class _ReflectedTypeMirror extends ReflectedType {
);
@override
bool isAssignableTo(ReflectedType other) {
bool isAssignableTo(ReflectedType? other) {
if (other is _ReflectedClassMirror) {
return mirror.isAssignableTo(other.mirror);
} else if (other is _ReflectedTypeMirror) {
@ -98,7 +98,7 @@ class _ReflectedTypeMirror extends ReflectedType {
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
[Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
throw ReflectionException(
'$name is not a class, and therefore cannot be instantiated.');
}
@ -154,7 +154,7 @@ class _ReflectedClassMirror extends ReflectedClass {
List<ReflectedFunction> get constructors => _constructorsOf(mirror);
@override
bool isAssignableTo(ReflectedType other) {
bool isAssignableTo(ReflectedType? other) {
if (other is _ReflectedClassMirror) {
return mirror.isAssignableTo(other.mirror);
} else if (other is _ReflectedTypeMirror) {
@ -167,7 +167,7 @@ class _ReflectedClassMirror extends ReflectedClass {
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
[Map<String, dynamic>? namedArguments, List<Type>? typeArguments]) {
return _ReflectedInstanceMirror(
mirror.newInstance(Symbol(constructorName), positionalArguments));
}
@ -207,7 +207,7 @@ class _ReflectedInstanceMirror extends ReflectedInstance {
class _ReflectedMethodMirror extends ReflectedFunction {
final dart.MethodMirror mirror;
final dart.ClosureMirror closureMirror;
final dart.ClosureMirror? closureMirror;
_ReflectedMethodMirror(this.mirror, [this.closureMirror])
: super(
@ -242,7 +242,7 @@ class _ReflectedMethodMirror extends ReflectedFunction {
'This object was reflected without a ClosureMirror, and therefore cannot be directly invoked.');
}
return _ReflectedInstanceMirror(closureMirror.invoke(invocation.memberName,
return _ReflectedInstanceMirror(closureMirror!.invoke(invocation.memberName,
invocation.positionalArguments, invocation.namedArguments));
}
}

View file

@ -4,15 +4,15 @@ import 'package:quiver/core.dart';
abstract class Reflector {
const Reflector();
String getName(Symbol symbol);
String? getName(Symbol symbol);
ReflectedClass reflectClass(Type clazz);
ReflectedClass? reflectClass(Type clazz);
ReflectedFunction reflectFunction(Function function);
ReflectedFunction? reflectFunction(Function function);
ReflectedType reflectType(Type type);
ReflectedType? reflectType(Type type);
ReflectedInstance reflectInstance(Object object);
ReflectedInstance? reflectInstance(Object object);
ReflectedType reflectFutureOf(Type type) {
throw UnsupportedError('`reflectFutureOf` requires `dart:mirrors`.');
@ -22,7 +22,7 @@ abstract class Reflector {
abstract class ReflectedInstance {
final ReflectedType type;
final ReflectedClass clazz;
final Object reflectee;
final Object? reflectee;
const ReflectedInstance(this.type, this.clazz, this.reflectee);
@ -56,9 +56,9 @@ abstract class ReflectedType {
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]);
[Map<String, dynamic>? namedArguments, List<Type>? typeArguments]);
bool isAssignableTo(ReflectedType other);
bool isAssignableTo(ReflectedType? other);
}
abstract class ReflectedClass extends ReflectedType {
@ -94,7 +94,7 @@ abstract class ReflectedClass extends ReflectedType {
class ReflectedDeclaration {
final String name;
final bool isStatic;
final ReflectedFunction function;
final ReflectedFunction? function;
const ReflectedDeclaration(this.name, this.isStatic, this.function);

View file

@ -16,7 +16,7 @@ class StaticReflector extends Reflector {
this.instances = const {}});
@override
String getName(Symbol symbol) {
String? getName(Symbol symbol) {
if (!names.containsKey(symbol)) {
throw ArgumentError(
'The value of $symbol is unknown - it was not generated.');
@ -26,11 +26,11 @@ class StaticReflector extends Reflector {
}
@override
ReflectedClass reflectClass(Type clazz) =>
reflectType(clazz) as ReflectedClass;
ReflectedClass? reflectClass(Type clazz) =>
reflectType(clazz) as ReflectedClass?;
@override
ReflectedFunction reflectFunction(Function function) {
ReflectedFunction? reflectFunction(Function function) {
if (!functions.containsKey(function)) {
throw ArgumentError(
'There is no reflection information available about $function.');
@ -40,7 +40,7 @@ class StaticReflector extends Reflector {
}
@override
ReflectedInstance reflectInstance(Object object) {
ReflectedInstance? reflectInstance(Object object) {
if (!instances.containsKey(object)) {
throw ArgumentError(
'There is no reflection information available about $object.');
@ -50,7 +50,7 @@ class StaticReflector extends Reflector {
}
@override
ReflectedType reflectType(Type type) {
ReflectedType? reflectType(Type type) {
if (!types.containsKey(type)) {
throw ArgumentError(
'There is no reflection information available about $type.');

View file

@ -17,7 +17,7 @@ class ThrowingReflector extends Reflector {
const ThrowingReflector({this.errorMessage = defaultErrorMessage});
@override
String getName(Symbol symbol) => const EmptyReflector().getName(symbol);
String? getName(Symbol symbol) => const EmptyReflector().getName(symbol);
UnsupportedError _error() => UnsupportedError(errorMessage);

View file

@ -1,13 +1,13 @@
name: angel_container
version: 2.0.0
version: 3.0.0
author: Tobe O <thosakwe@gmail.com>
description: A hierarchical DI container, and pluggable backends for reflection.
homepage: https://github.com/angel-dart/container.git
environment:
sdk: ">=2.10.0 <3.0.0"
sdk: '>=2.12.0 <3.0.0'
dependencies:
collection: ^1.15.0
quiver: ^2.1.5
quiver: ^3.0.0
dev_dependencies:
pedantic: ^1.11.0
test: ^1.16.5
test: ^1.16.8

View file

@ -7,7 +7,7 @@ void returnVoidFromAFunction(int x) {}
void testReflector(Reflector reflector) {
var blaziken = Pokemon('Blaziken', PokemonType.fire);
Container container;
late Container container;
setUp(() {
container = Container(reflector);
@ -16,7 +16,7 @@ void testReflector(Reflector reflector) {
});
test('get field', () {
var blazikenMirror = reflector.reflectInstance(blaziken);
var blazikenMirror = reflector.reflectInstance(blaziken)!;
expect(blazikenMirror.getField('type').reflectee, blaziken.type);
});
@ -24,19 +24,19 @@ void testReflector(Reflector reflector) {
var mirror = reflector.reflectFunction(returnVoidFromAFunction);
test('void return type returns dynamic', () {
expect(mirror.returnType, reflector.reflectType(dynamic));
expect(mirror!.returnType, reflector.reflectType(dynamic));
});
test('counts parameters', () {
expect(mirror.parameters, hasLength(1));
expect(mirror!.parameters, hasLength(1));
});
test('counts types parameters', () {
expect(mirror.typeParameters, isEmpty);
expect(mirror!.typeParameters, isEmpty);
});
test('correctly reflects parameter types', () {
var p = mirror.parameters[0];
var p = mirror!.parameters[0];
expect(p.name, 'x');
expect(p.isRequired, true);
expect(p.isNamed, false);
@ -67,12 +67,12 @@ void testReflector(Reflector reflector) {
});
test('constructor injects singleton', () {
var lower = container.make<LowerPokemon>();
var lower = container.make<LowerPokemon>()!;
expect(lower.lowercaseName, blaziken.name.toLowerCase());
});
test('newInstance works', () {
var type = container.reflector.reflectType(Pokemon);
var type = container.reflector.reflectType(Pokemon)!;
var instance =
type.newInstance('changeName', [blaziken, 'Charizard']).reflectee
as Pokemon;
@ -83,7 +83,7 @@ void testReflector(Reflector reflector) {
test('isAssignableTo', () {
var pokemonType = container.reflector.reflectType(Pokemon);
var kantoPokemonType = container.reflector.reflectType(KantoPokemon);
var kantoPokemonType = container.reflector.reflectType(KantoPokemon)!;
expect(kantoPokemonType.isAssignableTo(pokemonType), true);
expect(

View file

@ -2,7 +2,7 @@ import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart';
void main() {
Container container;
late Container container;
setUp(() {
container = Container(const EmptyReflector())
@ -37,14 +37,14 @@ void main() {
}
class Artist {
final String name;
final Song song;
final String? name;
final Song? song;
Artist({this.name, this.song});
}
class Song {
final String title;
final String? title;
Song({this.title});
}

View file

@ -2,7 +2,7 @@ import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart';
void main() {
Container container;
late Container container;
setUp(() {
container = Container(const EmptyReflector());
@ -10,7 +10,7 @@ void main() {
});
test('fetch by name', () {
expect(container.findByName<Foo>('foo').bar, 'baz');
expect(container.findByName<Foo>('foo')!.bar, 'baz');
});
test('cannot redefine', () {
@ -28,7 +28,7 @@ void main() {
}
class Foo {
final String bar;
final String? bar;
Foo({this.bar});
}