Add 'packages/container/' from commit 'a7eb96a391cced0f9b2d6a9fbaffc3483c2558eb'

git-subtree-dir: packages/container
git-subtree-mainline: dd33154af1
git-subtree-split: a7eb96a391
This commit is contained in:
Tobe O 2020-02-15 18:22:26 -05:00
commit 9c36a7e981
37 changed files with 7100 additions and 0 deletions

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 The Angel Framework
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,2 @@
# container
A better IoC container for Angel, ultimately allowing Angel to be used without dart:mirrors.

View file

@ -0,0 +1,13 @@
# See https://www.dartlang.org/guides/libraries/private-files
# Files and directories created by pub
.dart_tool/
.packages
.pub/
build/
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/

View file

@ -0,0 +1,65 @@
# 1.1.0
* `pedantic` lints.
* Add `ThrowingReflector`, which throws on all operations.
* `EmptyReflector` uses `Object` instead of `dynamic` as its returned
type, as the `dynamic` type is (apparently?) no longer a valid constant value.
* `registerSingleton` now returns the provided `object`.
* `registerFactory` and `registerLazySingleton` now return the provided function `f`.
# 1.0.4
* Slight patch to prevent annoying segfault.
# 1.0.3
* Added `Future` support to `Reflector`.
# 1.0.2
* Added `makeAsync<T>`.
# 1.0.1
* Added `hasNamed`.
# 1.0.0
* Removed `@GenerateReflector`.
# 1.0.0-alpha.12
* `StaticReflector` now defaults to empty arguments.
# 1.0.0-alpha.11
* Added `StaticReflector`.
# 1.0.0-alpha.10
* Added `Container.registerLazySingleton<T>`.
* Added named singleton support.
# 1.0.0-alpha.9
* Added `Container.has<T>`.
# 1.0.0-alpha.8
* Fixed a bug where `_ReflectedTypeInstance.isAssignableTo` always failed.
* Added `@GenerateReflector` annotation.
# 1.0.0-alpha.7
* Add `EmptyReflector`.
* `ReflectedType.newInstance` now returns a `ReflectedInstance`.
* Moved `ReflectedInstance.invoke` to `ReflectedFunction.invoke`.
# 1.0.0-alpha.6
* Add `getField` to `ReflectedInstance`.
# 1.0.0-alpha.5
* Remove concrete type from `ReflectedTypeParameter`.
# 1.0.0-alpha.4
* Safely handle `void` return types of methods.
# 1.0.0-alpha.3
* Reflecting `void` in `MirrorsReflector` now forwards to `dynamic`.
# 1.0.0-alpha.2
* Added `ReflectedInstance.reflectee`.
# 1.0.0-alpha.1
* Allow omission of the first argument of `Container.make`, to use
a generic type argument instead.
* `singleton` -> `registerSingleton`
* Add `createChild`, and support hierarchical containers.

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 The Angel Framework
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,2 @@
# container
A better IoC container for Angel, ultimately allowing Angel to be used without dart:mirrors.

View file

@ -0,0 +1,4 @@
include: package:pedantic/analysis_options.yaml
analyzer:
strong-mode:
implicit-casts: false

View file

@ -0,0 +1,75 @@
import 'dart:async';
import 'package:angel_container/angel_container.dart';
import 'package:angel_container/mirrors.dart';
Future<void> main() async {
// Create a container instance.
var container = Container(const MirrorsReflector());
// Register a singleton.
container.registerSingleton<Engine>(Engine(40));
// You can also omit the type annotation, in which the object's runtime type will be used.
// If you're injecting an abstract class, prefer the type annotation.
//
// container.registerSingleton(Engine(40));
// Register a factory that creates a truck.
container.registerFactory<Truck>((container) {
return _TruckImpl(container.make<Engine>());
});
// Use `make` to create an instance.
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());
// Register a named singleton.
container.registerNamedSingleton('the_truck', truck);
// Should print: 'Vroom! I have 40 horsepower in my engine.'
truck.drive();
// Should print the same.
container.findByName<Truck>('the_truck').drive();
// We can make a child container with its own factory.
var childContainer = container.createChild();
childContainer.registerFactory<Truck>((container) {
return _TruckImpl(Engine(5666));
});
// Make a truck with 5666 HP.
childContainer.make<Truck>().drive();
// However, calling `make<Engine>` will return the Engine singleton we created above.
print(childContainer.make<Engine>().horsePower);
}
abstract class Truck {
void drive();
}
class Engine {
final int horsePower;
Engine(this.horsePower);
}
class _TruckImpl implements Truck {
final Engine engine;
_TruckImpl(this.engine);
@override
void drive() {
print('Vroom! I have ${engine.horsePower} horsepower in my engine.');
}
}

View file

@ -0,0 +1,6 @@
import 'package:angel_container/angel_container.dart';
void main() {
var reflector = const ThrowingReflector();
reflector.reflectClass(StringBuffer);
}

View file

@ -0,0 +1,8 @@
library angel_container;
export 'src/container.dart';
export 'src/empty/empty.dart';
export 'src/static/static.dart';
export 'src/exception.dart';
export 'src/reflector.dart';
export 'src/throwing.dart';

View file

@ -0,0 +1 @@
export 'src/mirrors/mirrors.dart';

View file

@ -0,0 +1,218 @@
import 'dart:async';
import 'exception.dart';
import 'reflector.dart';
class Container {
final Reflector reflector;
final Map<Type, dynamic> _singletons = {};
final Map<Type, dynamic Function(Container)> _factories = {};
final Map<String, dynamic> _namedSingletons = {};
final Container _parent;
Container(this.reflector) : _parent = null;
Container._child(this._parent) : reflector = _parent.reflector;
bool get isRoot => _parent == null;
/// Creates a child [Container] that can define its own singletons and factories.
///
/// Use this to create children of a global "scope."
Container createChild() {
return Container._child(this);
}
/// Determines if the container has an injection of the given type.
bool has<T>([Type t]) {
var search = this;
t ??= T == dynamic ? t : T;
while (search != null) {
if (search._singletons.containsKey(t)) {
return true;
} else if (search._factories.containsKey(t)) {
return true;
} else {
search = search._parent;
}
}
return false;
}
/// Determines if the container has a named singleton with the given [name].
bool hasNamed(String name) {
var search = this;
while (search != null) {
if (search._namedSingletons.containsKey(name)) {
return true;
} else {
search = search._parent;
}
}
return false;
}
/// Instantiates an instance of [T], asynchronously.
///
/// It is similar to [make], but resolves an injection of either
/// `Future<T>` or `T`.
Future<T> makeAsync<T>([Type type]) {
type ??= T;
Type futureType; //.Future<T>.value(null).runtimeType;
if (T == dynamic) {
try {
futureType = reflector.reflectFutureOf(type).reflectedType;
} on UnsupportedError {
// Ignore this.
}
}
if (has<T>(type)) {
return Future<T>.value(make(type));
} else if (has<Future<T>>()) {
return make<Future<T>>();
} else if (futureType != null) {
return make(futureType);
} else {
throw ReflectionException(
'No injection for Future<$type> or $type was found.');
}
}
/// Instantiates an instance of [T].
///
/// In contexts where a static generic type cannot be used, use
/// the [type] argument, instead of [T].
T make<T>([Type type]) {
type ??= T;
var search = this;
while (search != null) {
if (search._singletons.containsKey(type)) {
// Find a singleton, if any.
return search._singletons[type] as T;
} else if (search._factories.containsKey(type)) {
// Find a factory, if any.
return search._factories[type](this) as T;
} else {
search = search._parent;
}
}
var reflectedType = reflector.reflectType(type);
var positional = [];
var named = <String, dynamic>{};
if (reflectedType is ReflectedClass) {
bool isDefault(String name) {
return name.isEmpty || name == reflectedType.name;
}
var constructor = reflectedType.constructors.firstWhere(
(c) => isDefault(c.name),
orElse: () => throw ReflectionException(
'${reflectedType.name} has no default constructor, and therefore cannot be instantiated.'));
for (var param in constructor.parameters) {
var value = make(param.type.reflectedType);
if (param.isNamed) {
named[param.name] = value;
} else {
positional.add(value);
}
}
return reflectedType.newInstance(
isDefault(constructor.name) ? '' : constructor.name,
positional,
named, []).reflectee as T;
} else {
throw ReflectionException(
'$type is not a class, and therefore cannot be instantiated.');
}
}
/// Shorthand for registering a factory that injects a singleton when it runs.
///
/// In many cases, you might prefer this to [registerFactory].
///
/// Returns [f].
T Function(Container) registerLazySingleton<T>(T Function(Container) f,
{Type as}) {
return registerFactory<T>(
(container) {
var r = f(container);
container.registerSingleton<T>(r, as: as);
return r;
},
as: as,
);
}
/// Registers a factory. Any attempt to resolve the
/// type within *this* container will return the result of [f].
///
/// Returns [f].
T Function(Container) registerFactory<T>(T Function(Container) f, {Type as}) {
as ??= T;
if (_factories.containsKey(as)) {
throw StateError('This container already has a factory for $as.');
}
_factories[as] = f;
return f;
}
/// Registers a singleton. Any attempt to resolve the
/// type within *this* container will return [object].
///
/// Returns [object].
T registerSingleton<T>(T object, {Type as}) {
as ??= T == dynamic ? as : T;
if (_singletons.containsKey(as ?? object.runtimeType)) {
throw StateError(
'This container already has a singleton for ${as ?? object.runtimeType}.');
}
_singletons[as ?? object.runtimeType] = object;
return object;
}
/// Finds a named singleton.
///
/// In general, prefer using [registerSingleton] and [registerFactory].
///
/// [findByName] is best reserved for internal logic that end users of code should
/// not see.
T findByName<T>(String name) {
if (_namedSingletons.containsKey(name)) {
return _namedSingletons[name] as T;
} else if (_parent != null) {
return _parent.findByName<T>(name);
} else {
throw StateError(
'This container does not have a singleton named "$name".');
}
}
/// Registers a *named* singleton.
///
/// Note that this is not related to type-based injections, and exists as a mechanism
/// to enable injecting multiple instances of a type within the same container hierarchy.
T registerNamedSingleton<T>(String name, T object) {
if (_namedSingletons.containsKey(name)) {
throw StateError('This container already has a singleton named "$name".');
}
_namedSingletons[name] = object;
return object;
}
}

View file

@ -0,0 +1,126 @@
import 'package:angel_container/angel_container.dart';
final Map<Symbol, String> _symbolNames = <Symbol, String>{};
/// A [Reflector] implementation that performs no actual reflection,
/// instead returning empty objects on every invocation.
///
/// Use this in contexts where you know you won't need any reflective capabilities.
class EmptyReflector extends Reflector {
/// A [RegExp] that can be used to extract the name of a symbol without reflection.
static final RegExp symbolRegex = RegExp(r'Symbol\("([^"]+)"\)');
const EmptyReflector();
@override
String getName(Symbol symbol) {
return _symbolNames.putIfAbsent(
symbol, () => symbolRegex.firstMatch(symbol.toString()).group(1));
}
@override
ReflectedClass reflectClass(Type clazz) {
return const _EmptyReflectedClass();
}
@override
ReflectedInstance reflectInstance(Object object) {
return const _EmptyReflectedInstance();
}
@override
ReflectedType reflectType(Type type) {
return const _EmptyReflectedType();
}
@override
ReflectedFunction reflectFunction(Function function) {
return const _EmptyReflectedFunction();
}
}
class _EmptyReflectedClass extends ReflectedClass {
const _EmptyReflectedClass()
: super(
'(empty)',
const <ReflectedTypeParameter>[],
const <ReflectedInstance>[],
const <ReflectedFunction>[],
const <ReflectedDeclaration>[],
Object);
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
throw UnsupportedError(
'Classes reflected via an EmptyReflector cannot be instantiated.');
}
@override
bool isAssignableTo(ReflectedType other) {
return other == this;
}
@override
bool operator ==(other) {
return other is ReflectedClass && other.hashCode == hashCode;
}
}
class _EmptyReflectedType extends ReflectedType {
const _EmptyReflectedType()
: super('(empty)', const <ReflectedTypeParameter>[], Object);
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
throw UnsupportedError(
'Types reflected via an EmptyReflector cannot be instantiated.');
}
@override
bool isAssignableTo(ReflectedType other) {
return other == this;
}
@override
bool operator ==(other) {
return other is ReflectedType && other.hashCode == hashCode;
}
}
class _EmptyReflectedInstance extends ReflectedInstance {
const _EmptyReflectedInstance()
: super(const _EmptyReflectedType(), const _EmptyReflectedClass(), null);
@override
bool operator ==(other) {
return other is ReflectedInstance && other.hashCode == hashCode;
}
@override
ReflectedInstance getField(String name) {
throw UnsupportedError(
'Instances reflected via an EmptyReflector cannot call getField().');
}
}
class _EmptyReflectedFunction extends ReflectedFunction {
const _EmptyReflectedFunction()
: super(
'(empty)',
const <ReflectedTypeParameter>[],
const <ReflectedInstance>[],
const _EmptyReflectedType(),
const <ReflectedParameter>[],
false,
false);
@override
ReflectedInstance invoke(Invocation invocation) {
throw UnsupportedError(
'Instances reflected via an EmptyReflector cannot call invoke().');
}
}

View file

@ -0,0 +1,8 @@
class ReflectionException implements Exception {
final String message;
ReflectionException(this.message);
@override
String toString() => message;
}

View file

@ -0,0 +1 @@
export 'reflector.dart';

View file

@ -0,0 +1,247 @@
import 'dart:async';
import 'dart:mirrors' as dart;
import 'package:angel_container/angel_container.dart';
import 'package:angel_container/src/reflector.dart';
/// A [Reflector] implementation that forwards to `dart:mirrors`.
///
/// Useful on the server, where reflection is supported.
class MirrorsReflector extends Reflector {
const MirrorsReflector();
@override
String getName(Symbol symbol) => dart.MirrorSystem.getName(symbol);
@override
ReflectedClass reflectClass(Type clazz) {
var mirror = dart.reflectType(clazz);
if (mirror is dart.ClassMirror) {
return _ReflectedClassMirror(mirror);
} else {
throw ArgumentError('$clazz is not a class.');
}
}
@override
ReflectedFunction reflectFunction(Function function) {
var closure = dart.reflect(function) as dart.ClosureMirror;
return _ReflectedMethodMirror(closure.function, closure);
}
@override
ReflectedType reflectType(Type type) {
var mirror = dart.reflectType(type);
if (!mirror.hasReflectedType) {
return reflectType(dynamic);
} else {
if (mirror is dart.ClassMirror) {
return _ReflectedClassMirror(mirror);
} else {
return _ReflectedTypeMirror(mirror);
}
}
}
@override
ReflectedType reflectFutureOf(Type type) {
var inner = reflectType(type);
dart.TypeMirror _mirror;
if (inner is _ReflectedClassMirror) {
_mirror = inner.mirror;
} else if (inner is _ReflectedTypeMirror) {
_mirror = inner.mirror;
} else {
throw ArgumentError('$type is not a class or type.');
}
var future = dart.reflectType(Future, [_mirror.reflectedType]);
return _ReflectedClassMirror(future as dart.ClassMirror);
}
@override
ReflectedInstance reflectInstance(Object object) {
return _ReflectedInstanceMirror(dart.reflect(object));
}
}
class _ReflectedTypeParameter extends ReflectedTypeParameter {
final dart.TypeVariableMirror mirror;
_ReflectedTypeParameter(this.mirror)
: super(dart.MirrorSystem.getName(mirror.simpleName));
}
class _ReflectedTypeMirror extends ReflectedType {
final dart.TypeMirror mirror;
_ReflectedTypeMirror(this.mirror)
: super(
dart.MirrorSystem.getName(mirror.simpleName),
mirror.typeVariables.map((m) => _ReflectedTypeParameter(m)).toList(),
mirror.reflectedType,
);
@override
bool isAssignableTo(ReflectedType other) {
if (other is _ReflectedClassMirror) {
return mirror.isAssignableTo(other.mirror);
} else if (other is _ReflectedTypeMirror) {
return mirror.isAssignableTo(other.mirror);
} else {
return false;
}
}
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
throw ReflectionException(
'$name is not a class, and therefore cannot be instantiated.');
}
}
class _ReflectedClassMirror extends ReflectedClass {
final dart.ClassMirror mirror;
_ReflectedClassMirror(this.mirror)
: super(
dart.MirrorSystem.getName(mirror.simpleName),
mirror.typeVariables.map((m) => _ReflectedTypeParameter(m)).toList(),
[],
[],
_declarationsOf(mirror),
mirror.reflectedType,
);
static List<ReflectedFunction> _constructorsOf(dart.ClassMirror mirror) {
var out = <ReflectedFunction>[];
for (var key in mirror.declarations.keys) {
var value = mirror.declarations[key];
if (value is dart.MethodMirror && value.isConstructor) {
out.add(_ReflectedMethodMirror(value));
}
}
return out;
}
static List<ReflectedDeclaration> _declarationsOf(dart.ClassMirror mirror) {
var out = <ReflectedDeclaration>[];
for (var key in mirror.declarations.keys) {
var value = mirror.declarations[key];
if (value is dart.MethodMirror && !value.isConstructor) {
out.add(
_ReflectedDeclarationMirror(dart.MirrorSystem.getName(key), value));
}
}
return out;
}
@override
List<ReflectedInstance> get annotations =>
mirror.metadata.map((m) => _ReflectedInstanceMirror(m)).toList();
@override
List<ReflectedFunction> get constructors => _constructorsOf(mirror);
@override
bool isAssignableTo(ReflectedType other) {
if (other is _ReflectedClassMirror) {
return mirror.isAssignableTo(other.mirror);
} else if (other is _ReflectedTypeMirror) {
return mirror.isAssignableTo(other.mirror);
} else {
return false;
}
}
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
return _ReflectedInstanceMirror(
mirror.newInstance(Symbol(constructorName), positionalArguments));
}
@override
bool operator ==(other) {
return other is _ReflectedClassMirror && other.mirror == mirror;
}
}
class _ReflectedDeclarationMirror extends ReflectedDeclaration {
final String name;
final dart.MethodMirror mirror;
_ReflectedDeclarationMirror(this.name, this.mirror)
: super(name, mirror.isStatic, null);
@override
bool get isStatic => mirror.isStatic;
@override
ReflectedFunction get function => _ReflectedMethodMirror(mirror);
}
class _ReflectedInstanceMirror extends ReflectedInstance {
final dart.InstanceMirror mirror;
_ReflectedInstanceMirror(this.mirror)
: super(_ReflectedClassMirror(mirror.type),
_ReflectedClassMirror(mirror.type), mirror.reflectee);
@override
ReflectedInstance getField(String name) {
return _ReflectedInstanceMirror(mirror.getField(Symbol(name)));
}
}
class _ReflectedMethodMirror extends ReflectedFunction {
final dart.MethodMirror mirror;
final dart.ClosureMirror closureMirror;
_ReflectedMethodMirror(this.mirror, [this.closureMirror])
: super(
dart.MirrorSystem.getName(mirror.simpleName),
<ReflectedTypeParameter>[],
mirror.metadata
.map((mirror) => _ReflectedInstanceMirror(mirror))
.toList(),
!mirror.returnType.hasReflectedType
? const MirrorsReflector().reflectType(dynamic)
: const MirrorsReflector()
.reflectType(mirror.returnType.reflectedType),
mirror.parameters.map(_reflectParameter).toList(),
mirror.isGetter,
mirror.isSetter);
static ReflectedParameter _reflectParameter(dart.ParameterMirror mirror) {
return ReflectedParameter(
dart.MirrorSystem.getName(mirror.simpleName),
mirror.metadata
.map((mirror) => _ReflectedInstanceMirror(mirror))
.toList(),
const MirrorsReflector().reflectType(mirror.type.reflectedType),
!mirror.isOptional,
mirror.isNamed);
}
@override
ReflectedInstance invoke(Invocation invocation) {
if (closureMirror == null) {
throw StateError(
'This object was reflected without a ClosureMirror, and therefore cannot be directly invoked.');
}
return _ReflectedInstanceMirror(closureMirror.invoke(invocation.memberName,
invocation.positionalArguments, invocation.namedArguments));
}
}

View file

@ -0,0 +1,187 @@
import 'package:collection/collection.dart';
import 'package:quiver/core.dart';
abstract class Reflector {
const Reflector();
String getName(Symbol symbol);
ReflectedClass reflectClass(Type clazz);
ReflectedFunction reflectFunction(Function function);
ReflectedType reflectType(Type type);
ReflectedInstance reflectInstance(Object object);
ReflectedType reflectFutureOf(Type type) {
throw UnsupportedError('`reflectFutureOf` requires `dart:mirrors`.');
}
}
abstract class ReflectedInstance {
final ReflectedType type;
final ReflectedClass clazz;
final Object reflectee;
const ReflectedInstance(this.type, this.clazz, this.reflectee);
@override
int get hashCode => hash2(type, clazz);
@override
bool operator ==(other) =>
other is ReflectedInstance && other.type == type && other.clazz == clazz;
ReflectedInstance getField(String name);
}
abstract class ReflectedType {
final String name;
final List<ReflectedTypeParameter> typeParameters;
final Type reflectedType;
const ReflectedType(this.name, this.typeParameters, this.reflectedType);
@override
int get hashCode => hash3(name, typeParameters, reflectedType);
@override
bool operator ==(other) =>
other is ReflectedType &&
other.name == name &&
const ListEquality<ReflectedTypeParameter>()
.equals(other.typeParameters, typeParameters) &&
other.reflectedType == reflectedType;
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]);
bool isAssignableTo(ReflectedType other);
}
abstract class ReflectedClass extends ReflectedType {
final List<ReflectedInstance> annotations;
final List<ReflectedFunction> constructors;
final List<ReflectedDeclaration> declarations;
const ReflectedClass(
String name,
List<ReflectedTypeParameter> typeParameters,
this.annotations,
this.constructors,
this.declarations,
Type reflectedType)
: super(name, typeParameters, reflectedType);
@override
int get hashCode =>
hash4(super.hashCode, annotations, constructors, declarations);
@override
bool operator ==(other) =>
other is ReflectedClass &&
super == other &&
const ListEquality<ReflectedInstance>()
.equals(other.annotations, annotations) &&
const ListEquality<ReflectedFunction>()
.equals(other.constructors, constructors) &&
const ListEquality<ReflectedDeclaration>()
.equals(other.declarations, declarations);
}
class ReflectedDeclaration {
final String name;
final bool isStatic;
final ReflectedFunction function;
const ReflectedDeclaration(this.name, this.isStatic, this.function);
@override
int get hashCode => hash3(name, isStatic, function);
@override
bool operator ==(other) =>
other is ReflectedDeclaration &&
other.name == name &&
other.isStatic == isStatic &&
other.function == function;
}
abstract class ReflectedFunction {
final String name;
final List<ReflectedTypeParameter> typeParameters;
final List<ReflectedInstance> annotations;
final ReflectedType returnType;
final List<ReflectedParameter> parameters;
final bool isGetter, isSetter;
const ReflectedFunction(this.name, this.typeParameters, this.annotations,
this.returnType, this.parameters, this.isGetter, this.isSetter);
@override
int get hashCode => hashObjects([
name,
typeParameters,
annotations,
returnType,
parameters,
isGetter,
isSetter
]);
@override
bool operator ==(other) =>
other is ReflectedFunction &&
other.name == name &&
const ListEquality<ReflectedTypeParameter>()
.equals(other.typeParameters, typeParameters) &&
const ListEquality<ReflectedInstance>()
.equals(other.annotations, annotations) &&
other.returnType == returnType &&
const ListEquality<ReflectedParameter>()
.equals(other.parameters, other.parameters) &&
other.isGetter == isGetter &&
other.isSetter == isSetter;
ReflectedInstance invoke(Invocation invocation);
}
class ReflectedParameter {
final String name;
final List<ReflectedInstance> annotations;
final ReflectedType type;
final bool isRequired;
final bool isNamed;
const ReflectedParameter(
this.name, this.annotations, this.type, this.isRequired, this.isNamed);
@override
int get hashCode =>
hashObjects([name, annotations, type, isRequired, isNamed]);
@override
bool operator ==(other) =>
other is ReflectedParameter &&
other.name == name &&
const ListEquality<ReflectedInstance>()
.equals(other.annotations, annotations) &&
other.type == type &&
other.isRequired == isRequired &&
other.isNamed == isNamed;
}
class ReflectedTypeParameter {
final String name;
const ReflectedTypeParameter(this.name);
@override
int get hashCode => hashObjects([name]);
@override
bool operator ==(other) =>
other is ReflectedTypeParameter && other.name == name;
}

View file

@ -0,0 +1,61 @@
import 'package:angel_container/angel_container.dart';
/// A [Reflector] implementation that performs simple [Map] lookups.
///
/// `package:angel_container_generator` uses this to create reflectors from analysis metadata.
class StaticReflector extends Reflector {
final Map<Symbol, String> names;
final Map<Type, ReflectedType> types;
final Map<Function, ReflectedFunction> functions;
final Map<Object, ReflectedInstance> instances;
const StaticReflector(
{this.names = const {},
this.types = const {},
this.functions = const {},
this.instances = const {}});
@override
String getName(Symbol symbol) {
if (!names.containsKey(symbol)) {
throw ArgumentError(
'The value of $symbol is unknown - it was not generated.');
}
return names[symbol];
}
@override
ReflectedClass reflectClass(Type clazz) =>
reflectType(clazz) as ReflectedClass;
@override
ReflectedFunction reflectFunction(Function function) {
if (!functions.containsKey(function)) {
throw ArgumentError(
'There is no reflection information available about $function.');
}
return functions[function];
}
@override
ReflectedInstance reflectInstance(Object object) {
if (!instances.containsKey(object)) {
throw ArgumentError(
'There is no reflection information available about $object.');
}
return instances[object];
}
@override
ReflectedType reflectType(Type type) {
if (!types.containsKey(type)) {
throw ArgumentError(
'There is no reflection information available about $type.');
}
return types[type];
}
}

View file

@ -0,0 +1,34 @@
import 'package:angel_container/angel_container.dart';
/// A [Reflector] implementation that throws exceptions on all attempts
/// to perform reflection.
///
/// Use this in contexts where you know you won't need any reflective capabilities.
class ThrowingReflector extends Reflector {
/// The error message to give the end user when an [UnsupportedError] is thrown.
final String errorMessage;
static const String defaultErrorMessage =
'You attempted to perform a reflective action, but you are using `ThrowingReflector`, '
'a class which disables reflection. Consider using the `MirrorsReflector` '
'class if you need reflection.';
const ThrowingReflector({this.errorMessage = defaultErrorMessage});
@override
String getName(Symbol symbol) => const EmptyReflector().getName(symbol);
UnsupportedError _error() => UnsupportedError(errorMessage);
@override
ReflectedClass reflectClass(Type clazz) => throw _error();
@override
ReflectedInstance reflectInstance(Object object) => throw _error();
@override
ReflectedType reflectType(Type type) => throw _error();
@override
ReflectedFunction reflectFunction(Function function) => throw _error();
}

View file

@ -0,0 +1,13 @@
name: angel_container
version: 1.1.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: ">=1.8.0 <3.0.0"
dependencies:
collection: ^1.0.0
quiver: ^2.0.0
dev_dependencies:
pedantic: ^1.0.0
test: ^1.0.0

View file

@ -0,0 +1,122 @@
import 'dart:async';
import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart';
void returnVoidFromAFunction(int x) {}
void testReflector(Reflector reflector) {
var blaziken = Pokemon('Blaziken', PokemonType.fire);
Container container;
setUp(() {
container = Container(reflector);
container.registerSingleton(blaziken);
container.registerFactory<Future<int>>((_) async => 46);
});
test('get field', () {
var blazikenMirror = reflector.reflectInstance(blaziken);
expect(blazikenMirror.getField('type').reflectee, blaziken.type);
});
group('reflectFunction', () {
var mirror = reflector.reflectFunction(returnVoidFromAFunction);
test('void return type returns dynamic', () {
expect(mirror.returnType, reflector.reflectType(dynamic));
});
test('counts parameters', () {
expect(mirror.parameters, hasLength(1));
});
test('counts types parameters', () {
expect(mirror.typeParameters, isEmpty);
});
test('correctly reflects parameter types', () {
var p = mirror.parameters[0];
expect(p.name, 'x');
expect(p.isRequired, true);
expect(p.isNamed, false);
expect(p.annotations, isEmpty);
expect(p.type, reflector.reflectType(int));
});
});
test('make on singleton type returns singleton', () {
expect(container.make(Pokemon), blaziken);
});
test('make with generic returns same as make with explicit type', () {
expect(container.make<Pokemon>(), blaziken);
});
test('make async returns async object', () async {
expect(container.makeAsync<int>(), completion(46));
});
test('make async returns sync object', () async {
expect(container.makeAsync<Pokemon>(), completion(blaziken));
});
test('make on aliased singleton returns singleton', () {
container.registerSingleton(blaziken, as: StateError);
expect(container.make(StateError), blaziken);
});
test('constructor injects singleton', () {
var lower = container.make<LowerPokemon>();
expect(lower.lowercaseName, blaziken.name.toLowerCase());
});
test('newInstance works', () {
var type = container.reflector.reflectType(Pokemon);
var instance =
type.newInstance('changeName', [blaziken, 'Charizard']).reflectee
as Pokemon;
print(instance);
expect(instance.name, 'Charizard');
expect(instance.type, PokemonType.fire);
});
test('isAssignableTo', () {
var pokemonType = container.reflector.reflectType(Pokemon);
var kantoPokemonType = container.reflector.reflectType(KantoPokemon);
expect(kantoPokemonType.isAssignableTo(pokemonType), true);
expect(
kantoPokemonType
.isAssignableTo(container.reflector.reflectType(String)),
false);
});
}
class LowerPokemon {
final Pokemon pokemon;
LowerPokemon(this.pokemon);
String get lowercaseName => pokemon.name.toLowerCase();
}
class Pokemon {
final String name;
final PokemonType type;
Pokemon(this.name, this.type);
factory Pokemon.changeName(Pokemon other, String name) {
return Pokemon(name, other.type);
}
@override
String toString() => 'NAME: $name, TYPE: $type';
}
class KantoPokemon extends Pokemon {
KantoPokemon(String name, PokemonType type) : super(name, type);
}
enum PokemonType { water, fire, grass, ice, poison, flying }

View file

@ -0,0 +1,138 @@
import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart';
void main() {
var reflector = const EmptyReflector();
test('getName', () {
expect(reflector.getName(#foo), 'foo');
expect(reflector.getName(#==), '==');
});
group('reflectClass', () {
var mirror = reflector.reflectClass(Truck);
test('name returns empty', () {
expect(mirror.name, '(empty)');
});
test('annotations returns empty', () {
expect(mirror.annotations, isEmpty);
});
test('typeParameters returns empty', () {
expect(mirror.typeParameters, isEmpty);
});
test('declarations returns empty', () {
expect(mirror.declarations, isEmpty);
});
test('constructors returns empty', () {
expect(mirror.constructors, isEmpty);
});
test('reflectedType returns Object', () {
expect(mirror.reflectedType, Object);
});
test('cannot call newInstance', () {
expect(() => mirror.newInstance('', []), throwsUnsupportedError);
});
test('isAssignableTo self', () {
expect(mirror.isAssignableTo(mirror), true);
});
});
group('reflectType', () {
var mirror = reflector.reflectType(Truck);
test('name returns empty', () {
expect(mirror.name, '(empty)');
});
test('typeParameters returns empty', () {
expect(mirror.typeParameters, isEmpty);
});
test('reflectedType returns Object', () {
expect(mirror.reflectedType, Object);
});
test('cannot call newInstance', () {
expect(() => mirror.newInstance('', []), throwsUnsupportedError);
});
test('isAssignableTo self', () {
expect(mirror.isAssignableTo(mirror), true);
});
});
group('reflectFunction', () {
void doIt(int x) {}
var mirror = reflector.reflectFunction(doIt);
test('name returns empty', () {
expect(mirror.name, '(empty)');
});
test('annotations returns empty', () {
expect(mirror.annotations, isEmpty);
});
test('typeParameters returns empty', () {
expect(mirror.typeParameters, isEmpty);
});
test('parameters returns empty', () {
expect(mirror.parameters, isEmpty);
});
test('return type is dynamic', () {
expect(mirror.returnType, reflector.reflectType(dynamic));
});
test('isGetter returns false', () {
expect(mirror.isGetter, false);
});
test('isSetter returns false', () {
expect(mirror.isSetter, false);
});
test('cannot invoke', () {
var invocation = Invocation.method(#drive, []);
expect(() => mirror.invoke(invocation), throwsUnsupportedError);
});
});
group('reflectInstance', () {
var mirror = reflector.reflectInstance(Truck());
test('reflectee returns null', () {
expect(mirror.reflectee, null);
});
test('type returns empty', () {
expect(mirror.type.name, '(empty)');
});
test('clazz returns empty', () {
expect(mirror.clazz.name, '(empty)');
});
test('cannot getField', () {
expect(() => mirror.getField('wheelCount'), throwsUnsupportedError);
});
});
}
class Truck {
int get wheelCount => 4;
void drive() {
print('Vroom!!!');
}
}

View file

@ -0,0 +1,50 @@
import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart';
void main() {
Container container;
setUp(() {
container = Container(const EmptyReflector())
..registerSingleton<Song>(Song(title: 'I Wish'))
..registerNamedSingleton('foo', 1)
..registerFactory<Artist>((container) {
return Artist(
name: 'Stevie Wonder',
song: container.make<Song>(),
);
});
});
test('hasNamed', () {
var child = container.createChild()..registerNamedSingleton('bar', 2);
expect(child.hasNamed('foo'), true);
expect(child.hasNamed('bar'), true);
expect(child.hasNamed('baz'), false);
});
test('has on singleton', () {
expect(container.has<Song>(), true);
});
test('has on factory', () {
expect(container.has<Artist>(), true);
});
test('false if neither', () {
expect(container.has<bool>(), false);
});
}
class Artist {
final String name;
final Song song;
Artist({this.name, this.song});
}
class Song {
final String title;
Song({this.title});
}

View file

@ -0,0 +1,18 @@
import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart';
void main() {
test('returns the same instance', () {
var container = Container(const EmptyReflector())
..registerLazySingleton<Dummy>((_) => Dummy('a'));
var first = container.make<Dummy>();
expect(container.make<Dummy>(), first);
});
}
class Dummy {
final String s;
Dummy(this.s);
}

View file

@ -0,0 +1,26 @@
import 'dart:async';
import 'package:angel_container/angel_container.dart';
import 'package:angel_container/mirrors.dart';
import 'package:test/test.dart';
import 'common.dart';
void main() {
testReflector(const MirrorsReflector());
test('futureOf', () {
var r = MirrorsReflector();
var fStr = r.reflectFutureOf(String);
expect(fStr.reflectedType.toString(), 'Future<String>');
// expect(fStr.reflectedType, Future<String>.value(null).runtimeType);
});
test('concrete future make', () async {
var c = Container(MirrorsReflector());
c.registerFactory<Future<String>>((_) async => 'hey');
var fStr = c.reflector.reflectFutureOf(String);
var s1 = await c.make(fStr.reflectedType);
var s2 = await c.makeAsync(String);
print([s1, s2]);
expect(s1, s2);
});
}

View file

@ -0,0 +1,34 @@
import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart';
void main() {
Container container;
setUp(() {
container = Container(const EmptyReflector());
container.registerNamedSingleton('foo', Foo(bar: 'baz'));
});
test('fetch by name', () {
expect(container.findByName<Foo>('foo').bar, 'baz');
});
test('cannot redefine', () {
expect(() => container.registerNamedSingleton('foo', Foo(bar: 'quux')),
throwsStateError);
});
test('throws on unknown name', () {
expect(() => container.findByName('bar'), throwsStateError);
});
test('throws on incorrect type', () {
expect(() => container.findByName<List<String>>('foo'), throwsA(anything));
});
}
class Foo {
final String bar;
Foo({this.bar});
}

View file

@ -0,0 +1,36 @@
import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart';
void main() {
var reflector = const ThrowingReflector();
test('getName', () {
expect(reflector.getName(#foo), 'foo');
expect(reflector.getName(#==), '==');
});
test('reflectClass fails', () {
expect(() => reflector.reflectClass(Truck), throwsUnsupportedError);
});
test('reflectType fails', () {
expect(() => reflector.reflectType(Truck), throwsUnsupportedError);
});
test('reflectFunction throws', () {
void doIt(int x) {}
expect(() => reflector.reflectFunction(doIt), throwsUnsupportedError);
});
test('reflectInstance throws', () {
expect(() => reflector.reflectInstance(Truck()), throwsUnsupportedError);
});
}
class Truck {
int get wheelCount => 4;
void drive() {
print('Vroom!!!');
}
}

View file

@ -0,0 +1,13 @@
# See https://www.dartlang.org/guides/libraries/private-files
# Files and directories created by pub
.dart_tool/
.packages
.pub/
build/
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/

View file

@ -0,0 +1,2 @@
# 1.0.1
* Update for `pkg:angel_container@1.0.3`.

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 The Angel Framework
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,2 @@
# container
A better IoC container for Angel, ultimately allowing Angel to be used without dart:mirrors.

View file

@ -0,0 +1,3 @@
analyzer:
#strong-mode:
#implicit-casts: false

View file

@ -0,0 +1,248 @@
import 'package:angel_container/angel_container.dart';
import 'package:reflectable/reflectable.dart';
/// A [Reflectable] instance that can be used as an annotation on types to generate metadata for them.
const Reflectable contained = const ContainedReflectable();
@contained
class ContainedReflectable extends Reflectable {
const ContainedReflectable()
: super(
declarationsCapability,
instanceInvokeCapability,
invokingCapability,
metadataCapability,
newInstanceCapability,
reflectedTypeCapability,
typeRelationsCapability,
typeCapability,
);
}
/// A [Reflector] instance that uses a [Reflectable] to reflect upon data.
class GeneratedReflector extends Reflector {
final Reflectable reflectable;
const GeneratedReflector([this.reflectable = contained]);
@override
String getName(Symbol symbol) {
return symbol.toString().substring(7);
}
@override
ReflectedClass reflectClass(Type clazz) {
return reflectType(clazz) as ReflectedClass;
}
@override
ReflectedFunction reflectFunction(Function function) {
if (!reflectable.canReflect(function)) {
throw new UnsupportedError('Cannot reflect $function.');
}
var mirror = reflectable.reflect(function);
if (mirror is ClosureMirror) {
return new _GeneratedReflectedFunction(mirror.function, this, mirror);
} else {
throw new ArgumentError('$function is not a Function.');
}
}
@override
ReflectedInstance reflectInstance(Object object) {
if (!reflectable.canReflect(object)) {
throw new UnsupportedError('Cannot reflect $object.');
} else {
var mirror = reflectable.reflect(object);
return new _GeneratedReflectedInstance(mirror, this);
}
}
@override
ReflectedType reflectType(Type type) {
if (!reflectable.canReflectType(type)) {
throw new UnsupportedError('Cannot reflect $type.');
} else {
var mirror = reflectable.reflectType(type);
return mirror is ClassMirror
? new _GeneratedReflectedClass(mirror, this)
: new _GeneratedReflectedType(mirror);
}
}
}
class _GeneratedReflectedInstance extends ReflectedInstance {
final InstanceMirror mirror;
final GeneratedReflector reflector;
_GeneratedReflectedInstance(this.mirror, this.reflector)
: super(null, new _GeneratedReflectedClass(mirror.type, reflector),
mirror.reflectee);
@override
ReflectedType get type => clazz;
@override
ReflectedInstance getField(String name) {
var result = mirror.invokeGetter(name);
var instance = reflector.reflectable.reflect(result);
return new _GeneratedReflectedInstance(instance, reflector);
}
}
class _GeneratedReflectedClass extends ReflectedClass {
final ClassMirror mirror;
final Reflector reflector;
_GeneratedReflectedClass(this.mirror, this.reflector)
: super(mirror.simpleName, null, null, null, null, mirror.reflectedType);
@override
List<ReflectedTypeParameter> get typeParameters =>
mirror.typeVariables.map(_convertTypeVariable).toList();
@override
List<ReflectedFunction> get constructors =>
_constructorsOf(mirror.declarations, reflector);
@override
List<ReflectedDeclaration> get declarations =>
_declarationsOf(mirror.declarations, reflector);
@override
List<ReflectedInstance> get annotations =>
mirror.metadata.map(reflector.reflectInstance).toList();
@override
bool isAssignableTo(ReflectedType other) {
if (other is _GeneratedReflectedClass) {
return mirror.isAssignableTo(other.mirror);
} else if (other is _GeneratedReflectedType) {
return mirror.isAssignableTo(other.mirror);
} else {
return false;
}
}
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
namedArguments ??= {};
var result = mirror.newInstance(constructorName, positionalArguments,
namedArguments.map((k, v) => new MapEntry(new Symbol(k), v)));
return reflector.reflectInstance(result);
}
}
class _GeneratedReflectedType extends ReflectedType {
final TypeMirror mirror;
_GeneratedReflectedType(this.mirror)
: super(mirror.simpleName, null, mirror.reflectedType);
@override
List<ReflectedTypeParameter> get typeParameters =>
mirror.typeVariables.map(_convertTypeVariable).toList();
@override
bool isAssignableTo(ReflectedType other) {
if (other is _GeneratedReflectedClass) {
return mirror.isAssignableTo(other.mirror);
} else if (other is _GeneratedReflectedType) {
return mirror.isAssignableTo(other.mirror);
} else {
return false;
}
}
@override
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
throw new UnsupportedError(
'Cannot create a new instance of $reflectedType.');
}
}
class _GeneratedReflectedFunction extends ReflectedFunction {
final MethodMirror mirror;
final Reflector reflector;
final ClosureMirror closure;
_GeneratedReflectedFunction(this.mirror, this.reflector, [this.closure])
: super(
mirror.simpleName,
[],
null,
!mirror.isRegularMethod
? null
: new _GeneratedReflectedType(mirror.returnType),
mirror.parameters
.map((p) => _convertParameter(p, reflector))
.toList(),
mirror.isGetter,
mirror.isSetter);
@override
List<ReflectedInstance> get annotations =>
mirror.metadata.map(reflector.reflectInstance).toList();
@override
ReflectedInstance invoke(Invocation invocation) {
if (closure != null) {
throw new UnsupportedError('Only closures can be invoked directly.');
} else {
var result = closure.delegate(invocation);
return reflector.reflectInstance(result);
}
}
}
List<ReflectedFunction> _constructorsOf(
Map<String, DeclarationMirror> map, Reflector reflector) {
return map.entries.fold<List<ReflectedFunction>>([], (out, entry) {
var v = entry.value;
if (v is MethodMirror && v.isConstructor) {
return out..add(new _GeneratedReflectedFunction(v, reflector));
} else {
return out;
}
});
}
List<ReflectedDeclaration> _declarationsOf(
Map<String, DeclarationMirror> map, Reflector reflector) {
return map.entries.fold<List<ReflectedDeclaration>>([], (out, entry) {
var v = entry.value;
if (v is VariableMirror) {
var decl = new ReflectedDeclaration(v.simpleName, v.isStatic, null);
return out..add(decl);
}
if (v is MethodMirror) {
var decl = new ReflectedDeclaration(v.simpleName, v.isStatic,
new _GeneratedReflectedFunction(v, reflector));
return out..add(decl);
} else {
return out;
}
});
}
ReflectedTypeParameter _convertTypeVariable(TypeVariableMirror mirror) {
return new ReflectedTypeParameter(mirror.simpleName);
}
ReflectedParameter _convertParameter(
ParameterMirror mirror, Reflector reflector) {
return new ReflectedParameter(
mirror.simpleName,
mirror.metadata.map(reflector.reflectInstance).toList(),
reflector.reflectType(mirror.type.reflectedType),
!mirror.isOptional,
mirror.isNamed);
}

View file

@ -0,0 +1,14 @@
name: angel_container_generator
version: 1.0.1
author: Tobe O <thosakwe@gmail.com>
description: Codegen support for using pkg:reflectable with pkg:angel_container.
homepage: https://github.com/angel-dart/container.git
environment:
sdk: ">=2.0.0-dev <3.0.0"
dependencies:
angel_container: ^1.0.0-alpha
reflectable: ^2.0.0
dev_dependencies:
build_runner: ^1.0.0
build_test:
test: ^1.0.0

View file

@ -0,0 +1,182 @@
import 'package:angel_container/angel_container.dart';
import 'package:angel_container_generator/angel_container_generator.dart';
@GlobalQuantifyCapability(
r'^dart\.core\.(Iterable|List|String|int|Object)', contained)
import 'package:reflectable/reflectable.dart';
import 'package:test/test.dart';
import 'reflector_test.reflectable.dart';
void main() {
initializeReflectable();
var reflector = const GeneratedReflector();
Container container;
setUp(() {
container = new Container(reflector);
container.registerSingleton(new Artist(name: 'Stevie Wonder'));
});
group('reflectClass', () {
var mirror = reflector.reflectClass(Artist);
test('name', () {
expect(mirror.name, 'Artist');
});
});
test('inject constructor parameters', () {
var album = container.make<Album>();
print(album.title);
expect(album.title, 'flowers by stevie wonder');
});
testReflector(reflector);
}
@contained
void returnVoidFromAFunction(int x) {}
void testReflector(Reflector reflector) {
var blaziken = new Pokemon('Blaziken', PokemonType.fire);
Container container;
setUp(() {
container = new Container(reflector);
container.registerSingleton(blaziken);
});
test('get field', () {
var blazikenMirror = reflector.reflectInstance(blaziken);
expect(blazikenMirror.getField('type').reflectee, blaziken.type);
});
/*
group('reflectFunction', () {
var mirror = reflector.reflectFunction(returnVoidFromAFunction);
test('void return type returns dynamic', () {
expect(mirror.returnType, reflector.reflectType(dynamic));
});
test('counts parameters', () {
expect(mirror.parameters, hasLength(1));
});
test('counts types parameters', () {
expect(mirror.typeParameters, isEmpty);
});
test('correctly reflects parameter types', () {
var p = mirror.parameters[0];
expect(p.name, 'x');
expect(p.isRequired, true);
expect(p.isNamed, false);
expect(p.annotations, isEmpty);
expect(p.type, reflector.reflectType(int));
});
}, skip: 'pkg:reflectable cannot reflect on closures at all (yet)');
*/
test('make on singleton type returns singleton', () {
expect(container.make(Pokemon), blaziken);
});
test('make with generic returns same as make with explicit type', () {
expect(container.make<Pokemon>(), blaziken);
});
test('make on aliased singleton returns singleton', () {
container.registerSingleton(blaziken, as: StateError);
expect(container.make(StateError), blaziken);
});
test('constructor injects singleton', () {
var lower = container.make<LowerPokemon>();
expect(lower.lowercaseName, blaziken.name.toLowerCase());
});
test('newInstance works', () {
var type = container.reflector.reflectType(Pokemon);
var instance =
type.newInstance('changeName', [blaziken, 'Charizard']).reflectee
as Pokemon;
print(instance);
expect(instance.name, 'Charizard');
expect(instance.type, PokemonType.fire);
});
test('isAssignableTo', () {
var pokemonType = container.reflector.reflectType(Pokemon);
var kantoPokemonType = container.reflector.reflectType(KantoPokemon);
expect(kantoPokemonType.isAssignableTo(pokemonType), true);
expect(
kantoPokemonType
.isAssignableTo(container.reflector.reflectType(String)),
false);
});
}
@contained
class LowerPokemon {
final Pokemon pokemon;
LowerPokemon(this.pokemon);
String get lowercaseName => pokemon.name.toLowerCase();
}
@contained
class Pokemon {
final String name;
final PokemonType type;
Pokemon(this.name, this.type);
factory Pokemon.changeName(Pokemon other, String name) {
return new Pokemon(name, other.type);
}
@override
String toString() => 'NAME: $name, TYPE: $type';
}
@contained
class KantoPokemon extends Pokemon {
KantoPokemon(String name, PokemonType type) : super(name, type);
}
@contained
enum PokemonType { water, fire, grass, ice, poison, flying }
@contained
class Artist {
final String name;
Artist({this.name});
String get lowerName {
return name.toLowerCase();
}
}
@contained
class Album {
final Artist artist;
Album(this.artist);
String get title => 'flowers by ${artist.lowerName}';
}
@contained
class AlbumLength {
final Artist artist;
final Album album;
AlbumLength(this.artist, this.album);
int get totalLength => artist.name.length + album.title.length;
}

File diff suppressed because it is too large Load diff