mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-18 07:50:22 +00:00
Auto create $inject property form the argument names. Any arg starting with $ or _ will be injected
This commit is contained in:
parent
7a54d2791f
commit
7d4aee31bb
4 changed files with 110 additions and 23 deletions
|
|
@ -4,6 +4,7 @@
|
||||||
### API
|
### API
|
||||||
- rewrite of JQuery lite implementation for better supports operations on multiple nodes when
|
- rewrite of JQuery lite implementation for better supports operations on multiple nodes when
|
||||||
matched by a selector.
|
matched by a selector.
|
||||||
|
- Infer DI dependencies from function signature. http://docs.angularjs.org/#!guide.di
|
||||||
|
|
||||||
### Breaking changes
|
### Breaking changes
|
||||||
- Removed the $init() method after the compilation. The old way of compiling the DOM element was
|
- Removed the $init() method after the compilation. The old way of compiling the DOM element was
|
||||||
|
|
|
||||||
|
|
@ -1077,10 +1077,15 @@ function bindJQuery(){
|
||||||
/**
|
/**
|
||||||
* throw error of the argument is falsy.
|
* throw error of the argument is falsy.
|
||||||
*/
|
*/
|
||||||
function assertArg(arg, name) {
|
function assertArg(arg, name, reason) {
|
||||||
if (!arg) {
|
if (!arg) {
|
||||||
var error = new Error("Argument '" + name + "' is required");
|
var error = new Error("Argument '" + (name||'?') + "' is " +
|
||||||
|
(reason || "required"));
|
||||||
if (window.console) window.console.log(error.stack);
|
if (window.console) window.console.log(error.stack);
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function assertArgFn(arg, name) {
|
||||||
|
assertArg(isFunction(arg, name, 'not a function'));
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,37 +5,41 @@
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
* Creates an inject function that can be used for dependency injection.
|
* Creates an inject function that can be used for dependency injection.
|
||||||
|
* (See {@link guide.di dependency injection})
|
||||||
|
*
|
||||||
|
* The inject function can be used for retrieving service instances or for calling any function
|
||||||
|
* which has the $inject property so that the services can be automatically provided. Angular
|
||||||
|
* creates an injection function automatically for the root scope and it is available as
|
||||||
|
* {@link angular.scope.$service $service}.
|
||||||
*
|
*
|
||||||
* @param {Object=} [providerScope={}] provider's `this`
|
* @param {Object=} [providerScope={}] provider's `this`
|
||||||
* @param {Object.<string, function()>=} [providers=angular.service] Map of provider (factory)
|
* @param {Object.<string, function()>=} [providers=angular.service] Map of provider (factory)
|
||||||
* function.
|
* function.
|
||||||
* @param {Object.<string, function()>=} [cache={}] Place where instances are saved for reuse. Can
|
* @param {Object.<string, function()>=} [cache={}] Place where instances are saved for reuse. Can
|
||||||
* also be used to override services speciafied by `providers` (useful in tests).
|
* also be used to override services speciafied by `providers` (useful in tests).
|
||||||
* @returns {function()} Injector function.
|
* @returns
|
||||||
|
* {function()} Injector function: `function(value, scope, args...)`:
|
||||||
|
*
|
||||||
|
* * `value` - `{string|array|function}`
|
||||||
|
* * `scope(optional=rootScope)` - optional function "`this`" when `value` is type `function`.
|
||||||
|
* * `args(optional)` - optional set of arguments to pass to function after injection arguments.
|
||||||
|
* (also known as curry arguments or currying).
|
||||||
|
*
|
||||||
|
* #Return value of `function(value, scope, args...)`
|
||||||
|
* The injector function return value depended on the type of `value` argument:
|
||||||
|
*
|
||||||
|
* * `string`: return an instance for the injection key.
|
||||||
|
* * `array` of keys: returns an array of instances for those keys. (see `string` above.)
|
||||||
|
* * `function`: look at `$inject` property of function to determine instances to inject
|
||||||
|
* and then call the function with instances and `scope`. Any additional arguments
|
||||||
|
* (`args`) are appended to the function arguments.
|
||||||
|
* * `none`: initialize eager providers.
|
||||||
*
|
*
|
||||||
* @TODO These docs need a lot of work. Specifically the returned function should be described in
|
|
||||||
* great detail + we need to provide some examples.
|
|
||||||
*/
|
*/
|
||||||
function createInjector(providerScope, providers, cache) {
|
function createInjector(providerScope, providers, cache) {
|
||||||
providers = providers || angularService;
|
providers = providers || angularService;
|
||||||
cache = cache || {};
|
cache = cache || {};
|
||||||
providerScope = providerScope || {};
|
providerScope = providerScope || {};
|
||||||
/**
|
|
||||||
* injection function
|
|
||||||
* @param value: string, array, object or function.
|
|
||||||
* @param scope: optional function "this"
|
|
||||||
* @param args: optional arguments to pass to function after injection
|
|
||||||
* parameters
|
|
||||||
* @returns depends on value:
|
|
||||||
* string: return an instance for the injection key.
|
|
||||||
* array of keys: returns an array of instances.
|
|
||||||
* function: look at $inject property of function to determine instances
|
|
||||||
* and then call the function with instances and `scope`. Any
|
|
||||||
* additional arguments (`args`) are appended to the function
|
|
||||||
* arguments.
|
|
||||||
* object: initialize eager providers and publish them the ones with publish here.
|
|
||||||
* none: same as object but use providerScope as place to publish.
|
|
||||||
*/
|
|
||||||
return function inject(value, scope, args){
|
return function inject(value, scope, args){
|
||||||
var returnValue, provider;
|
var returnValue, provider;
|
||||||
if (isString(value)) {
|
if (isString(value)) {
|
||||||
|
|
@ -51,7 +55,7 @@ function createInjector(providerScope, providers, cache) {
|
||||||
returnValue.push(inject(name));
|
returnValue.push(inject(name));
|
||||||
});
|
});
|
||||||
} else if (isFunction(value)) {
|
} else if (isFunction(value)) {
|
||||||
returnValue = inject(value.$inject || []);
|
returnValue = inject(injectionArgs(value));
|
||||||
returnValue = value.apply(scope, concat(returnValue, arguments, 2));
|
returnValue = value.apply(scope, concat(returnValue, arguments, 2));
|
||||||
} else if (isObject(value)) {
|
} else if (isObject(value)) {
|
||||||
forEach(providers, function(provider, name){
|
forEach(providers, function(provider, name){
|
||||||
|
|
@ -80,3 +84,33 @@ function injectUpdateView(fn) {
|
||||||
function angularServiceInject(name, fn, inject, eager) {
|
function angularServiceInject(name, fn, inject, eager) {
|
||||||
angularService(name, fn, {$inject:inject, $eager:eager});
|
angularService(name, fn, {$inject:inject, $eager:eager});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns the $inject property of function. If not found the
|
||||||
|
* the $inject is computed by looking at the toString of function and
|
||||||
|
* extracting all arguments which start with $ or end with _ as the
|
||||||
|
* injection names.
|
||||||
|
*/
|
||||||
|
var FN_ARGS = /^function [^\(]*\(([^\)]*)\)/;
|
||||||
|
var FN_ARG_SPLIT = /,/;
|
||||||
|
var FN_ARG = /^\s*(((\$?).+?)(_?))\s*$/;
|
||||||
|
var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
|
||||||
|
function injectionArgs(fn) {
|
||||||
|
assertArgFn(fn);
|
||||||
|
if (!fn.$inject) {
|
||||||
|
var args = fn.$inject = [];
|
||||||
|
var fnText = fn.toString().replace(STRIP_COMMENTS, '');
|
||||||
|
var argDecl = fnText.match(FN_ARGS);
|
||||||
|
forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg){
|
||||||
|
arg.replace(FN_ARG, function(all, name, injectName, $, _){
|
||||||
|
assertArg(args, name, 'after non-injectable arg');
|
||||||
|
if ($ || _)
|
||||||
|
args.push(injectName);
|
||||||
|
else
|
||||||
|
args = null; // once we reach an argument which is not injectable then ignore
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return fn.$inject;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -53,9 +53,56 @@ describe('injector', function(){
|
||||||
|
|
||||||
it('should autostart eager services', function(){
|
it('should autostart eager services', function(){
|
||||||
var log = '';
|
var log = '';
|
||||||
providers('eager', function(){log += 'eager;'; return 'foo'}, {$eager: true});
|
providers('eager', function(){log += 'eager;'; return 'foo';}, {$eager: true});
|
||||||
inject();
|
inject();
|
||||||
expect(log).toEqual('eager;');
|
expect(log).toEqual('eager;');
|
||||||
expect(inject('eager')).toBe('foo');
|
expect(inject('eager')).toBe('foo');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('annotation', function(){
|
||||||
|
it('should return $inject', function(){
|
||||||
|
function fn(){};
|
||||||
|
fn.$inject = ['a'];
|
||||||
|
expect(injectionArgs(fn)).toBe(fn.$inject);
|
||||||
|
expect(injectionArgs(function(){})).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create $inject', function(){
|
||||||
|
// keep the multi-line to make sure we can handle it
|
||||||
|
function $f_n0(
|
||||||
|
$a, // x, <-- looks like an arg but it is a comment
|
||||||
|
b_, /* z, <-- looks like an arg but it is a
|
||||||
|
multi-line comment
|
||||||
|
function (a, b){}
|
||||||
|
*/
|
||||||
|
/* {some type} */ c){ extraParans();};
|
||||||
|
expect(injectionArgs($f_n0)).toEqual(['$a', 'b']);
|
||||||
|
expect($f_n0.$inject).toEqual(['$a', 'b']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle no arg functions', function(){
|
||||||
|
function $f_n0(){};
|
||||||
|
expect(injectionArgs($f_n0)).toEqual([]);
|
||||||
|
expect($f_n0.$inject).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle args with both $ and _', function(){
|
||||||
|
function $f_n0($a_){};
|
||||||
|
expect(injectionArgs($f_n0)).toEqual(['$a']);
|
||||||
|
expect($f_n0.$inject).toEqual(['$a']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw on non function arg', function(){
|
||||||
|
expect(function(){
|
||||||
|
injectionArgs({});
|
||||||
|
}).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw on injectable after non-injectable arg', function(){
|
||||||
|
expect(function(){
|
||||||
|
injectionArgs(function($a, b_, nonInject, d_){});
|
||||||
|
}).toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue