use reflectable

This commit is contained in:
Tobe O 2018-11-30 00:32:49 -05:00
parent f9a452bf06
commit 4e8845a410
14 changed files with 358 additions and 280 deletions

View file

@ -1,3 +1,6 @@
# 1.0.0
* Removed `@GenerateReflector`.
# 1.0.0-alpha.12
* `StaticReflector` now defaults to empty arguments.

View file

@ -4,36 +4,4 @@ export 'src/container.dart';
export 'src/empty/empty.dart';
export 'src/static/static.dart';
export 'src/exception.dart';
export 'src/reflector.dart';
/// An annotation used by `package:angel_container_generator` to generate reflection metadata for types chosen by the user.
///
/// When attached to a library, it generates a class that implements the `Reflector` interface.
///
/// When attached to a class, it can be used to customize the output of the generator.
class GenerateReflector {
/// The list of types that should have reflection metadata generated for them.
final List<Type> types;
/// The list of top-level functions that should have reflection metadata generated for them.
final List<Function> functions;
/// The list of symbols within this class that should have reflection metadata generated for them.
///
/// If omitted, then all symbols will be included.
final List<Symbol> symbols;
/// An explicit name for the generated reflector.
///
/// By default, a class with the library's name in PascalCase is created,
/// with the text "Reflector" appended.
///
/// Ex. `my_cool_library` becomes `const MyCoolLibraryReflector()`.
final String name;
const GenerateReflector(
{this.types: const <Type>[],
this.functions: const <Function>[],
this.symbols: const <Symbol>[],
this.name});
}
export 'src/reflector.dart';

View file

@ -1,5 +1,5 @@
name: angel_container
version: 1.0.0-alpha.12
version: 1.0.0
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
@ -8,7 +8,5 @@ environment:
dependencies:
collection: ^1.0.0
quiver: ^2.0.0
reflectable: ^2.0.0
dev_dependencies:
build_runner:
test:

View file

@ -1,12 +0,0 @@
builders:
angel_container:
import: "package:angel_container_generator/angel_container_generator.dart"
builder_factories:
- angelContainerBuilder
build_extensions:
.dart:
- ".reflector.g.dart"
auto_apply: root_package
build_to: source
required_inputs:
- .dart

View file

@ -1,8 +1,166 @@
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'package:angel_container/angel_container.dart';
import 'package:reflectable/reflectable.dart';
import 'src/generator.dart';
/// A [Reflectable] instance that can be used as an annotation on types to generate metadata for them.
const Reflectable contained = const ContainedReflectable();
Builder angelContainerBuilder(_) {
return new PartBuilder([new AngelContainerGenerator()], '.reflector.g.dart');
class ContainedReflectable extends Reflectable {
const ContainedReflectable()
: super(
declarationsCapability,
instanceInvokeCapability,
invokingCapability,
metadataCapability,
newInstanceCapability,
reflectedTypeCapability,
typeRelationsCapability);
}
/// A [Reflector] instance that uses a [Reflectable] to reflect upon data.
class GeneratedReflector implements Reflector {
final Reflectable reflectable;
const GeneratedReflector([this.reflectable = contained]);
@override
String getName(Symbol symbol) {
// TODO: implement getName
throw new UnimplementedError();
}
@override
ReflectedClass reflectClass(Type clazz) {
return reflectType(clazz) as ReflectedClass;
}
@override
ReflectedFunction reflectFunction(Function function) {
// TODO: implement reflectFunction
throw new UnimplementedError();
}
@override
ReflectedInstance reflectInstance(Object object) {
if (!reflectable.canReflect(object)) {
throw new UnsupportedError('Cannot reflect $object.');
} else {
return new _GeneratedReflectedInstance(reflectable.reflect(object), 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;
_GeneratedReflectedInstance(this.mirror, Reflector reflector)
: super(null, new _GeneratedReflectedClass(mirror.type, reflector),
mirror.reflectee);
@override
ReflectedType get type => clazz;
@override
ReflectedInstance getField(String name) {
return mirror.invokeGetter(name);
}
}
class _GeneratedReflectedClass extends ReflectedClass {
final ClassMirror mirror;
final Reflector reflector;
_GeneratedReflectedClass(this.mirror, this.reflector)
: super(
mirror.simpleName,
mirror.typeVariables.map(_convertTypeVariable).toList(),
null,
_constructorsOf(mirror.declarations, reflector),
_declarationsOf(mirror.declarations, reflector),
mirror.reflectedType);
@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]) {
return mirror.newInstance(constructorName, positionalArguments,
namedArguments.map((k, v) => new MapEntry(new Symbol(k), v)));
}
}
class _GeneratedReflectedType extends ReflectedType {
final TypeMirror mirror;
_GeneratedReflectedType(this.mirror)
: super(
mirror.simpleName,
mirror.typeVariables.map(_convertTypeVariable).toList(),
mirror.reflectedType);
@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.');
}
}
// TODO: Reflect functions?
List<ReflectedFunction> _constructorsOf(
Map<String, DeclarationMirror> map, Reflector reflector) {
print(map);
return map.entries.fold<List<ReflectedFunction>>([], (out, entry) {
var k = entry.key, v = entry.value;
return out;
});
}
List<ReflectedDeclaration> _declarationsOf(
Map<String, DeclarationMirror> map, Reflector reflector) {
print(map);
return map.entries.fold<List<ReflectedDeclaration>>([], (out, entry) {
var k = entry.key, v = entry.value;
});
}
ReflectedTypeParameter _convertTypeVariable(TypeVariableMirror mirror) {
return new ReflectedTypeParameter(mirror.simpleName);
}

View file

@ -1,31 +0,0 @@
import 'dart:async';
import 'package:analyzer/dart/element/element.dart';
import 'package:angel_container/angel_container.dart';
import 'package:build/build.dart';
import 'package:source_gen/source_gen.dart';
import 'library_generator.dart';
import 'util.dart';
class AngelContainerGenerator
extends GeneratorForAnnotation<GenerateReflector> {
@override
FutureOr<String> generate(LibraryReader library, BuildStep buildStep) {
var annotation = typeChecker.firstAnnotationOf(library.element);
if (annotation == null) {
return null;
} else {
var reader = new GenerateReflectorReader(new ConstantReader(annotation));
var generator = new ReflectorLibraryGenerator(library.element, reader);
return generator.toSource();
}
}
@override
generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep) {
throw new UnimplementedError();
}
}

View file

@ -1,116 +0,0 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:angel_container/angel_container.dart';
import 'package:code_builder/code_builder.dart';
import 'package:recase/recase.dart';
import 'util.dart';
class ReflectorLibraryGenerator {
final LibraryElement element;
final GenerateReflectorReader annotation;
ReflectorLibraryGenerator(this.element, this.annotation);
String get reflectorClassName {
// Select the name
if (annotation.name?.isNotEmpty == true) {
return new ReCase(annotation.name).pascalCase + 'Reflector';
} else if (element.name?.isNotEmpty == true) {
var rc = new ReCase(element.name);
return rc.pascalCase + 'Reflector';
} else {
throw new StateError(
'A statically-generated Reflector must reside in a named library, or include the `name` attribute in @GenerateReflector().');
}
}
String get typeMapName => new ReCase(reflectorClassName).camelCase + 'Types';
String toSource() {
return generate().accept(new DartEmitter()).toString();
}
Library generate() {
return new Library((lib) {
var clazz = generateReflectorClass();
// Generate a ReflectedClass for each type
var staticTypes = <String, Expression>{};
for (var type in annotation.types) {
if (type is InterfaceType) {
var reflected = generateReflectedClass(type);
lib.body.add(reflected);
staticTypes[type.name] =
refer(reflected.name).constInstanceNamed('_', []);
} else {
// TODO: Handle these
}
}
clazz = clazz.rebuild((b) {
// Generate static values
b.fields.add(new Field((b) => b
..name = 'staticTypes'
..modifier = FieldModifier.constant
..static = true
..assignment = literalConstMap(staticTypes
.map((name, type) => new MapEntry(refer(name), type))).code));
});
lib.body.add(clazz);
});
}
Class generateReflectorClass() {
return new Class((clazz) {
clazz.name = reflectorClassName;
// extends StaticReflector
clazz.extend = refer('StaticReflector');
// Add a const constructor
clazz.constructors.add(new Constructor((b) {
b
..constant = true
..initializers.add(
refer('super').call([], {'types': refer('staticTypes')}).code);
// TODO: Invoke super with static info
}));
});
}
Reference _convertDartType(DartType type) {
if (type is InterfaceType) {
return new TypeReference((b) => b
..symbol = type.name
..types.addAll(type.typeArguments.map(_convertDartType)));
} else {
return refer(type.name);
}
}
Class generateReflectedClass(InterfaceType type) {
return new Class((clazz) {
var rc = new ReCase(type.name);
clazz
..name = '_Reflected${rc.pascalCase}'
..extend = refer('ReflectedClass');
// Add const constructor
var superArgs = <Expression>[
literalString(type.name), // name
literalConstList([]), // typeParameters
literalConstList([]), // annotations
literalConstList([]), // constructors
literalConstList([]), // declarations,
_convertDartType(type), // reflectedType
];
clazz.constructors.add(new Constructor((b) => b
..constant = true
..name = '_'
..initializers.add(refer('super').call(superArgs).code)));
});
}
}

View file

@ -1,35 +0,0 @@
import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:angel_container/angel_container.dart';
import 'package:source_gen/source_gen.dart';
const TypeChecker generateReflectorTypeChecker =
const TypeChecker.fromRuntime(GenerateReflector);
/// Reads data from a [GenerateReflector] annotation.
class GenerateReflectorReader {
final ConstantReader annotation;
GenerateReflectorReader(this.annotation);
String get name => annotation.peek('name')?.stringValue;
List<DartType> get types =>
annotation
.peek('types')
?.listValue
?.map((o) => ConstantReader(o).typeValue)
?.toList() ??
<DartType>[];
List<Symbol> get symbols =>
annotation
.peek('symbols')
?.listValue
?.map((o) => ConstantReader(o).symbolValue)
?.toList() ??
<Symbol>[];
List<DartObject> get functions =>
annotation.peek('functions')?.listValue ?? <DartObject>[];
}

View file

@ -7,11 +7,7 @@ environment:
sdk: ">=2.0.0-dev <3.0.0"
dependencies:
angel_container: ^1.0.0-alpha
build: ^0.12.0
build_config: ^0.3.0
code_builder: ^3.0.0
recase: ^2.0.0
source_gen: ^0.9.0
reflectable: ^2.0.0
dev_dependencies:
build_runner: ^0.10.0
build_runner: ^1.0.0
test: ^1.0.0

View file

@ -1,21 +0,0 @@
@GenerateReflector(types: [Artist])
library angel_container_generator_test;
import 'package:angel_container/angel_container.dart';
import 'package:test/test.dart';
part 'reflector.reflector.g.dart';
void main() {
var reflector = const AngelContainerGeneratorTestReflector();
group('reflectClass', () {
var mirror = reflector.reflectClass(Artist);
test('name', () {
expect(mirror.name, 'Artist');
});
});
}
class Artist {}

View file

@ -1,18 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of angel_container_generator_test;
// **************************************************************************
// AngelContainerGenerator
// **************************************************************************
class _ReflectedArtist extends ReflectedClass {
const _ReflectedArtist._()
: super('Artist', const [], const [], const [], const [], Artist);
}
class AngelContainerGeneratorTestReflector extends StaticReflector {
const AngelContainerGeneratorTestReflector() : super(types: staticTypes);
static const staticTypes = const {Artist: const _ReflectedArtist._()};
}

View file

@ -0,0 +1,21 @@
import 'package:angel_container_generator/angel_container_generator.dart';
import 'package:test/test.dart';
import 'reflector_test.reflectable.dart';
void main() {
var reflector = const GeneratedReflector();
initializeReflectable();
group('reflectClass', () {
var mirror = reflector.reflectClass(Artist);
test('name', () {
expect(mirror.name, 'Artist');
});
});
}
@contained
class Artist {
String name;
}

View file

@ -0,0 +1,167 @@
// This file has been generated by the reflectable package.
// https://github.com/dart-lang/reflectable.
import "dart:core";
import 'package:angel_container_generator/angel_container_generator.dart'
as prefix0;
import 'reflector_test.dart' as prefix1;
// ignore:unused_import
import "package:reflectable/mirrors.dart" as m;
// ignore:unused_import
import "package:reflectable/src/reflectable_builder_based.dart" as r;
// ignore:unused_import
import "package:reflectable/reflectable.dart" as r show Reflectable;
final _data = <r.Reflectable, r.ReflectorData>{
const prefix0.ContainedReflectable(): new r.ReflectorData(
<m.TypeMirror>[
new r.NonGenericClassMirrorImpl(
r"Artist",
r".Artist",
7,
0,
const prefix0.ContainedReflectable(),
const <int>[0, 3],
const <int>[4, 5, 6, 7, 8, 1, 2],
const <int>[],
-1,
{},
{},
{r"": (b) => () => b ? new prefix1.Artist() : null},
-1,
0,
const <int>[],
const <Object>[prefix0.contained],
null)
],
<m.DeclarationMirror>[
new r.VariableMirrorImpl(
r"name",
32773,
0,
const prefix0.ContainedReflectable(),
-1,
1,
1, const <int>[], const <Object>[]),
new r.ImplicitGetterMirrorImpl(
const prefix0.ContainedReflectable(), 0, 1, 1, 1),
new r.ImplicitSetterMirrorImpl(
const prefix0.ContainedReflectable(), 0, 1, 1, 2),
new r.MethodMirrorImpl(r"", 64, 0, -1, 0, 0, const <int>[],
const <int>[], const prefix0.ContainedReflectable(), const []),
new r.MethodMirrorImpl(
r"==",
131074,
null,
-1,
2,
2,
const <int>[],
const <int>[1],
const prefix0.ContainedReflectable(),
const <Object>[]),
new r.MethodMirrorImpl(
r"toString",
131074,
null,
-1,
1,
1,
const <int>[],
const <int>[],
const prefix0.ContainedReflectable(),
const <Object>[]),
new r.MethodMirrorImpl(
r"noSuchMethod",
65538,
null,
null,
null,
null,
const <int>[],
const <int>[2],
const prefix0.ContainedReflectable(),
const <Object>[const pragma("vm:entry-point")]),
new r.MethodMirrorImpl(
r"hashCode",
131075,
null,
-1,
3,
3,
const <int>[],
const <int>[],
const prefix0.ContainedReflectable(),
const <Object>[]),
new r.MethodMirrorImpl(
r"runtimeType",
131075,
null,
-1,
4,
4,
const <int>[],
const <int>[],
const prefix0.ContainedReflectable(),
const <Object>[])
],
<m.ParameterMirror>[
new r.ParameterMirrorImpl(
r"_name",
32870,
2,
const prefix0.ContainedReflectable(),
-1,
1,
1,
const <int>[],
const [],
null,
null),
new r.ParameterMirrorImpl(
r"other",
16390,
4,
const prefix0.ContainedReflectable(),
null,
null,
null,
const <int>[],
const <Object>[],
null,
null),
new r.ParameterMirrorImpl(
r"invocation",
32774,
6,
const prefix0.ContainedReflectable(),
-1,
5,
5,
const <int>[],
const <Object>[],
null,
null)
],
<Type>[prefix1.Artist, String, bool, int, Type, Invocation],
1,
{
r"==": (dynamic instance) => (x) => instance == x,
r"toString": (dynamic instance) => instance.toString,
r"noSuchMethod": (dynamic instance) => instance.noSuchMethod,
r"hashCode": (dynamic instance) => instance.hashCode,
r"runtimeType": (dynamic instance) => instance.runtimeType,
r"name": (dynamic instance) => instance.name
},
{r"name=": (dynamic instance, value) => instance.name = value},
null,
[])
};
final _memberSymbolMap = null;
initializeReflectable() {
r.data = _data;
r.memberSymbolMap = _memberSymbolMap;
}