From b3b6fc7855d1d7ceaa1c8bcfd7b577078c4747dd Mon Sep 17 00:00:00 2001 From: Pavel Jbanov Date: Thu, 14 Aug 2014 15:48:54 -0400 Subject: [PATCH] fix(injector): allow using static injector without transformers --- lib/di_static.dart | 7 ++ lib/module_transformer.dart | 4 +- lib/src/injector.dart | 2 +- lib/src/module.dart | 139 ++---------------------------------- lib/src/module_static.dart | 136 +++++++++++++++++++++++++++++++++++ lib/src/reflector.dart | 2 - 6 files changed, 153 insertions(+), 137 deletions(-) create mode 100644 lib/di_static.dart create mode 100644 lib/src/module_static.dart diff --git a/lib/di_static.dart b/lib/di_static.dart new file mode 100644 index 0000000..84c0da6 --- /dev/null +++ b/lib/di_static.dart @@ -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; diff --git a/lib/module_transformer.dart b/lib/module_transformer.dart index 5992a6e..69f4ed7 100644 --- a/lib/module_transformer.dart +++ b/lib/module_transformer.dart @@ -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\';'))); }); } } diff --git a/lib/src/injector.dart b/lib/src/injector.dart index fc4bdca..f3ed2b6 100644 --- a/lib/src/injector.dart +++ b/lib/src/injector.dart @@ -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); diff --git a/lib/src/module.dart b/lib/src/module.dart index 5694e58..852ca02 100644 --- a/lib/src/module.dart +++ b/lib/src/module.dart @@ -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 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 bindings = new Map(); - - /** - * 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); } diff --git a/lib/src/module_static.dart b/lib/src/module_static.dart new file mode 100644 index 0000000..814cc6d --- /dev/null +++ b/lib/src/module_static.dart @@ -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 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 bindings = new Map(); + + /** + * 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; + } +} diff --git a/lib/src/reflector.dart b/lib/src/reflector.dart index 9de6a73..21da2e7 100644 --- a/lib/src/reflector.dart +++ b/lib/src/reflector.dart @@ -1,8 +1,6 @@ library di.reflector; import "../key.dart"; -import "errors.dart"; -import "module.dart"; abstract class TypeReflector { /**