Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit f13dd33

Browse files
committed
feat(injector): infer _foo_ as foo
this is to enable nicer tests: describe('fooSvc', function() { var fooSvc; beforeEach(inject(function(_fooSvc_) { fooSvc = _fooSvc_; })); it('should do this thing', function() { //test fooSvc }); });
1 parent bca96e7 commit f13dd33

File tree

3 files changed

+105
-2
lines changed

3 files changed

+105
-2
lines changed

docs/content/guide/dev_guide.di.understanding_di.ngdoc

+97
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,103 @@ minifiers/obfuscators. In the future, we may provide a pre-processor which will
8787
code and insert the `$inject` into the source code so that it can be minified/obfuscated.
8888

8989

90+
### Dependency inference and variable name shadowing
91+
92+
During inference, the injector considers argument names with leading and trailing underscores to be
93+
equivivalent to the name without these underscores. For example `_fooSvc_` argument name is treated
94+
as if it was `fooSvc`, this is useful especially in tests where variable name shadowing can cause
95+
some friction. This is best illustrated on examples:
96+
97+
When testing a service, it's common to need a reference to it in every single test. This can be
98+
done in jasmine with DI inference like this:
99+
100+
<pre>
101+
describe('fooSvc', function() {
102+
it('should do this thing', inject(function(fooSvc) {
103+
//test fooSvc
104+
}));
105+
106+
it('should do that thing', inject(function(fooSvc) {
107+
//test fooSvc
108+
}));
109+
110+
// more its
111+
});
112+
</pre>
113+
114+
... but having to inject the service over and over gets easily tiresome.
115+
116+
It's likely better to rewrite these tests with a use of jasmine's `beforeEach`:
117+
118+
<pre>
119+
describe('fooSvc', function() {
120+
var fooSvc;
121+
122+
beforeEach(inject(function(fooSvc) {
123+
fooSvc = fooSvc; // DOESN'T WORK! outer fooSvc is being shadowed
124+
}));
125+
126+
it('should do this thing', function() {
127+
//test fooSvc
128+
});
129+
130+
it('should do that thing', function() {
131+
//test fooSvc
132+
});
133+
134+
// more its
135+
});
136+
</pre>
137+
138+
This obviously won't work because `fooSvc` variable in the describe block is being shadowed by the
139+
`fooSvc` argument of the beforeEach function. So we have to resort to alternative solutions, like
140+
for example use of array notation to annotate the beforeEach fn:
141+
142+
<pre>
143+
describe('fooSvc', function() {
144+
var fooSvc;
145+
146+
beforeEach(inject(['fooSvc', function(fooSvc_) {
147+
fooSvc = fooSvc_;
148+
}]));
149+
150+
it('should do this thing', function() {
151+
//test fooSvc
152+
});
153+
154+
it('should do that thing', function() {
155+
//test fooSvc
156+
});
157+
});
158+
</pre>
159+
160+
161+
That's better, but it's still annoying, especially if you have many services to inject.
162+
163+
To resolve this shadowing problem, the injector considers `_fooSvc_` argument names equal to
164+
`fooSvc`, so the test can be rewritten like this:
165+
166+
<pre>
167+
describe('fooSvc', function() {
168+
var fooSvc;
169+
170+
beforeEach(inject(function(_fooSvc_) {
171+
fooSvc = _fooSvc_;
172+
}));
173+
174+
it('should do this thing', function() {
175+
//test fooSvc
176+
});
177+
178+
it('should do that thing', function() {
179+
//test fooSvc
180+
});
181+
182+
// more its
183+
});
184+
</pre>
185+
186+
90187
## Related Topics
91188

92189
* {@link dev_guide.services Angular Services}

src/Injector.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040

4141
var FN_ARGS = /^function\s*[^\(]*\(([^\)]*)\)/m;
4242
var FN_ARG_SPLIT = /,/;
43-
var FN_ARG = /^\s*(.+?)\s*$/;
43+
var FN_ARG = /^\s*(_?)(.+?)\1\s*$/;
4444
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
4545
function inferInjectionArgs(fn) {
4646
assertArgFn(fn);
@@ -49,7 +49,7 @@ function inferInjectionArgs(fn) {
4949
var fnText = fn.toString().replace(STRIP_COMMENTS, '');
5050
var argDecl = fnText.match(FN_ARGS);
5151
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
52-
arg.replace(FN_ARG, function(all, name){
52+
arg.replace(FN_ARG, function(all, underscore, name){
5353
args.push(name);
5454
});
5555
});

test/InjectorSpec.js

+6
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ describe('injector', function() {
147147
});
148148

149149

150+
it('should strip leading and trailing underscores from arg name during inference', function() {
151+
function beforeEachFn(_foo_) { /* foo = _foo_ */ };
152+
expect(inferInjectionArgs(beforeEachFn)).toEqual(['foo']);
153+
});
154+
155+
150156
it('should handle no arg functions', function() {
151157
function $f_n0() {}
152158
expect(inferInjectionArgs($f_n0)).toEqual([]);

0 commit comments

Comments
 (0)