* Add EmptyReflector
.
* `ReflectedType.newInstance` now returns a `ReflectedInstance`. * Moved `ReflectedInstance.invoke` to `ReflectedFunction.invoke`.
This commit is contained in:
parent
3ec5749548
commit
3f12f4d581
9 changed files with 304 additions and 23 deletions
|
@ -1,3 +1,8 @@
|
||||||
|
# 1.0.0-alpha.7
|
||||||
|
* Add `EmptyReflector`.
|
||||||
|
* `ReflectedType.newInstance` now returns a `ReflectedInstance`.
|
||||||
|
* Moved `ReflectedInstance.invoke` to `ReflectedFunction.invoke`.
|
||||||
|
|
||||||
# 1.0.0-alpha.6
|
# 1.0.0-alpha.6
|
||||||
* Add `getField` to `ReflectedInstance`.
|
* Add `getField` to `ReflectedInstance`.
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
export 'src/empty/empty.dart';
|
||||||
export 'src/container.dart';
|
export 'src/container.dart';
|
||||||
export 'src/exception.dart';
|
export 'src/exception.dart';
|
||||||
export 'src/reflector.dart';
|
export 'src/reflector.dart';
|
||||||
|
|
|
@ -76,7 +76,7 @@ class Container {
|
||||||
return reflectedType.newInstance(
|
return reflectedType.newInstance(
|
||||||
isDefault(constructor.name) ? '' : constructor.name,
|
isDefault(constructor.name) ? '' : constructor.name,
|
||||||
positional,
|
positional,
|
||||||
named, []);
|
named, []).reflectee;
|
||||||
} else {
|
} else {
|
||||||
throw new ReflectionException(
|
throw new ReflectionException(
|
||||||
'$type is not a class, and therefore cannot be instantiated.');
|
'$type is not a class, and therefore cannot be instantiated.');
|
||||||
|
|
126
angel_container/lib/src/empty/empty.dart
Normal file
126
angel_container/lib/src/empty/empty.dart
Normal 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 implements Reflector {
|
||||||
|
/// A [RegExp] that can be used to extract the name of a symbol without reflection.
|
||||||
|
static final RegExp symbolRegex = new 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>[],
|
||||||
|
dynamic);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ReflectedInstance newInstance(
|
||||||
|
String constructorName, List positionalArguments,
|
||||||
|
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
|
||||||
|
throw new 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>[], dynamic);
|
||||||
|
|
||||||
|
@override
|
||||||
|
ReflectedInstance newInstance(
|
||||||
|
String constructorName, List positionalArguments,
|
||||||
|
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
|
||||||
|
throw new 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 new 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 new UnsupportedError(
|
||||||
|
'Instances reflected via an EmptyReflector cannot call invoke().');
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,7 +26,7 @@ class MirrorsReflector implements Reflector {
|
||||||
@override
|
@override
|
||||||
ReflectedFunction reflectFunction(Function function) {
|
ReflectedFunction reflectFunction(Function function) {
|
||||||
var closure = dart.reflect(function) as dart.ClosureMirror;
|
var closure = dart.reflect(function) as dart.ClosureMirror;
|
||||||
return new _ReflectedMethodMirror(closure.function);
|
return new _ReflectedMethodMirror(closure.function, closure);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -75,7 +75,8 @@ class _ReflectedTypeMirror extends ReflectedType {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
T newInstance<T>(String constructorName, List positionalArguments,
|
ReflectedInstance newInstance(
|
||||||
|
String constructorName, List positionalArguments,
|
||||||
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
|
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
|
||||||
throw new ReflectionException(
|
throw new ReflectionException(
|
||||||
'$name is not a class, and therefore cannot be instantiated.');
|
'$name is not a class, and therefore cannot be instantiated.');
|
||||||
|
@ -139,11 +140,11 @@ class _ReflectedClassMirror extends ReflectedClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
T newInstance<T>(String constructorName, List positionalArguments,
|
ReflectedInstance newInstance(
|
||||||
|
String constructorName, List positionalArguments,
|
||||||
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
|
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
|
||||||
return mirror
|
return new _ReflectedInstanceMirror(
|
||||||
.newInstance(new Symbol(constructorName), positionalArguments)
|
mirror.newInstance(new Symbol(constructorName), positionalArguments));
|
||||||
.reflectee as T;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -174,20 +175,16 @@ class _ReflectedInstanceMirror extends ReflectedInstance {
|
||||||
new _ReflectedClassMirror(mirror.type), mirror.reflectee);
|
new _ReflectedClassMirror(mirror.type), mirror.reflectee);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
T invoke<T>(Invocation invocation) {
|
ReflectedInstance getField(String name) {
|
||||||
return mirror.delegate(invocation) as T;
|
return new _ReflectedInstanceMirror(mirror.getField(new Symbol(name)));
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
T getField<T>(String name) {
|
|
||||||
return mirror.getField(new Symbol(name)).reflectee as T;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ReflectedMethodMirror extends ReflectedFunction {
|
class _ReflectedMethodMirror extends ReflectedFunction {
|
||||||
final dart.MethodMirror mirror;
|
final dart.MethodMirror mirror;
|
||||||
|
final dart.ClosureMirror closureMirror;
|
||||||
|
|
||||||
_ReflectedMethodMirror(this.mirror)
|
_ReflectedMethodMirror(this.mirror, [this.closureMirror])
|
||||||
: super(
|
: super(
|
||||||
dart.MirrorSystem.getName(mirror.simpleName),
|
dart.MirrorSystem.getName(mirror.simpleName),
|
||||||
<ReflectedTypeParameter>[],
|
<ReflectedTypeParameter>[],
|
||||||
|
@ -212,4 +209,17 @@ class _ReflectedMethodMirror extends ReflectedFunction {
|
||||||
!mirror.isOptional,
|
!mirror.isOptional,
|
||||||
mirror.isNamed);
|
mirror.isNamed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ReflectedInstance invoke(Invocation invocation) {
|
||||||
|
if (closureMirror == null) {
|
||||||
|
throw new StateError(
|
||||||
|
'This object was reflected without a ClosureMirror, and therefore cannot be directly invoked.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return new _ReflectedInstanceMirror(closureMirror.invoke(
|
||||||
|
invocation.memberName,
|
||||||
|
invocation.positionalArguments,
|
||||||
|
invocation.namedArguments));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,9 +27,7 @@ abstract class ReflectedInstance {
|
||||||
bool operator ==(other) =>
|
bool operator ==(other) =>
|
||||||
other is ReflectedInstance && other.type == type && other.clazz == clazz;
|
other is ReflectedInstance && other.type == type && other.clazz == clazz;
|
||||||
|
|
||||||
T invoke<T>(Invocation invocation);
|
ReflectedInstance getField(String name);
|
||||||
|
|
||||||
T getField<T>(String name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ReflectedType {
|
abstract class ReflectedType {
|
||||||
|
@ -50,7 +48,8 @@ abstract class ReflectedType {
|
||||||
.equals(other.typeParameters, typeParameters) &&
|
.equals(other.typeParameters, typeParameters) &&
|
||||||
other.reflectedType == reflectedType;
|
other.reflectedType == reflectedType;
|
||||||
|
|
||||||
T newInstance<T>(String constructorName, List positionalArguments,
|
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);
|
||||||
|
@ -104,7 +103,7 @@ class ReflectedDeclaration {
|
||||||
other.function == function;
|
other.function == function;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReflectedFunction {
|
abstract class ReflectedFunction {
|
||||||
final String name;
|
final String name;
|
||||||
final List<ReflectedTypeParameter> typeParameters;
|
final List<ReflectedTypeParameter> typeParameters;
|
||||||
final List<ReflectedInstance> annotations;
|
final List<ReflectedInstance> annotations;
|
||||||
|
@ -139,6 +138,8 @@ class ReflectedFunction {
|
||||||
.equals(other.parameters, other.parameters) &&
|
.equals(other.parameters, other.parameters) &&
|
||||||
other.isGetter == isGetter &&
|
other.isGetter == isGetter &&
|
||||||
other.isSetter == isSetter;
|
other.isSetter == isSetter;
|
||||||
|
|
||||||
|
ReflectedInstance invoke(Invocation invocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
class ReflectedParameter {
|
class ReflectedParameter {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: angel_container
|
name: angel_container
|
||||||
version: 1.0.0-alpha.6
|
version: 1.0.0-alpha.7
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
description: "A better IoC container and dependency injector for Angel, ultimately allowing Angel to be used without dart:mirrors."
|
description: "A better IoC container and dependency injector for Angel, ultimately allowing Angel to be used without dart:mirrors."
|
||||||
homepage: https://github.com/angel-dart/container.git
|
homepage: https://github.com/angel-dart/container.git
|
||||||
|
|
|
@ -14,7 +14,7 @@ void testReflector(Reflector reflector) {
|
||||||
|
|
||||||
test('get field', () {
|
test('get field', () {
|
||||||
var blazikenMirror = reflector.reflectInstance(blaziken);
|
var blazikenMirror = reflector.reflectInstance(blaziken);
|
||||||
expect(blazikenMirror.getField<PokemonType>('type'), blaziken.type);
|
expect(blazikenMirror.getField('type').reflectee, blaziken.type);
|
||||||
});
|
});
|
||||||
|
|
||||||
group('reflectFunction', () {
|
group('reflectFunction', () {
|
||||||
|
@ -63,7 +63,7 @@ void testReflector(Reflector reflector) {
|
||||||
test('newInstance works', () {
|
test('newInstance works', () {
|
||||||
var type = container.reflector.reflectType(Pokemon);
|
var type = container.reflector.reflectType(Pokemon);
|
||||||
var instance =
|
var instance =
|
||||||
type.newInstance('changeName', [blaziken, 'Charizard']) as Pokemon;
|
type.newInstance('changeName', [blaziken, 'Charizard']).reflectee as Pokemon;
|
||||||
print(instance);
|
print(instance);
|
||||||
expect(instance.name, 'Charizard');
|
expect(instance.name, 'Charizard');
|
||||||
expect(instance.type, PokemonType.fire);
|
expect(instance.type, PokemonType.fire);
|
||||||
|
|
138
angel_container/test/empty_reflector_test.dart
Normal file
138
angel_container/test/empty_reflector_test.dart
Normal 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 dynamic', () {
|
||||||
|
expect(mirror.reflectedType, dynamic);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 dynamic', () {
|
||||||
|
expect(mirror.reflectedType, dynamic);
|
||||||
|
});
|
||||||
|
|
||||||
|
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 = new Invocation.method(#drive, []);
|
||||||
|
expect(() => mirror.invoke(invocation), throwsUnsupportedError);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
group('reflectInstance', () {
|
||||||
|
var mirror = reflector.reflectInstance(new 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!!!');
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue