Start
This commit is contained in:
parent
4d00db78bc
commit
24b03ce71c
14 changed files with 425 additions and 0 deletions
0
.gitignore → angel_container/.gitignore
vendored
0
.gitignore → angel_container/.gitignore
vendored
21
angel_container/LICENSE
Normal file
21
angel_container/LICENSE
Normal 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.
|
2
angel_container/README.md
Normal file
2
angel_container/README.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# container
|
||||||
|
A better IoC container for Angel, ultimately allowing Angel to be used without dart:mirrors.
|
3
angel_container/lib/angel_container.dart
Normal file
3
angel_container/lib/angel_container.dart
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export 'src/container.dart';
|
||||||
|
export 'src/exception.dart';
|
||||||
|
export 'src/reflector.dart';
|
1
angel_container/lib/mirrors.dart
Normal file
1
angel_container/lib/mirrors.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export 'src/mirrors/mirrors.dart';
|
51
angel_container/lib/src/container.dart
Normal file
51
angel_container/lib/src/container.dart
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import 'exception.dart';
|
||||||
|
import 'reflector.dart';
|
||||||
|
|
||||||
|
class Container {
|
||||||
|
final Reflector reflector;
|
||||||
|
final Map<Type, dynamic> _singletons = {};
|
||||||
|
|
||||||
|
Container(this.reflector);
|
||||||
|
|
||||||
|
T make<T>(Type type) {
|
||||||
|
if (_singletons.containsKey(type)) {
|
||||||
|
return _singletons[type] as T;
|
||||||
|
} else {
|
||||||
|
var reflectedType = reflector.reflectType(type);
|
||||||
|
var positional = [];
|
||||||
|
var named = <String, dynamic>{};
|
||||||
|
|
||||||
|
if (reflectedType is ReflectedClass) {
|
||||||
|
var constructor = reflectedType.constructors.firstWhere(
|
||||||
|
(c) => c.name.isEmpty,
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (param.isNamed) {
|
||||||
|
named[param.name] = value;
|
||||||
|
} else {
|
||||||
|
positional.add(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reflectedType
|
||||||
|
.newInstance(constructor.name, positional, named, []);
|
||||||
|
} else {
|
||||||
|
throw new ReflectionException(
|
||||||
|
'$type is not a class, and therefore cannot be instantiated.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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}.');
|
||||||
|
}
|
||||||
|
|
||||||
|
_singletons[as ?? object.runtimeType] = object;
|
||||||
|
}
|
||||||
|
}
|
8
angel_container/lib/src/exception.dart
Normal file
8
angel_container/lib/src/exception.dart
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
class ReflectionException implements Exception {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
ReflectionException(this.message);
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() => message;
|
||||||
|
}
|
1
angel_container/lib/src/mirrors/mirrors.dart
Normal file
1
angel_container/lib/src/mirrors/mirrors.dart
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export 'reflector.dart';
|
127
angel_container/lib/src/mirrors/reflector.dart
Normal file
127
angel_container/lib/src/mirrors/reflector.dart
Normal file
|
@ -0,0 +1,127 @@
|
||||||
|
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';
|
||||||
|
|
||||||
|
class MirrorsReflector implements Reflector {
|
||||||
|
@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 new _ReflectedClassMirror(mirror);
|
||||||
|
} else {
|
||||||
|
throw new ArgumentError('$clazz is not a class.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ReflectedFunction reflectFunction(Function function) {
|
||||||
|
// TODO: implement reflectFunction
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
ReflectedType reflectType(Type type) {
|
||||||
|
var mirror = dart.reflectType(type);
|
||||||
|
|
||||||
|
if (mirror is dart.ClassMirror) {
|
||||||
|
return new _ReflectedClassMirror(mirror);
|
||||||
|
} else {
|
||||||
|
return new _ReflectedTypeMirror(mirror);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ReflectedTypeParameter extends ReflectedTypeParameter {
|
||||||
|
final dart.TypeVariableMirror mirror;
|
||||||
|
|
||||||
|
_ReflectedTypeParameter(this.mirror)
|
||||||
|
: super(
|
||||||
|
dart.MirrorSystem.getName(mirror.simpleName), mirror.reflectedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ReflectedTypeMirror extends ReflectedType {
|
||||||
|
final dart.TypeMirror mirror;
|
||||||
|
|
||||||
|
_ReflectedTypeMirror(this.mirror)
|
||||||
|
: super(
|
||||||
|
dart.MirrorSystem.getName(mirror.simpleName),
|
||||||
|
mirror.typeVariables
|
||||||
|
.map((m) => new _ReflectedTypeParameter(m))
|
||||||
|
.toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool isAssignableTo(ReflectedType other) {
|
||||||
|
return other is _ReflectedTypeMirror && mirror.isAssignableTo(other.mirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
T newInstance<T>(String constructorName, List positionalArguments,
|
||||||
|
Map<String, dynamic> namedArguments, List<Type> typeArguments) {
|
||||||
|
throw new 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) => new _ReflectedTypeParameter(m))
|
||||||
|
.toList(),
|
||||||
|
mirror.metadata.map((m) => new _ReflectedInstanceMirror(m)).toList(),
|
||||||
|
_constructorsOf(mirror),
|
||||||
|
_declarationsOf(mirror),
|
||||||
|
);
|
||||||
|
|
||||||
|
static List<ReflectedFunction> _constructorsOf(dart.ClassMirror mirror) {
|
||||||
|
var out = <ReflectedFunction>[];
|
||||||
|
|
||||||
|
for (var key in mirror.declarations.keys) {
|
||||||
|
var value = mirror.declarations[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<ReflectedDeclaration> _declarationsOf(dart.ClassMirror mirror) {
|
||||||
|
var out = <ReflectedDeclaration>[];
|
||||||
|
|
||||||
|
for (var key in mirror.declarations.keys) {
|
||||||
|
var value = mirror.declarations[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool isAssignableTo(ReflectedType other) {
|
||||||
|
return other is _ReflectedTypeMirror && mirror.isAssignableTo(other.mirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
T newInstance<T>(String constructorName, List positionalArguments,
|
||||||
|
Map<String, dynamic> namedArguments, List<Type> typeArguments) {
|
||||||
|
// TODO: implement newInstance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ReflectedInstanceMirror extends ReflectedInstance {
|
||||||
|
final dart.InstanceMirror mirror;
|
||||||
|
|
||||||
|
_ReflectedInstanceMirror(this.mirror)
|
||||||
|
: super(new _ReflectedClassMirror(mirror.type),
|
||||||
|
new _ReflectedClassMirror(mirror.type));
|
||||||
|
|
||||||
|
@override
|
||||||
|
T invoke<T>(Invocation invocation) {
|
||||||
|
return mirror.delegate(invocation) as T;
|
||||||
|
}
|
||||||
|
}
|
171
angel_container/lib/src/reflector.dart
Normal file
171
angel_container/lib/src/reflector.dart
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
|
import 'package:quiver_hashcode/hashcode.dart';
|
||||||
|
|
||||||
|
abstract class Reflector {
|
||||||
|
String getName(Symbol symbol);
|
||||||
|
|
||||||
|
ReflectedClass reflectClass(Type clazz);
|
||||||
|
|
||||||
|
ReflectedFunction reflectFunction(Function function);
|
||||||
|
|
||||||
|
ReflectedType reflectType(Type type);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ReflectedInstance {
|
||||||
|
final ReflectedType type;
|
||||||
|
final ReflectedClass clazz;
|
||||||
|
|
||||||
|
const ReflectedInstance(this.type, this.clazz);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => hash2(type, clazz);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(other) =>
|
||||||
|
other is ReflectedInstance && other.type == type && other.clazz == clazz;
|
||||||
|
|
||||||
|
T invoke<T>(Invocation invocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ReflectedType {
|
||||||
|
final String name;
|
||||||
|
final List<ReflectedTypeParameter> typeParameters;
|
||||||
|
|
||||||
|
const ReflectedType(this.name, this.typeParameters);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => hash2(name, typeParameters);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(other) =>
|
||||||
|
other is ReflectedType &&
|
||||||
|
other.name == name &&
|
||||||
|
const ListEquality<ReflectedTypeParameter>()
|
||||||
|
.equals(other.typeParameters, typeParameters);
|
||||||
|
|
||||||
|
T newInstance<T>(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)
|
||||||
|
: super(name, typeParameters);
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReflectedFunction {
|
||||||
|
final String name;
|
||||||
|
final List<ReflectedTypeParameter> typeParameters;
|
||||||
|
final List<ReflectedInstance> annotations;
|
||||||
|
final Type 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ReflectedParameter {
|
||||||
|
final String name;
|
||||||
|
final List<ReflectedInstance> annotations;
|
||||||
|
final Type 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;
|
||||||
|
final Type type;
|
||||||
|
|
||||||
|
const ReflectedTypeParameter(this.name, this.type);
|
||||||
|
|
||||||
|
@override
|
||||||
|
int get hashCode => hash2(name, type);
|
||||||
|
|
||||||
|
@override
|
||||||
|
bool operator ==(other) =>
|
||||||
|
other is ReflectedTypeParameter &&
|
||||||
|
other.name == name &&
|
||||||
|
other.type == type;
|
||||||
|
}
|
4
angel_container/pubspec.yaml
Normal file
4
angel_container/pubspec.yaml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
name: angel_container
|
||||||
|
dependencies:
|
||||||
|
collection: ^1.0.0
|
||||||
|
quiver_hashcode: ^1.0.0
|
13
angel_container_generator/.gitignore
vendored
Normal file
13
angel_container_generator/.gitignore
vendored
Normal 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/
|
21
angel_container_generator/LICENSE
Normal file
21
angel_container_generator/LICENSE
Normal 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.
|
2
angel_container_generator/README.md
Normal file
2
angel_container_generator/README.md
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
# container
|
||||||
|
A better IoC container for Angel, ultimately allowing Angel to be used without dart:mirrors.
|
Loading…
Reference in a new issue