Stack overflow
This commit is contained in:
parent
24b03ce71c
commit
a570537bac
6 changed files with 165 additions and 24 deletions
|
@ -16,13 +16,17 @@ class Container {
|
|||
var named = <String, dynamic>{};
|
||||
|
||||
if (reflectedType is ReflectedClass) {
|
||||
bool isDefault(String name) {
|
||||
return name.isEmpty || name == reflectedType.name;
|
||||
}
|
||||
|
||||
var constructor = reflectedType.constructors.firstWhere(
|
||||
(c) => c.name.isEmpty,
|
||||
orElse: () => throw new ReflectionException('${reflectedType
|
||||
.name} has no default constructor, and therefore cannot be instantiated.'));
|
||||
(c) => isDefault(c.name),
|
||||
orElse: () => throw new ReflectionException(
|
||||
'${reflectedType.name} has no default constructor, and therefore cannot be instantiated.'));
|
||||
|
||||
for (var param in constructor.parameters) {
|
||||
var value = make(param.type);
|
||||
var value = make(param.type.reflectedType);
|
||||
|
||||
if (param.isNamed) {
|
||||
named[param.name] = value;
|
||||
|
@ -31,8 +35,10 @@ class Container {
|
|||
}
|
||||
}
|
||||
|
||||
return reflectedType
|
||||
.newInstance(constructor.name, positional, named, []);
|
||||
return reflectedType.newInstance(
|
||||
isDefault(constructor.name) ? '' : constructor.name,
|
||||
positional,
|
||||
named, []);
|
||||
} else {
|
||||
throw new ReflectionException(
|
||||
'$type is not a class, and therefore cannot be instantiated.');
|
||||
|
@ -42,8 +48,8 @@ class Container {
|
|||
|
||||
void singleton(Object object, {Type as}) {
|
||||
if (_singletons.containsKey(as ?? object.runtimeType)) {
|
||||
throw new StateError('This container already has a singleton for ${as ??
|
||||
object.runtimeType}.');
|
||||
throw new StateError(
|
||||
'This container already has a singleton for ${as ?? object.runtimeType}.');
|
||||
}
|
||||
|
||||
_singletons[as ?? object.runtimeType] = object;
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
import 'dart:mirrors' as dart;
|
||||
|
||||
import 'package:angel_container/angel_container.dart';
|
||||
import 'package:angel_container/src/reflector.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 implements Reflector {
|
||||
const MirrorsReflector();
|
||||
|
||||
@override
|
||||
String getName(Symbol symbol) => dart.MirrorSystem.getName(symbol);
|
||||
|
||||
|
@ -20,7 +25,8 @@ class MirrorsReflector implements Reflector {
|
|||
|
||||
@override
|
||||
ReflectedFunction reflectFunction(Function function) {
|
||||
// TODO: implement reflectFunction
|
||||
var closure = dart.reflect(function) as dart.ClosureMirror;
|
||||
return new _ReflectedMethodMirror(closure.function);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -33,6 +39,11 @@ class MirrorsReflector implements Reflector {
|
|||
return new _ReflectedTypeMirror(mirror);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
ReflectedInstance reflectInstance(Object object) {
|
||||
return new _ReflectedInstanceMirror(object);
|
||||
}
|
||||
}
|
||||
|
||||
class _ReflectedTypeParameter extends ReflectedTypeParameter {
|
||||
|
@ -52,6 +63,7 @@ class _ReflectedTypeMirror extends ReflectedType {
|
|||
mirror.typeVariables
|
||||
.map((m) => new _ReflectedTypeParameter(m))
|
||||
.toList(),
|
||||
mirror.reflectedType,
|
||||
);
|
||||
|
||||
@override
|
||||
|
@ -61,7 +73,7 @@ class _ReflectedTypeMirror extends ReflectedType {
|
|||
|
||||
@override
|
||||
T newInstance<T>(String constructorName, List positionalArguments,
|
||||
Map<String, dynamic> namedArguments, List<Type> typeArguments) {
|
||||
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
|
||||
throw new ReflectionException(
|
||||
'$name is not a class, and therefore cannot be instantiated.');
|
||||
}
|
||||
|
@ -79,6 +91,7 @@ class _ReflectedClassMirror extends ReflectedClass {
|
|||
mirror.metadata.map((m) => new _ReflectedInstanceMirror(m)).toList(),
|
||||
_constructorsOf(mirror),
|
||||
_declarationsOf(mirror),
|
||||
mirror.reflectedType,
|
||||
);
|
||||
|
||||
static List<ReflectedFunction> _constructorsOf(dart.ClassMirror mirror) {
|
||||
|
@ -86,6 +99,10 @@ class _ReflectedClassMirror extends ReflectedClass {
|
|||
|
||||
for (var key in mirror.declarations.keys) {
|
||||
var value = mirror.declarations[key];
|
||||
|
||||
if (value is dart.MethodMirror && value.isConstructor) {
|
||||
out.add(new _ReflectedMethodMirror(value));
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
|
@ -96,6 +113,11 @@ class _ReflectedClassMirror extends ReflectedClass {
|
|||
|
||||
for (var key in mirror.declarations.keys) {
|
||||
var value = mirror.declarations[key];
|
||||
|
||||
if (value is dart.MethodMirror && !value.isConstructor) {
|
||||
out.add(new ReflectedDeclaration(dart.MirrorSystem.getName(key),
|
||||
value.isStatic, new _ReflectedMethodMirror(value)));
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
|
@ -108,8 +130,10 @@ class _ReflectedClassMirror extends ReflectedClass {
|
|||
|
||||
@override
|
||||
T newInstance<T>(String constructorName, List positionalArguments,
|
||||
Map<String, dynamic> namedArguments, List<Type> typeArguments) {
|
||||
// TODO: implement newInstance
|
||||
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
|
||||
return mirror
|
||||
.newInstance(new Symbol(constructorName), positionalArguments)
|
||||
.reflectee as T;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,3 +149,31 @@ class _ReflectedInstanceMirror extends ReflectedInstance {
|
|||
return mirror.delegate(invocation) as T;
|
||||
}
|
||||
}
|
||||
|
||||
class _ReflectedMethodMirror extends ReflectedFunction {
|
||||
final dart.MethodMirror mirror;
|
||||
|
||||
_ReflectedMethodMirror(this.mirror)
|
||||
: super(
|
||||
dart.MirrorSystem.getName(mirror.simpleName),
|
||||
<ReflectedTypeParameter>[],
|
||||
mirror.metadata
|
||||
.map((mirror) => new _ReflectedInstanceMirror(mirror))
|
||||
.toList(),
|
||||
const MirrorsReflector()
|
||||
.reflectType(mirror.returnType.reflectedType),
|
||||
mirror.parameters.map(_reflectParameter).toList(),
|
||||
mirror.isGetter,
|
||||
mirror.isSetter);
|
||||
|
||||
static ReflectedParameter _reflectParameter(dart.ParameterMirror mirror) {
|
||||
return new ReflectedParameter(
|
||||
dart.MirrorSystem.getName(mirror.simpleName),
|
||||
mirror.metadata
|
||||
.map((mirror) => new _ReflectedInstanceMirror(mirror))
|
||||
.toList(),
|
||||
const MirrorsReflector().reflectType(mirror.type.reflectedType),
|
||||
!mirror.isOptional,
|
||||
mirror.isNamed);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import 'package:collection/collection.dart';
|
||||
import 'package:quiver_hashcode/hashcode.dart';
|
||||
import 'package:quiver/core.dart';
|
||||
|
||||
abstract class Reflector {
|
||||
String getName(Symbol symbol);
|
||||
|
@ -9,6 +9,8 @@ abstract class Reflector {
|
|||
ReflectedFunction reflectFunction(Function function);
|
||||
|
||||
ReflectedType reflectType(Type type);
|
||||
|
||||
ReflectedInstance reflectInstance(Object object);
|
||||
}
|
||||
|
||||
abstract class ReflectedInstance {
|
||||
|
@ -30,21 +32,23 @@ abstract class ReflectedInstance {
|
|||
abstract class ReflectedType {
|
||||
final String name;
|
||||
final List<ReflectedTypeParameter> typeParameters;
|
||||
final Type reflectedType;
|
||||
|
||||
const ReflectedType(this.name, this.typeParameters);
|
||||
const ReflectedType(this.name, this.typeParameters, this.reflectedType);
|
||||
|
||||
@override
|
||||
int get hashCode => hash2(name, typeParameters);
|
||||
int get hashCode => hash3(name, typeParameters, reflectedType);
|
||||
|
||||
@override
|
||||
bool operator ==(other) =>
|
||||
other is ReflectedType &&
|
||||
other.name == name &&
|
||||
const ListEquality<ReflectedTypeParameter>()
|
||||
.equals(other.typeParameters, typeParameters);
|
||||
.equals(other.typeParameters, typeParameters) &&
|
||||
other.reflectedType == reflectedType;
|
||||
|
||||
T newInstance<T>(String constructorName, List positionalArguments,
|
||||
Map<String, dynamic> namedArguments, List<Type> typeArguments);
|
||||
[Map<String, dynamic> namedArguments, List<Type> typeArguments]);
|
||||
|
||||
bool isAssignableTo(ReflectedType other);
|
||||
}
|
||||
|
@ -54,9 +58,14 @@ abstract class ReflectedClass extends ReflectedType {
|
|||
final List<ReflectedFunction> constructors;
|
||||
final List<ReflectedDeclaration> declarations;
|
||||
|
||||
const ReflectedClass(String name, List<ReflectedTypeParameter> typeParameters,
|
||||
this.annotations, this.constructors, this.declarations)
|
||||
: super(name, typeParameters);
|
||||
const ReflectedClass(
|
||||
String name,
|
||||
List<ReflectedTypeParameter> typeParameters,
|
||||
this.annotations,
|
||||
this.constructors,
|
||||
this.declarations,
|
||||
Type reflectedType)
|
||||
: super(name, typeParameters, reflectedType);
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
|
@ -96,7 +105,7 @@ class ReflectedFunction {
|
|||
final String name;
|
||||
final List<ReflectedTypeParameter> typeParameters;
|
||||
final List<ReflectedInstance> annotations;
|
||||
final Type returnType;
|
||||
final ReflectedType returnType;
|
||||
final List<ReflectedParameter> parameters;
|
||||
final bool isGetter, isSetter;
|
||||
|
||||
|
@ -132,7 +141,7 @@ class ReflectedFunction {
|
|||
class ReflectedParameter {
|
||||
final String name;
|
||||
final List<ReflectedInstance> annotations;
|
||||
final Type type;
|
||||
final ReflectedType type;
|
||||
final bool isRequired;
|
||||
final bool isNamed;
|
||||
|
||||
|
|
|
@ -1,4 +1,12 @@
|
|||
name: angel_container
|
||||
version: 1.0.0-alpha
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
description: "A better IoC container for Angel, ultimately allowing Angel to be used without dart:mirrors."
|
||||
homepage: https://github.com/angel-dart/container.git
|
||||
environment:
|
||||
sdk: ">=1.8.0 <3.0.0"
|
||||
dependencies:
|
||||
collection: ^1.0.0
|
||||
quiver_hashcode: ^1.0.0
|
||||
quiver: ^2.0.0
|
||||
dev_dependencies:
|
||||
test:
|
59
angel_container/test/common.dart
Normal file
59
angel_container/test/common.dart
Normal file
|
@ -0,0 +1,59 @@
|
|||
import 'package:angel_container/angel_container.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
void testReflector(Reflector reflector) {
|
||||
var blaziken = new Pokemon('Blaziken', PokemonType.fire);
|
||||
Container container;
|
||||
|
||||
setUp(() {
|
||||
container = new Container(reflector);
|
||||
container.singleton(blaziken);
|
||||
});
|
||||
|
||||
test('make on singleton type returns singleton', () {
|
||||
expect(container.make(Pokemon), blaziken);
|
||||
});
|
||||
|
||||
test('make on aliased singleton returns singleton', () {
|
||||
container.singleton(blaziken, as: StateError);
|
||||
expect(container.make(StateError), blaziken);
|
||||
});
|
||||
|
||||
test('constructor injects singleton', () {
|
||||
var lower = container.make(LowerPokemon) as LowerPokemon;
|
||||
expect(lower.lowercaseName, blaziken.name.toLowerCase());
|
||||
});
|
||||
|
||||
test('newInstance works', () {
|
||||
var type = container.reflector.reflectType(Pokemon);
|
||||
var instance =
|
||||
type.newInstance('changeName', [blaziken, 'Charizard']) as Pokemon;
|
||||
print(instance);
|
||||
expect(instance.name, 'Charizard');
|
||||
expect(instance.type, PokemonType.fire);
|
||||
});
|
||||
}
|
||||
|
||||
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 new Pokemon(name, other.type);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() => 'NAME: $name, TYPE: $type';
|
||||
}
|
||||
|
||||
enum PokemonType { water, fire, grass, ice, poison, flying }
|
7
angel_container/test/mirrors_test.dart
Normal file
7
angel_container/test/mirrors_test.dart
Normal file
|
@ -0,0 +1,7 @@
|
|||
import 'package:angel_container/mirrors.dart';
|
||||
|
||||
import 'common.dart';
|
||||
|
||||
void main() {
|
||||
testReflector(const MirrorsReflector());
|
||||
}
|
Loading…
Reference in a new issue