Skip to content

Commit d313cac

Browse files
committed
refactor(injector): change toFactory to use reflector to construct dependencies
1 parent 06a2216 commit d313cac

File tree

6 files changed

+61
-32
lines changed

6 files changed

+61
-32
lines changed

modules/di/src/binding.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {FIELD, Type, bool} from 'facade/lang';
1+
import {FIELD, Type, bool, isBlank} from 'facade/lang';
22
import {List, MapWrapper, ListWrapper} from 'facade/collection';
33
import {reflector} from './reflector';
44
import {Key} from './key';
@@ -13,6 +13,7 @@ export class Dependency {
1313
this.lazy = lazy;
1414
}
1515
}
16+
1617
export class Binding {
1718
constructor(key:Key, factory:Function, dependencies:List, providedAsFuture:bool) {
1819
this.key = key;
@@ -49,25 +50,27 @@ export class BindingBuilder {
4950
);
5051
}
5152

52-
toFactory(dependencies:List, factoryFunction:Function):Binding {
53+
toFactory(factoryFunction:Function, {dependencies=null}={}):Binding {
5354
return new Binding(
5455
Key.get(this.token),
5556
reflector.convertToFactory(factoryFunction),
56-
this._constructDependencies(dependencies),
57+
this._constructDependencies(factoryFunction, dependencies),
5758
false
5859
);
5960
}
6061

61-
toAsyncFactory(dependencies:List, factoryFunction:Function):Binding {
62+
toAsyncFactory(factoryFunction:Function, {dependencies=null}={}):Binding {
6263
return new Binding(
6364
Key.get(this.token),
6465
reflector.convertToFactory(factoryFunction),
65-
this._constructDependencies(dependencies),
66+
this._constructDependencies(factoryFunction, dependencies),
6667
true
6768
);
6869
}
6970

70-
_constructDependencies(deps:List) {
71-
return ListWrapper.map(deps, (t) => new Dependency(Key.get(t), false, false));
71+
_constructDependencies(factoryFunction:Function, dependencies:List) {
72+
return isBlank(dependencies) ?
73+
reflector.dependencies(factoryFunction) :
74+
ListWrapper.map(dependencies, (t) => new Dependency(Key.get(t), false, false));
7275
}
7376
}

modules/di/src/exceptions.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ export class InvalidBindingError extends Error {
7777
}
7878

7979
export class NoAnnotationError extends Error {
80-
constructor(type) {
81-
this.message = `Cannot resolve all parameters for ${stringify(type)}`;
80+
constructor(typeOrFunc) {
81+
this.message = `Cannot resolve all parameters for ${stringify(typeOrFunc)}`;
8282
}
8383

8484
toString() {

modules/di/src/reflector.dart

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,13 @@ class Reflector {
2323
return (args) => create(name, args).reflectee;
2424
}
2525

26-
List<Dependency> dependencies(Type type) {
27-
ClassMirror classMirror = reflectType(type);
28-
MethodMirror ctor = classMirror.declarations[classMirror.simpleName];
26+
List<Dependency> dependencies(typeOrFunc) {
27+
final parameters = typeOrFunc is Type ?
28+
_constructorParameters(typeOrFunc) :
29+
_functionParameters(typeOrFunc);
2930

30-
return new List.generate(ctor.parameters.length, (int pos) {
31-
ParameterMirror p = ctor.parameters[pos];
31+
return new List.generate(parameters.length, (int pos) {
32+
ParameterMirror p = parameters[pos];
3233

3334
final metadata = p.metadata.map((m) => m.reflectee);
3435

@@ -49,10 +50,20 @@ class Reflector {
4950
return new Dependency(Key.get(p.type.reflectedType), false, false);
5051

5152
} else {
52-
throw new NoAnnotationError(type);
53+
throw new NoAnnotationError(typeOrFunc);
5354
}
5455
}, growable:false);
5556
}
57+
58+
List<ParameterMirror> _functionParameters(Function func) {
59+
return reflect(func).function.parameters;
60+
}
61+
62+
List<ParameterMirror> _constructorParameters(Type type) {
63+
ClassMirror classMirror = reflectType(type);
64+
MethodMirror ctor = classMirror.declarations[classMirror.simpleName];
65+
return ctor.parameters;
66+
}
5667
}
5768

5869
final Reflector reflector = new Reflector();

modules/di/src/reflector.es6

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,14 @@ class Reflector {
1414
return (args) => factoryFunction(...args);
1515
}
1616

17-
dependencies(type:Type):List {
18-
var p = type.parameters;
19-
if (p == undefined && type.length == 0) return [];
20-
if (p == undefined) throw new NoAnnotationError(type);
21-
return type.parameters.map((p) => this._extractToken(type, p));
17+
dependencies(typeOrFunc):List {
18+
var p = typeOrFunc.parameters;
19+
if (p == undefined && typeOrFunc.length == 0) return [];
20+
if (p == undefined) throw new NoAnnotationError(typeOrFunc);
21+
return typeOrFunc.parameters.map((p) => this._extractToken(typeOrFunc, p));
2222
}
2323

24-
_extractToken(constructedType:Type, annotations) {
24+
_extractToken(typeOrFunc, annotations) {
2525
var type;
2626

2727
for (var paramAnnotation of annotations) {
@@ -42,7 +42,7 @@ class Reflector {
4242
if (isPresent(type)) {
4343
return this._createDependency(type, false, false);
4444
} else {
45-
throw new NoAnnotationError(constructedType);
45+
throw new NoAnnotationError(typeOrFunc);
4646
}
4747
}
4848

modules/di/test/di/async_spec.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export function main() {
3030
describe("asyncGet", function () {
3131
it('should return a future', function () {
3232
var injector = new Injector([
33-
bind(UserList).toAsyncFactory([], fetchUsers)
33+
bind(UserList).toAsyncFactory(fetchUsers)
3434
]);
3535
var p = injector.asyncGet(UserList);
3636
expect(p).toBeFuture();
@@ -64,7 +64,7 @@ export function main() {
6464
it('should return a future when instantiating a sync binding ' +
6565
'with an async dependency', function (done) {
6666
var injector = new Injector([
67-
bind(UserList).toAsyncFactory([], fetchUsers),
67+
bind(UserList).toAsyncFactory(fetchUsers),
6868
UserController
6969
]);
7070

@@ -77,7 +77,7 @@ export function main() {
7777

7878
it("should create only one instance (async + async)", function (done) {
7979
var injector = new Injector([
80-
bind(UserList).toAsyncFactory([], fetchUsers)
80+
bind(UserList).toAsyncFactory(fetchUsers)
8181
]);
8282

8383
var ul1 = injector.asyncGet(UserList);
@@ -109,7 +109,7 @@ export function main() {
109109
it('should show the full path when error happens in a constructor', function (done) {
110110
var injector = new Injector([
111111
UserController,
112-
bind(UserList).toAsyncFactory([], function () {
112+
bind(UserList).toAsyncFactory(function () {
113113
throw "Broken UserList";
114114
})
115115
]);
@@ -125,7 +125,7 @@ export function main() {
125125
describe("get", function () {
126126
it('should throw when instantiating an async binding', function () {
127127
var injector = new Injector([
128-
bind(UserList).toAsyncFactory([], fetchUsers)
128+
bind(UserList).toAsyncFactory(fetchUsers)
129129
]);
130130

131131
expect(() => injector.get(UserList))
@@ -134,7 +134,7 @@ export function main() {
134134

135135
it('should throw when instantiating a sync binding with an dependency', function () {
136136
var injector = new Injector([
137-
bind(UserList).toAsyncFactory([], fetchUsers),
137+
bind(UserList).toAsyncFactory(fetchUsers),
138138
UserController
139139
]);
140140

@@ -144,7 +144,7 @@ export function main() {
144144

145145
it('should resolve synchronously when an async dependency requested as a future', function () {
146146
var injector = new Injector([
147-
bind(UserList).toAsyncFactory([], fetchUsers),
147+
bind(UserList).toAsyncFactory(fetchUsers),
148148
AsyncUserController
149149
]);
150150
var controller = injector.get(AsyncUserController);
@@ -155,7 +155,7 @@ export function main() {
155155

156156
it('should wrap sync dependencies into futures if required', function () {
157157
var injector = new Injector([
158-
bind(UserList).toFactory([], () => new UserList()),
158+
bind(UserList).toFactory(() => new UserList()),
159159
AsyncUserController
160160
]);
161161
var controller = injector.get(AsyncUserController);

modules/di/test/di/injector_spec.js

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,24 @@ export function main() {
108108
});
109109

110110
it('should bind to a factory', function () {
111+
function sportsCarFactory(e:Engine) {
112+
return new SportsCar(e);
113+
}
114+
115+
var injector = new Injector([
116+
Engine,
117+
bind(Car).toFactory(sportsCarFactory)
118+
]);
119+
120+
var car = injector.get(Car);
121+
expect(car).toBeAnInstanceOf(SportsCar);
122+
expect(car.engine).toBeAnInstanceOf(Engine);
123+
});
124+
125+
it('should support overriding factory dependencies', function () {
111126
var injector = new Injector([
112127
Engine,
113-
bind(Car).toFactory([Engine], (e) => new SportsCar(e))
128+
bind(Car).toFactory((e) => new SportsCar(e), {dependencies: [Engine]})
114129
]);
115130

116131
var car = injector.get(Car);
@@ -181,7 +196,7 @@ export function main() {
181196

182197
var injector = new Injector([
183198
Car,
184-
bind(Engine).toFactory([], () => isBroken ? new BrokenEngine() : new Engine())
199+
bind(Engine).toFactory(() => isBroken ? new BrokenEngine() : new Engine())
185200
]);
186201

187202
expect(() => injector.get(Car)).toThrow();

0 commit comments

Comments
 (0)