refactor(di): added support for custom dep providers
This commit is contained in:
parent
e987ac4034
commit
569766fa8b
|
@ -56,7 +56,8 @@ export {
|
||||||
Self,
|
Self,
|
||||||
Parent,
|
Parent,
|
||||||
Ancestor,
|
Ancestor,
|
||||||
Unbounded
|
Unbounded,
|
||||||
|
DependencyProvider
|
||||||
} from './di';
|
} from './di';
|
||||||
|
|
||||||
export * from './core';
|
export * from './core';
|
||||||
|
|
|
@ -33,6 +33,7 @@ export {
|
||||||
resolveBindings,
|
resolveBindings,
|
||||||
Injector,
|
Injector,
|
||||||
ProtoInjector,
|
ProtoInjector,
|
||||||
|
DependencyProvider,
|
||||||
PUBLIC_AND_PRIVATE,
|
PUBLIC_AND_PRIVATE,
|
||||||
PUBLIC,
|
PUBLIC,
|
||||||
PRIVATE,
|
PRIVATE,
|
||||||
|
|
|
@ -28,6 +28,7 @@ import {
|
||||||
resolveBindings,
|
resolveBindings,
|
||||||
Visibility,
|
Visibility,
|
||||||
VisibilityAnnotation,
|
VisibilityAnnotation,
|
||||||
|
DependencyProvider,
|
||||||
self
|
self
|
||||||
} from 'angular2/di';
|
} from 'angular2/di';
|
||||||
import {
|
import {
|
||||||
|
@ -429,7 +430,7 @@ export class ProtoElementInjector {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class ElementInjector extends TreeNode<ElementInjector> {
|
export class ElementInjector extends TreeNode<ElementInjector> implements DependencyProvider {
|
||||||
private _host: ElementInjector;
|
private _host: ElementInjector;
|
||||||
private _preBuiltObjects = null;
|
private _preBuiltObjects = null;
|
||||||
|
|
||||||
|
@ -447,9 +448,7 @@ export class ElementInjector extends TreeNode<ElementInjector> {
|
||||||
constructor(public _proto: ProtoElementInjector, parent: ElementInjector) {
|
constructor(public _proto: ProtoElementInjector, parent: ElementInjector) {
|
||||||
super(parent);
|
super(parent);
|
||||||
|
|
||||||
this._injector = new Injector(this._proto.protoInjector);
|
this._injector = new Injector(this._proto.protoInjector, null, this);
|
||||||
this._injector.ei = this; // TODO savkin remove after mergin DI and EI
|
|
||||||
|
|
||||||
// we couple ourselves to the injector strategy to avoid polymoprhic calls
|
// we couple ourselves to the injector strategy to avoid polymoprhic calls
|
||||||
var injectorStrategy = <any>this._injector.internalStrategy;
|
var injectorStrategy = <any>this._injector.internalStrategy;
|
||||||
this._strategy = injectorStrategy instanceof InjectorInlineStrategy ?
|
this._strategy = injectorStrategy instanceof InjectorInlineStrategy ?
|
||||||
|
@ -588,7 +587,7 @@ export class ElementInjector extends TreeNode<ElementInjector> {
|
||||||
|
|
||||||
isComponentKey(key: Key): boolean { return this._strategy.isComponentKey(key); }
|
isComponentKey(key: Key): boolean { return this._strategy.isComponentKey(key); }
|
||||||
|
|
||||||
getDependency(dep: any): any {
|
getDependency(injector: Injector, binding: ResolvedBinding, dep: Dependency): any {
|
||||||
var key: Key = dep.key;
|
var key: Key = dep.key;
|
||||||
|
|
||||||
if (!(dep instanceof DirectiveDependency)) return undefinedValue;
|
if (!(dep instanceof DirectiveDependency)) return undefinedValue;
|
||||||
|
|
|
@ -402,6 +402,13 @@ export class BindingWithVisibility {
|
||||||
getKeyId(): number { return this.binding.key.id; }
|
getKeyId(): number { return this.binding.key.id; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to provide dependencies that cannot be easily expressed as bindings.
|
||||||
|
*/
|
||||||
|
export interface DependencyProvider {
|
||||||
|
getDependency(injector: Injector, binding: ResolvedBinding, dependency: Dependency): any;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dependency injection container used for resolving dependencies.
|
* A dependency injection container used for resolving dependencies.
|
||||||
*
|
*
|
||||||
|
@ -476,10 +483,12 @@ export class Injector {
|
||||||
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a
|
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a
|
||||||
*recursive list of more
|
*recursive list of more
|
||||||
* bindings.
|
* bindings.
|
||||||
|
* @param `depProvider`
|
||||||
*/
|
*/
|
||||||
static resolveAndCreate(bindings: List<Type | Binding | List<any>>): Injector {
|
static resolveAndCreate(bindings: List<Type | Binding | List<any>>,
|
||||||
|
depProvider: DependencyProvider = null): Injector {
|
||||||
var resolvedBindings = Injector.resolve(bindings);
|
var resolvedBindings = Injector.resolve(bindings);
|
||||||
return Injector.fromResolvedBindings(resolvedBindings);
|
return Injector.fromResolvedBindings(resolvedBindings, depProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -488,11 +497,13 @@ export class Injector {
|
||||||
*
|
*
|
||||||
* @param `bindings` A sparse list of {@link ResolvedBinding}s. See `resolve` for the
|
* @param `bindings` A sparse list of {@link ResolvedBinding}s. See `resolve` for the
|
||||||
* {@link Injector}.
|
* {@link Injector}.
|
||||||
|
* @param `depProvider`
|
||||||
*/
|
*/
|
||||||
static fromResolvedBindings(bindings: List<ResolvedBinding>): Injector {
|
static fromResolvedBindings(bindings: List<ResolvedBinding>,
|
||||||
|
depProvider: DependencyProvider = null): Injector {
|
||||||
var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC));
|
var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC));
|
||||||
var proto = new ProtoInjector(bd, 0);
|
var proto = new ProtoInjector(bd, 0);
|
||||||
var inj = new Injector(proto);
|
var inj = new Injector(proto, null, depProvider);
|
||||||
return inj;
|
return inj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,10 +511,8 @@ export class Injector {
|
||||||
_isBoundary: boolean = false;
|
_isBoundary: boolean = false;
|
||||||
_constructionCounter: number = 0;
|
_constructionCounter: number = 0;
|
||||||
|
|
||||||
// TODO vsavkin remove it after DI and EI are merged
|
constructor(public _proto: ProtoInjector, public _parent: Injector = null,
|
||||||
ei: any;
|
private _depProvider: DependencyProvider = null) {
|
||||||
|
|
||||||
constructor(public _proto: ProtoInjector, public _parent: Injector = null) {
|
|
||||||
this._strategy = _proto._strategy.createInjectorStrategy(this);
|
this._strategy = _proto._strategy.createInjectorStrategy(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -555,11 +564,12 @@ export class Injector {
|
||||||
*
|
*
|
||||||
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a
|
* @param `bindings` can be a list of `Type`, {@link Binding}, {@link ResolvedBinding}, or a
|
||||||
* recursive list of more bindings.
|
* recursive list of more bindings.
|
||||||
*
|
* @param `depProvider`
|
||||||
*/
|
*/
|
||||||
resolveAndCreateChild(bindings: List<Type | Binding | List<any>>): Injector {
|
resolveAndCreateChild(bindings: List<Type | Binding | List<any>>,
|
||||||
|
depProvider: DependencyProvider = null): Injector {
|
||||||
var resovledBindings = Injector.resolve(bindings);
|
var resovledBindings = Injector.resolve(bindings);
|
||||||
return this.createChildFromResolved(resovledBindings);
|
return this.createChildFromResolved(resovledBindings, depProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -567,12 +577,14 @@ export class Injector {
|
||||||
*
|
*
|
||||||
* @param `bindings`: A sparse list of {@link ResolvedBinding}s.
|
* @param `bindings`: A sparse list of {@link ResolvedBinding}s.
|
||||||
* See `resolve` for the {@link Injector}.
|
* See `resolve` for the {@link Injector}.
|
||||||
|
* @param `depProvider`
|
||||||
* @returns a new child {@link Injector}.
|
* @returns a new child {@link Injector}.
|
||||||
*/
|
*/
|
||||||
createChildFromResolved(bindings: List<ResolvedBinding>): Injector {
|
createChildFromResolved(bindings: List<ResolvedBinding>,
|
||||||
|
depProvider: DependencyProvider = null): Injector {
|
||||||
var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC));
|
var bd = bindings.map(b => new BindingWithVisibility(b, PUBLIC));
|
||||||
var proto = new ProtoInjector(bd, 1);
|
var proto = new ProtoInjector(bd, 1);
|
||||||
var inj = new Injector(proto);
|
var inj = new Injector(proto, null, depProvider);
|
||||||
inj._parent = this;
|
inj._parent = this;
|
||||||
return inj;
|
return inj;
|
||||||
}
|
}
|
||||||
|
@ -588,26 +600,26 @@ export class Injector {
|
||||||
|
|
||||||
var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16, d17, d18, d19;
|
var d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11, d12, d13, d14, d15, d16, d17, d18, d19;
|
||||||
try {
|
try {
|
||||||
d0 = length > 0 ? this._getByDependency(deps[0], visibility) : null;
|
d0 = length > 0 ? this._getByDependency(binding, deps[0], visibility) : null;
|
||||||
d1 = length > 1 ? this._getByDependency(deps[1], visibility) : null;
|
d1 = length > 1 ? this._getByDependency(binding, deps[1], visibility) : null;
|
||||||
d2 = length > 2 ? this._getByDependency(deps[2], visibility) : null;
|
d2 = length > 2 ? this._getByDependency(binding, deps[2], visibility) : null;
|
||||||
d3 = length > 3 ? this._getByDependency(deps[3], visibility) : null;
|
d3 = length > 3 ? this._getByDependency(binding, deps[3], visibility) : null;
|
||||||
d4 = length > 4 ? this._getByDependency(deps[4], visibility) : null;
|
d4 = length > 4 ? this._getByDependency(binding, deps[4], visibility) : null;
|
||||||
d5 = length > 5 ? this._getByDependency(deps[5], visibility) : null;
|
d5 = length > 5 ? this._getByDependency(binding, deps[5], visibility) : null;
|
||||||
d6 = length > 6 ? this._getByDependency(deps[6], visibility) : null;
|
d6 = length > 6 ? this._getByDependency(binding, deps[6], visibility) : null;
|
||||||
d7 = length > 7 ? this._getByDependency(deps[7], visibility) : null;
|
d7 = length > 7 ? this._getByDependency(binding, deps[7], visibility) : null;
|
||||||
d8 = length > 8 ? this._getByDependency(deps[8], visibility) : null;
|
d8 = length > 8 ? this._getByDependency(binding, deps[8], visibility) : null;
|
||||||
d9 = length > 9 ? this._getByDependency(deps[9], visibility) : null;
|
d9 = length > 9 ? this._getByDependency(binding, deps[9], visibility) : null;
|
||||||
d10 = length > 10 ? this._getByDependency(deps[10], visibility) : null;
|
d10 = length > 10 ? this._getByDependency(binding, deps[10], visibility) : null;
|
||||||
d11 = length > 11 ? this._getByDependency(deps[11], visibility) : null;
|
d11 = length > 11 ? this._getByDependency(binding, deps[11], visibility) : null;
|
||||||
d12 = length > 12 ? this._getByDependency(deps[12], visibility) : null;
|
d12 = length > 12 ? this._getByDependency(binding, deps[12], visibility) : null;
|
||||||
d13 = length > 13 ? this._getByDependency(deps[13], visibility) : null;
|
d13 = length > 13 ? this._getByDependency(binding, deps[13], visibility) : null;
|
||||||
d14 = length > 14 ? this._getByDependency(deps[14], visibility) : null;
|
d14 = length > 14 ? this._getByDependency(binding, deps[14], visibility) : null;
|
||||||
d15 = length > 15 ? this._getByDependency(deps[15], visibility) : null;
|
d15 = length > 15 ? this._getByDependency(binding, deps[15], visibility) : null;
|
||||||
d16 = length > 16 ? this._getByDependency(deps[16], visibility) : null;
|
d16 = length > 16 ? this._getByDependency(binding, deps[16], visibility) : null;
|
||||||
d17 = length > 17 ? this._getByDependency(deps[17], visibility) : null;
|
d17 = length > 17 ? this._getByDependency(binding, deps[17], visibility) : null;
|
||||||
d18 = length > 18 ? this._getByDependency(deps[18], visibility) : null;
|
d18 = length > 18 ? this._getByDependency(binding, deps[18], visibility) : null;
|
||||||
d19 = length > 19 ? this._getByDependency(deps[19], visibility) : null;
|
d19 = length > 19 ? this._getByDependency(binding, deps[19], visibility) : null;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof AbstractBindingError) e.addKey(binding.key);
|
if (e instanceof AbstractBindingError) e.addKey(binding.key);
|
||||||
throw e;
|
throw e;
|
||||||
|
@ -689,8 +701,11 @@ export class Injector {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _getByDependency(dep: Dependency, bindingVisibility: number): any {
|
private _getByDependency(binding: ResolvedBinding, dep: Dependency,
|
||||||
var special = isPresent(this.ei) ? this.ei.getDependency(dep) : undefinedValue;
|
bindingVisibility: number): any {
|
||||||
|
var special = isPresent(this._depProvider) ?
|
||||||
|
this._depProvider.getDependency(this, binding, dep) :
|
||||||
|
undefinedValue;
|
||||||
if (special !== undefinedValue) {
|
if (special !== undefinedValue) {
|
||||||
return special;
|
return special;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
library test_lib.spies;
|
library test_lib.spies;
|
||||||
|
|
||||||
import 'package:angular2/change_detection.dart';
|
import 'package:angular2/change_detection.dart';
|
||||||
|
import 'package:angular2/di.dart';
|
||||||
import './test_lib.dart';
|
import './test_lib.dart';
|
||||||
|
|
||||||
@proxy
|
@proxy
|
||||||
|
@ -22,3 +23,8 @@ class SpyPipe extends SpyObject implements Pipe {
|
||||||
class SpyPipeFactory extends SpyObject implements PipeFactory {
|
class SpyPipeFactory extends SpyObject implements PipeFactory {
|
||||||
noSuchMethod(m) => super.noSuchMethod(m);
|
noSuchMethod(m) => super.noSuchMethod(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@proxy
|
||||||
|
class SpyDependencyProvider extends SpyObject implements DependencyProvider {
|
||||||
|
noSuchMethod(m) => super.noSuchMethod(m);
|
||||||
|
}
|
|
@ -3,6 +3,9 @@ import {
|
||||||
ProtoChangeDetector,
|
ProtoChangeDetector,
|
||||||
DynamicChangeDetector
|
DynamicChangeDetector
|
||||||
} from 'angular2/change_detection';
|
} from 'angular2/change_detection';
|
||||||
|
|
||||||
|
import {DependencyProvider} from 'angular2/di';
|
||||||
|
|
||||||
import {BasePipe} from 'angular2/src/change_detection/pipes/pipe';
|
import {BasePipe} from 'angular2/src/change_detection/pipes/pipe';
|
||||||
import {SpyObject, proxy} from './test_lib';
|
import {SpyObject, proxy} from './test_lib';
|
||||||
|
|
||||||
|
@ -19,3 +22,5 @@ export class SpyPipe extends SpyObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SpyPipeFactory extends SpyObject {}
|
export class SpyPipeFactory extends SpyObject {}
|
||||||
|
|
||||||
|
export class SpyDependencyProvider extends SpyObject {}
|
|
@ -1,5 +1,13 @@
|
||||||
import {isBlank, BaseException, stringify} from 'angular2/src/facade/lang';
|
import {isBlank, BaseException, stringify} from 'angular2/src/facade/lang';
|
||||||
import {describe, ddescribe, it, iit, expect, beforeEach} from 'angular2/test_lib';
|
import {
|
||||||
|
describe,
|
||||||
|
ddescribe,
|
||||||
|
it,
|
||||||
|
iit,
|
||||||
|
expect,
|
||||||
|
beforeEach,
|
||||||
|
SpyDependencyProvider
|
||||||
|
} from 'angular2/test_lib';
|
||||||
import {
|
import {
|
||||||
Injector,
|
Injector,
|
||||||
bind,
|
bind,
|
||||||
|
@ -107,8 +115,8 @@ export function main() {
|
||||||
strategyClass: InjectorDynamicStrategy
|
strategyClass: InjectorDynamicStrategy
|
||||||
}].forEach((context) => {
|
}].forEach((context) => {
|
||||||
|
|
||||||
function createInjector(bindings: any[]) {
|
function createInjector(bindings: any[], dependencyProvider = null) {
|
||||||
return Injector.resolveAndCreate(bindings.concat(context['bindings']));
|
return Injector.resolveAndCreate(bindings.concat(context['bindings']), dependencyProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
describe(`injector ${context['strategy']}`, () => {
|
describe(`injector ${context['strategy']}`, () => {
|
||||||
|
@ -315,6 +323,20 @@ export function main() {
|
||||||
var injector = createInjector([bind('null').toValue(null)]);
|
var injector = createInjector([bind('null').toValue(null)]);
|
||||||
expect(injector.get('null')).toBe(null);
|
expect(injector.get('null')).toBe(null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should use custom dependency provider', () => {
|
||||||
|
var e = new Engine();
|
||||||
|
|
||||||
|
var depProvider = <any>new SpyDependencyProvider();
|
||||||
|
depProvider.spy("getDependency").andReturn(e);
|
||||||
|
|
||||||
|
var bindings = Injector.resolve([Car]);
|
||||||
|
var injector = Injector.fromResolvedBindings(bindings, depProvider);
|
||||||
|
|
||||||
|
expect(injector.get(Car).engine).toEqual(e);
|
||||||
|
expect(depProvider.spy("getDependency"))
|
||||||
|
.toHaveBeenCalledWith(injector, bindings[0], bindings[0].dependencies[0]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue