feat(injector): implement InjectLazy
This commit is contained in:
parent
e02cdfe733
commit
a0176273c5
|
@ -12,4 +12,11 @@ export class InjectFuture {
|
|||
constructor(token){
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
|
||||
export class InjectLazy {
|
||||
@CONST()
|
||||
constructor(token){
|
||||
this.token = token;
|
||||
}
|
||||
}
|
|
@ -59,6 +59,6 @@ export class BindingBuilder {
|
|||
}
|
||||
|
||||
_constructDependencies(deps:List) {
|
||||
return ListWrapper.map(deps, (t) => new Dependency(Key.get(t), false));
|
||||
return ListWrapper.map(deps, (t) => new Dependency(Key.get(t), false, false));
|
||||
}
|
||||
}
|
|
@ -37,11 +37,11 @@ export class Injector {
|
|||
}
|
||||
|
||||
getByKey(key:Key) {
|
||||
return this._getByKey(key, false);
|
||||
return this._getByKey(key, false, false);
|
||||
}
|
||||
|
||||
asyncGetByKey(key:Key) {
|
||||
return this._getByKey(key, true);
|
||||
return this._getByKey(key, true, false);
|
||||
}
|
||||
|
||||
createChild(bindings:List):Injector {
|
||||
|
@ -61,7 +61,11 @@ export class Injector {
|
|||
return ListWrapper.createFixedSize(Key.numberOfKeys() + 1);
|
||||
}
|
||||
|
||||
_getByKey(key:Key, returnFuture) {
|
||||
_getByKey(key:Key, returnFuture, returnLazy) {
|
||||
if (returnLazy) {
|
||||
return () => this._getByKey(key, returnFuture, false);
|
||||
}
|
||||
|
||||
var strategy = returnFuture ? this._asyncStrategy : this._syncStrategy;
|
||||
|
||||
var instance = strategy.readFromCache(key);
|
||||
|
@ -71,7 +75,7 @@ export class Injector {
|
|||
if (isPresent(instance)) return instance;
|
||||
|
||||
if (isPresent(this._parent)) {
|
||||
return this._parent._getByKey(key, returnFuture);
|
||||
return this._parent._getByKey(key, returnFuture, returnLazy);
|
||||
}
|
||||
throw new NoProviderError(key);
|
||||
}
|
||||
|
@ -129,7 +133,7 @@ class _SyncInjectorStrategy {
|
|||
|
||||
_resolveDependencies(key:Key, binding:Binding) {
|
||||
try {
|
||||
var getDependency = d => this.injector._getByKey(d.key, d.asFuture);
|
||||
var getDependency = d => this.injector._getByKey(d.key, d.asFuture, d.lazy);
|
||||
return ListWrapper.map(binding.dependencies, getDependency);
|
||||
} catch (e) {
|
||||
if (e instanceof ProviderError) e.addKey(key);
|
||||
|
@ -184,7 +188,7 @@ class _AsyncInjectorStrategy {
|
|||
}
|
||||
|
||||
_resolveDependencies(key:Key, binding:Binding):List {
|
||||
var getDependency = d => this.injector._getByKey(d.key, true);
|
||||
var getDependency = d => this.injector._getByKey(d.key, true, d.lazy);
|
||||
return ListWrapper.map(binding.dependencies, getDependency);
|
||||
}
|
||||
|
||||
|
|
|
@ -5,9 +5,10 @@ var _id = 0;
|
|||
|
||||
//TODO: vsavkin: move to binding once cyclic deps are supported
|
||||
export class Dependency {
|
||||
constructor(key:Key, asFuture){
|
||||
constructor(key:Key, asFuture, lazy){
|
||||
this.key = key;
|
||||
this.asFuture = asFuture;
|
||||
this.lazy = lazy;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
library facade.di.reflector;
|
||||
|
||||
import 'dart:mirrors';
|
||||
import 'annotations.dart' show Inject, InjectFuture;
|
||||
import 'annotations.dart' show Inject, InjectFuture, InjectLazy;
|
||||
import 'key.dart' show Key, Dependency;
|
||||
import 'exceptions.dart' show NoAnnotationError;
|
||||
|
||||
|
@ -31,15 +31,18 @@ class Reflector {
|
|||
|
||||
final metadata = p.metadata.map((m) => m.reflectee);
|
||||
|
||||
var inject = metadata.where((m) => m is Inject);
|
||||
var injectFuture = metadata.where((m) => m is InjectFuture);
|
||||
var inject = metadata.firstWhere((m) => m is Inject, orElse: () => null);
|
||||
var injectFuture = metadata.firstWhere((m) => m is InjectFuture, orElse: () => null);
|
||||
var injectLazy = metadata.firstWhere((m) => m is InjectLazy, orElse: () => null);
|
||||
|
||||
if (inject.isNotEmpty) {
|
||||
return new Dependency(Key.get(inject.first.token), false);
|
||||
} else if (injectFuture.isNotEmpty) {
|
||||
return new Dependency(Key.get(injectFuture.first.token), true);
|
||||
if (inject != null) {
|
||||
return new Dependency(Key.get(inject.token), false, false);
|
||||
} else if (injectFuture != null) {
|
||||
return new Dependency(Key.get(injectFuture.token), true, false);
|
||||
} else if (injectLazy != null) {
|
||||
return new Dependency(Key.get(injectLazy.token), false, true);
|
||||
} else if (p.type.qualifiedName != #dynamic) {
|
||||
return new Dependency(Key.get(p.type.reflectedType), false);
|
||||
return new Dependency(Key.get(p.type.reflectedType), false, false);
|
||||
} else {
|
||||
throw new NoAnnotationError(type);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {Type, isPresent} from 'facade/lang';
|
||||
import {Inject, InjectFuture} from './annotations';
|
||||
import {Inject, InjectFuture, InjectLazy} from './annotations';
|
||||
import {Dependency, Key} from './key';
|
||||
import {NoAnnotationError} from './exceptions';
|
||||
|
||||
|
@ -27,10 +27,13 @@ export class Reflector {
|
|||
type = paramAnnotation;
|
||||
|
||||
} else if (paramAnnotation instanceof Inject) {
|
||||
return this._createDependency(paramAnnotation.token, false);
|
||||
return this._createDependency(paramAnnotation.token, false, false);
|
||||
|
||||
} else if (paramAnnotation instanceof InjectFuture) {
|
||||
return this._createDependency(paramAnnotation.token, true);
|
||||
return this._createDependency(paramAnnotation.token, true, false);
|
||||
|
||||
} else if (paramAnnotation instanceof InjectLazy) {
|
||||
return this._createDependency(paramAnnotation.token, false, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +44,7 @@ export class Reflector {
|
|||
}
|
||||
}
|
||||
|
||||
_createDependency(token, asFuture):Dependency {
|
||||
return new Dependency(Key.get(token), asFuture);
|
||||
_createDependency(token, asFuture, lazy):Dependency {
|
||||
return new Dependency(Key.get(token), asFuture, lazy);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
import {describe, it, iit, expect, beforeEach} from 'test_lib/test_lib';
|
||||
import {Injector, Inject, bind} from 'di/di';
|
||||
import {describe, ddescribe, it, iit, expect, beforeEach} from 'test_lib/test_lib';
|
||||
import {Injector, Inject, InjectLazy, bind} from 'di/di';
|
||||
|
||||
class Engine {}
|
||||
class BrokenEngine {
|
||||
|
@ -19,6 +19,12 @@ class Car {
|
|||
}
|
||||
}
|
||||
|
||||
class CarWithLazyEngine {
|
||||
constructor(@InjectLazy(Engine) engineFactory) {
|
||||
this.engineFactory = engineFactory;
|
||||
}
|
||||
}
|
||||
|
||||
class CarWithDashboard {
|
||||
constructor(engine:Engine, dashboard:Dashboard) {
|
||||
this.engine = engine;
|
||||
|
@ -118,31 +124,6 @@ export function main() {
|
|||
expect(() => new Injector([bind("blah")])).toThrowError('Invalid binding blah');
|
||||
});
|
||||
|
||||
describe("child", function () {
|
||||
it('should load instances from parent injector', function() {
|
||||
var parent = new Injector([Engine]);
|
||||
var child = parent.createChild([]);
|
||||
|
||||
var engineFromParent = parent.get(Engine);
|
||||
var engineFromChild = child.get(Engine);
|
||||
|
||||
expect(engineFromChild).toBe(engineFromParent);
|
||||
});
|
||||
|
||||
it('should create new instance in a child injector', function() {
|
||||
var parent = new Injector([Engine]);
|
||||
var child = parent.createChild([
|
||||
bind(Engine).toClass(TurboEngine)
|
||||
]);
|
||||
|
||||
var engineFromParent = parent.get(Engine);
|
||||
var engineFromChild = child.get(Engine);
|
||||
|
||||
expect(engineFromParent).not.toBe(engineFromChild);
|
||||
expect(engineFromChild).toBeAnInstanceOf(TurboEngine);
|
||||
});
|
||||
});
|
||||
|
||||
it('should provide itself', function() {
|
||||
var parent = new Injector([]);
|
||||
var child = parent.createChild([]);
|
||||
|
@ -184,5 +165,56 @@ export function main() {
|
|||
expect(e.message).toContain("Error during instantiation of Engine! (Car -> Engine)");
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
describe("child", function () {
|
||||
it('should load instances from parent injector', function() {
|
||||
var parent = new Injector([Engine]);
|
||||
var child = parent.createChild([]);
|
||||
|
||||
var engineFromParent = parent.get(Engine);
|
||||
var engineFromChild = child.get(Engine);
|
||||
|
||||
expect(engineFromChild).toBe(engineFromParent);
|
||||
});
|
||||
|
||||
it('should create new instance in a child injector', function() {
|
||||
var parent = new Injector([Engine]);
|
||||
var child = parent.createChild([
|
||||
bind(Engine).toClass(TurboEngine)
|
||||
]);
|
||||
|
||||
var engineFromParent = parent.get(Engine);
|
||||
var engineFromChild = child.get(Engine);
|
||||
|
||||
expect(engineFromParent).not.toBe(engineFromChild);
|
||||
expect(engineFromChild).toBeAnInstanceOf(TurboEngine);
|
||||
});
|
||||
});
|
||||
|
||||
describe("lazy", function () {
|
||||
it("should create dependencies lazily", function () {
|
||||
var injector = new Injector([
|
||||
Engine,
|
||||
CarWithLazyEngine
|
||||
]);
|
||||
|
||||
var car = injector.get(CarWithLazyEngine);
|
||||
expect(car.engineFactory()).toBeAnInstanceOf(Engine);
|
||||
});
|
||||
|
||||
it("should cache instance created lazily", function () {
|
||||
var injector = new Injector([
|
||||
Engine,
|
||||
CarWithLazyEngine
|
||||
]);
|
||||
|
||||
var car = injector.get(CarWithLazyEngine);
|
||||
var e1 = car.engineFactory();
|
||||
var e2 = car.engineFactory();
|
||||
|
||||
expect(e1).toBe(e2);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue