Skip to content
This repository was archived by the owner on Dec 6, 2017. It is now read-only.

fix(injector): allow using static injector without transformers #169

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/di_static.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
library di_static;

export 'key.dart' show Key, key;
export 'src/injector.dart' show Injector, ModuleInjector;
export 'src/module_static.dart' show Module, Binding, DEFAULT_VALUE;
export 'src/reflector.dart' show TypeReflector;
export 'src/errors.dart' hide BaseError, PRIMITIVE_TYPES;
4 changes: 2 additions & 2 deletions lib/module_transformer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ class ModuleTransformer extends Transformer {
// Note: this rewrite is coupled with how module.dart is
// written. Make sure both are updated in sync.
transform.addOutput(new Asset.fromString(id, code
.replaceAll(new RegExp('import "reflector_dynamic.dart";'),
'import "reflector_null.dart";')));
.replaceAll(new RegExp('import \'reflector_dynamic.dart\';'),
'import \'reflector_null.dart\';')));
});
}
}
2 changes: 1 addition & 1 deletion lib/src/injector.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
library di.injector;

import '../key.dart';
import 'module.dart';
import 'module_static.dart';
import 'errors.dart';

final Key _INJECTOR_KEY = new Key(Injector);
Expand Down
139 changes: 7 additions & 132 deletions lib/src/module.dart
Original file line number Diff line number Diff line change
@@ -1,140 +1,15 @@
library di.module;

import "../key.dart";
import "../check_bind_args.dart" show checkBindArgs;
import "reflector.dart";
import "reflector_dynamic.dart";
import "errors.dart" show PRIMITIVE_TYPES;
import 'reflector.dart' show TypeReflector;
import 'reflector_dynamic.dart';

DEFAULT_VALUE(_) => null;
IDENTITY(p) => p;
import 'module_static.dart' as module_static;
export 'module_static.dart' hide Module;

class Binding {
Key key;
List<Key> parameterKeys;
Function factory;
static bool printInjectWarning = true;

_checkPrimitive(Key key) {
if (PRIMITIVE_TYPES.contains(key)) {
throw "Cannot bind primitive type '${key.type}'.";
}
return true;
}

void bind(k, TypeReflector reflector, {toValue: DEFAULT_VALUE,
Function toFactory: DEFAULT_VALUE, Type toImplementation,
List inject: const[], toInstanceOf}) {
key = k;
assert(_checkPrimitive(k));
if (inject.length == 1 && isNotSet(toFactory)) {
if (printInjectWarning) {
try {
throw [];
} catch (e, stackTrace) {
print("bind(${k.type}): Inject list without toFactory is deprecated. "
"Use `toInstanceOf: Type|Key` instead. "
"Called from:\n$stackTrace");
}
printInjectWarning = false;
}
toFactory = IDENTITY;
}
assert(checkBindArgs(toValue, toFactory, toImplementation, inject, toInstanceOf));

if (toInstanceOf != null) {
toFactory = IDENTITY;
inject = [toInstanceOf];
}
if (isSet(toValue)) {
factory = () => toValue;
parameterKeys = const [];
} else if (isSet(toFactory)) {
factory = toFactory;
parameterKeys = inject.map((t) {
if (t is Key) return t;
if (t is Type) return new Key(t);
throw "inject must be Keys or Types. '$t' is not an instance of Key or Type.";
}).toList(growable: false);
} else {
var implementationType = toImplementation == null ? key.type : toImplementation;
parameterKeys = reflector.parameterKeysFor(implementationType);
factory = reflector.factoryFor(implementationType);
}
}
}

bool isSet(val) => !identical(val, DEFAULT_VALUE);
bool isNotSet(val) => !isSet(val);

/**
* Module contributes configuration information to an [Injector] by providing
* a collection of type bindings that specify how each type is created.
*
* When an injector is created, it copies its configuration information from a
* module. Defining additional type bindings after an injector is created has
* no effect on that injector.
*/
class Module {
class Module extends module_static.Module {
static TypeReflector DEFAULT_REFLECTOR = getReflector();

/**
* A [TypeReflector] for the module to look up constructors for types when
* toFactory and toValue are not specified. This is done with mirroring or
* pre-generated typeFactories.
*/
final TypeReflector reflector;

Module(): reflector = DEFAULT_REFLECTOR;

/**
* Use a custom reflector instead of the default. Useful for testing purposes.
*/
Module.withReflector(this.reflector);

Map<Key, Binding> bindings = new Map<Key, Binding>();

/**
* Copies all bindings of [module] into this one. Overwriting when conflicts are found.
*/
void install(Module module) => bindings.addAll(module.bindings);

/**
* Registers a binding for a given [type].
*
* The default behavior is to simply instantiate the type.
*
* The following parameters can be specified:
*
* * [toImplementation]: The given type will be instantiated using the [new]
* operator and the resulting instance will be injected.
* * [toFactory]: The result of the factory function called with the types of [inject] as
* arguments is the value that will be injected.
* * [toValue]: The given value will be injected.
* * [toInstanceOf]: An instance of the given type will be fetched with DI. This is shorthand for
* toFactory: (x) => x, inject: [X].
* * [withAnnotation]: Type decorated with additional annotation.
*
* Up to one (0 or 1) of the following parameters can be specified at the
* same time: [toImplementation], [toFactory], [toValue], [toInstanceOf].
*/
void bind(Type type, {dynamic toValue: DEFAULT_VALUE,
Function toFactory: DEFAULT_VALUE, Type toImplementation,
List inject: const [], toInstanceOf, Type withAnnotation}) {
bindByKey(new Key(type, withAnnotation), toValue: toValue, toInstanceOf: toInstanceOf,
toFactory: toFactory, toImplementation: toImplementation, inject: inject);
}

/**
* Same as [bind] except it takes [Key] instead of
* [Type] [withAnnotation] combination. Faster.
*/
void bindByKey(Key key, {dynamic toValue: DEFAULT_VALUE, toInstanceOf,
Function toFactory: DEFAULT_VALUE, List inject: const [], Type toImplementation}) {
Module() : super.withReflector(getReflector());

var binding = new Binding();
binding.bind(key, reflector, toValue: toValue, toFactory: toFactory, toInstanceOf: toInstanceOf,
toImplementation: toImplementation, inject: inject);
bindings[key] = binding;
}
Module.withReflector(reflector) : super.withReflector(reflector);
}
136 changes: 136 additions & 0 deletions lib/src/module_static.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
library di.module_static;

import '../key.dart';
import '../check_bind_args.dart' show checkBindArgs;
import 'reflector.dart';
import 'errors.dart' show PRIMITIVE_TYPES;

DEFAULT_VALUE(_) => null;
IDENTITY(p) => p;

class Binding {
Key key;
List<Key> parameterKeys;
Function factory;
static bool printInjectWarning = true;

_checkPrimitive(Key key) {
if (PRIMITIVE_TYPES.contains(key)) {
throw "Cannot bind primitive type '${key.type}'.";
}
return true;
}

void bind(k, TypeReflector reflector, {toValue: DEFAULT_VALUE,
Function toFactory: DEFAULT_VALUE, Type toImplementation,
List inject: const[], toInstanceOf}) {
key = k;
assert(_checkPrimitive(k));
if (inject.length == 1 && isNotSet(toFactory)) {
if (printInjectWarning) {
try {
throw [];
} catch (e, stackTrace) {
print("bind(${k.type}): Inject list without toFactory is deprecated. "
"Use `toInstanceOf: Type|Key` instead. "
"Called from:\n$stackTrace");
}
printInjectWarning = false;
}
toFactory = IDENTITY;
}
assert(checkBindArgs(toValue, toFactory, toImplementation, inject, toInstanceOf));

if (toInstanceOf != null) {
toFactory = IDENTITY;
inject = [toInstanceOf];
}
if (isSet(toValue)) {
factory = () => toValue;
parameterKeys = const [];
} else if (isSet(toFactory)) {
factory = toFactory;
parameterKeys = inject.map((t) {
if (t is Key) return t;
if (t is Type) return new Key(t);
throw "inject must be Keys or Types. '$t' is not an instance of Key or Type.";
}).toList(growable: false);
} else {
var implementationType = toImplementation == null ? key.type : toImplementation;
parameterKeys = reflector.parameterKeysFor(implementationType);
factory = reflector.factoryFor(implementationType);
}
}
}

bool isSet(val) => !identical(val, DEFAULT_VALUE);
bool isNotSet(val) => !isSet(val);

/**
* Module contributes configuration information to an [Injector] by providing
* a collection of type bindings that specify how each type is created.
*
* When an injector is created, it copies its configuration information from a
* module. Defining additional type bindings after an injector is created has
* no effect on that injector.
*/
class Module {

/**
* A [TypeReflector] for the module to look up constructors for types when
* toFactory and toValue are not specified. This is done with mirroring or
* pre-generated typeFactories.
*/
final TypeReflector reflector;

/**
* Use a custom reflector instead of the default. Useful for testing purposes.
*/
Module.withReflector(this.reflector);

Map<Key, Binding> bindings = new Map<Key, Binding>();

/**
* Copies all bindings of [module] into this one. Overwriting when conflicts are found.
*/
void install(Module module) => bindings.addAll(module.bindings);

/**
* Registers a binding for a given [type].
*
* The default behavior is to simply instantiate the type.
*
* The following parameters can be specified:
*
* * [toImplementation]: The given type will be instantiated using the [new]
* operator and the resulting instance will be injected.
* * [toFactory]: The result of the factory function called with the types of [inject] as
* arguments is the value that will be injected.
* * [toValue]: The given value will be injected.
* * [toInstanceOf]: An instance of the given type will be fetched with DI. This is shorthand for
* toFactory: (x) => x, inject: [X].
* * [withAnnotation]: Type decorated with additional annotation.
*
* Up to one (0 or 1) of the following parameters can be specified at the
* same time: [toImplementation], [toFactory], [toValue], [toInstanceOf].
*/
void bind(Type type, {dynamic toValue: DEFAULT_VALUE,
Function toFactory: DEFAULT_VALUE, Type toImplementation,
List inject: const [], toInstanceOf, Type withAnnotation}) {
bindByKey(new Key(type, withAnnotation), toValue: toValue, toInstanceOf: toInstanceOf,
toFactory: toFactory, toImplementation: toImplementation, inject: inject);
}

/**
* Same as [bind] except it takes [Key] instead of
* [Type] [withAnnotation] combination. Faster.
*/
void bindByKey(Key key, {dynamic toValue: DEFAULT_VALUE, toInstanceOf,
Function toFactory: DEFAULT_VALUE, List inject: const [], Type toImplementation}) {

var binding = new Binding();
binding.bind(key, reflector, toValue: toValue, toFactory: toFactory, toInstanceOf: toInstanceOf,
toImplementation: toImplementation, inject: inject);
bindings[key] = binding;
}
}
2 changes: 0 additions & 2 deletions lib/src/reflector.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
library di.reflector;

import "../key.dart";
import "errors.dart";
import "module.dart";

abstract class TypeReflector {
/**
Expand Down