refactor(injection) infer injection args in ng:controller only

Because only controllers don't have currying, we can infer its arguments, all other APIs needing currying, automatic inference complicates the matters unecessary.
This commit is contained in:
Misko Hevery 2011-08-02 13:29:12 -07:00 committed by Igor Minar
parent 97e3ec4d1b
commit 25a62b58db
5 changed files with 27 additions and 16 deletions

View file

@ -40,8 +40,6 @@ Template.prototype = {
addLinkFn:function(linkingFn) { addLinkFn:function(linkingFn) {
if (linkingFn) { if (linkingFn) {
if (!linkingFn.$inject)
linkingFn.$inject = [];
this.linkFns.push(linkingFn); this.linkFns.push(linkingFn);
} }
}, },

View file

@ -60,6 +60,7 @@ function createInjector(factoryScope, factories, instanceCache) {
if (!(value in instanceCache)) { if (!(value in instanceCache)) {
var factory = factories[value]; var factory = factories[value];
if (!factory) throw Error("Unknown provider for '"+value+"'."); if (!factory) throw Error("Unknown provider for '"+value+"'.");
inferInjectionArgs(factory);
instanceCache[value] = invoke(factoryScope, factory); instanceCache[value] = invoke(factoryScope, factory);
} }
return instanceCache[value]; return instanceCache[value];
@ -67,7 +68,7 @@ function createInjector(factoryScope, factories, instanceCache) {
function invoke(self, fn, args){ function invoke(self, fn, args){
args = args || []; args = args || [];
var injectNames = injectionArgs(fn); var injectNames = fn.$inject || [];
var i = injectNames.length; var i = injectNames.length;
while(i--) { while(i--) {
args.unshift(injector(injectNames[i])); args.unshift(injector(injectNames[i]));
@ -133,7 +134,7 @@ var FN_ARGS = /^function\s*[^\(]*\(([^\)]*)\)/m;
var FN_ARG_SPLIT = /,/; var FN_ARG_SPLIT = /,/;
var FN_ARG = /^\s*(.+?)\s*$/; var FN_ARG = /^\s*(.+?)\s*$/;
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
function injectionArgs(fn) { function inferInjectionArgs(fn) {
assertArgFn(fn); assertArgFn(fn);
if (!fn.$inject) { if (!fn.$inject) {
var args = fn.$inject = []; var args = fn.$inject = [];

View file

@ -174,6 +174,7 @@ angularDirective("ng:controller", function(expression){
getter(scope, expression, true) || getter(scope, expression, true) ||
getter(window, expression, true); getter(window, expression, true);
assertArgFn(Controller, expression); assertArgFn(Controller, expression);
inferInjectionArgs(Controller);
return Controller; return Controller;
}); });
return noop; return noop;

View file

@ -85,11 +85,11 @@ describe('injector', function(){
it('should return $inject', function(){ it('should return $inject', function(){
function fn(){} function fn(){}
fn.$inject = ['a']; fn.$inject = ['a'];
expect(injectionArgs(fn)).toBe(fn.$inject); expect(inferInjectionArgs(fn)).toBe(fn.$inject);
expect(injectionArgs(function(){})).toEqual([]); expect(inferInjectionArgs(function(){})).toEqual([]);
expect(injectionArgs(function (){})).toEqual([]); expect(inferInjectionArgs(function (){})).toEqual([]);
expect(injectionArgs(function (){})).toEqual([]); expect(inferInjectionArgs(function (){})).toEqual([]);
expect(injectionArgs(function /* */ (){})).toEqual([]); expect(inferInjectionArgs(function /* */ (){})).toEqual([]);
}); });
it('should create $inject', function(){ it('should create $inject', function(){
@ -103,28 +103,35 @@ describe('injector', function(){
*/ */
_c, _c,
/* {some type} */ d){ extraParans();} /* {some type} */ d){ extraParans();}
expect(injectionArgs($f_n0)).toEqual(['$a', 'b_', '_c', 'd']); expect(inferInjectionArgs($f_n0)).toEqual(['$a', 'b_', '_c', 'd']);
expect($f_n0.$inject).toEqual(['$a', 'b_', '_c', 'd']); expect($f_n0.$inject).toEqual(['$a', 'b_', '_c', 'd']);
}); });
it('should handle no arg functions', function(){ it('should handle no arg functions', function(){
function $f_n0(){} function $f_n0(){}
expect(injectionArgs($f_n0)).toEqual([]); expect(inferInjectionArgs($f_n0)).toEqual([]);
expect($f_n0.$inject).toEqual([]); expect($f_n0.$inject).toEqual([]);
}); });
it('should handle args with both $ and _', function(){ it('should handle args with both $ and _', function(){
function $f_n0($a_){} function $f_n0($a_){}
expect(injectionArgs($f_n0)).toEqual(['$a_']); expect(inferInjectionArgs($f_n0)).toEqual(['$a_']);
expect($f_n0.$inject).toEqual(['$a_']); expect($f_n0.$inject).toEqual(['$a_']);
}); });
it('should throw on non function arg', function(){ it('should throw on non function arg', function(){
expect(function(){ expect(function(){
injectionArgs({}); inferInjectionArgs({});
}).toThrow(); }).toThrow();
}); });
it('should infer injection on services', function(){
var scope = angular.scope({
a: function(){ return 'a';},
b: function(a){ return a + 'b';}
});
expect(scope.$service('b')).toEqual('ab');
});
}); });
describe('inject', function(){ describe('inject', function(){

View file

@ -469,17 +469,21 @@ describe("directive", function() {
expect(scope.$element.text()).toEqual('hey dude!'); expect(scope.$element.text()).toEqual('hey dude!');
}); });
it('should infer injection arguments', function(){
temp.MyController = function($xhr){
this.$root.someService = $xhr;
};
var scope = compile('<div ng:controller="temp.MyController"></div>');
expect(scope.someService).toBe(scope.$service('$xhr'));
});
}); });
describe('ng:cloak', function() { describe('ng:cloak', function() {
it('should get removed when an element is compiled', function() { it('should get removed when an element is compiled', function() {
var element = jqLite('<div ng:cloak></div>'); var element = jqLite('<div ng:cloak></div>');
expect(element.attr('ng:cloak')).toBe(''); expect(element.attr('ng:cloak')).toBe('');
angular.compile(element); angular.compile(element);
expect(element.attr('ng:cloak')).toBeUndefined(); expect(element.attr('ng:cloak')).toBeUndefined();
}); });