* Add EmptyReflector.

* `ReflectedType.newInstance` now returns a `ReflectedInstance`.
* Moved `ReflectedInstance.invoke` to `ReflectedFunction.invoke`.
This commit is contained in:
Tobe O 2018-08-21 10:18:11 -04:00
parent 3ec5749548
commit 3f12f4d581
9 changed files with 304 additions and 23 deletions

View file

@ -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
* Add `getField` to `ReflectedInstance`.

View file

@ -1,3 +1,4 @@
export 'src/empty/empty.dart';
export 'src/container.dart';
export 'src/exception.dart';
export 'src/reflector.dart';

View file

@ -76,7 +76,7 @@ class Container {
return reflectedType.newInstance(
isDefault(constructor.name) ? '' : constructor.name,
positional,
named, []);
named, []).reflectee;
} else {
throw new ReflectionException(
'$type is not a class, and therefore cannot be instantiated.');

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 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().');
}
}

View file

@ -26,7 +26,7 @@ class MirrorsReflector implements Reflector {
@override
ReflectedFunction reflectFunction(Function function) {
var closure = dart.reflect(function) as dart.ClosureMirror;
return new _ReflectedMethodMirror(closure.function);
return new _ReflectedMethodMirror(closure.function, closure);
}
@override
@ -75,7 +75,8 @@ class _ReflectedTypeMirror extends ReflectedType {
}
@override
T newInstance<T>(String constructorName, List positionalArguments,
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
throw new ReflectionException(
'$name is not a class, and therefore cannot be instantiated.');
@ -139,11 +140,11 @@ class _ReflectedClassMirror extends ReflectedClass {
}
@override
T newInstance<T>(String constructorName, List positionalArguments,
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]) {
return mirror
.newInstance(new Symbol(constructorName), positionalArguments)
.reflectee as T;
return new _ReflectedInstanceMirror(
mirror.newInstance(new Symbol(constructorName), positionalArguments));
}
@override
@ -174,20 +175,16 @@ class _ReflectedInstanceMirror extends ReflectedInstance {
new _ReflectedClassMirror(mirror.type), mirror.reflectee);
@override
T invoke<T>(Invocation invocation) {
return mirror.delegate(invocation) as T;
}
@override
T getField<T>(String name) {
return mirror.getField(new Symbol(name)).reflectee as T;
ReflectedInstance getField(String name) {
return new _ReflectedInstanceMirror(mirror.getField(new Symbol(name)));
}
}
class _ReflectedMethodMirror extends ReflectedFunction {
final dart.MethodMirror mirror;
final dart.ClosureMirror closureMirror;
_ReflectedMethodMirror(this.mirror)
_ReflectedMethodMirror(this.mirror, [this.closureMirror])
: super(
dart.MirrorSystem.getName(mirror.simpleName),
<ReflectedTypeParameter>[],
@ -212,4 +209,17 @@ class _ReflectedMethodMirror extends ReflectedFunction {
!mirror.isOptional,
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));
}
}

View file

@ -27,9 +27,7 @@ abstract class ReflectedInstance {
bool operator ==(other) =>
other is ReflectedInstance && other.type == type && other.clazz == clazz;
T invoke<T>(Invocation invocation);
T getField<T>(String name);
ReflectedInstance getField(String name);
}
abstract class ReflectedType {
@ -50,7 +48,8 @@ abstract class ReflectedType {
.equals(other.typeParameters, typeParameters) &&
other.reflectedType == reflectedType;
T newInstance<T>(String constructorName, List positionalArguments,
ReflectedInstance newInstance(
String constructorName, List positionalArguments,
[Map<String, dynamic> namedArguments, List<Type> typeArguments]);
bool isAssignableTo(ReflectedType other);
@ -104,7 +103,7 @@ class ReflectedDeclaration {
other.function == function;
}
class ReflectedFunction {
abstract class ReflectedFunction {
final String name;
final List<ReflectedTypeParameter> typeParameters;
final List<ReflectedInstance> annotations;
@ -139,6 +138,8 @@ class ReflectedFunction {
.equals(other.parameters, other.parameters) &&
other.isGetter == isGetter &&
other.isSetter == isSetter;
ReflectedInstance invoke(Invocation invocation);
}
class ReflectedParameter {

View file

@ -1,5 +1,5 @@
name: angel_container
version: 1.0.0-alpha.6
version: 1.0.0-alpha.7
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."
homepage: https://github.com/angel-dart/container.git

View file

@ -14,7 +14,7 @@ void testReflector(Reflector reflector) {
test('get field', () {
var blazikenMirror = reflector.reflectInstance(blaziken);
expect(blazikenMirror.getField<PokemonType>('type'), blaziken.type);
expect(blazikenMirror.getField('type').reflectee, blaziken.type);
});
group('reflectFunction', () {
@ -63,7 +63,7 @@ void testReflector(Reflector reflector) {
test('newInstance works', () {
var type = container.reflector.reflectType(Pokemon);
var instance =
type.newInstance('changeName', [blaziken, 'Charizard']) as Pokemon;
type.newInstance('changeName', [blaziken, 'Charizard']).reflectee as Pokemon;
print(instance);
expect(instance.name, 'Charizard');
expect(instance.type, PokemonType.fire);

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 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!!!');
}
}