From 7d4aee31bb202e9b050fc15c56cfc33c46b9eaf5 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Wed, 16 Feb 2011 19:18:35 -0500 Subject: Auto create $inject property form the argument names. Any arg starting with $ or _ will be injected --- src/Injector.js | 74 +++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 20 deletions(-) (limited to 'src/Injector.js') diff --git a/src/Injector.js b/src/Injector.js index 295928bf..a5a0b540 100644 --- a/src/Injector.js +++ b/src/Injector.js @@ -5,37 +5,41 @@ * * @description * 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.=} [providers=angular.service] Map of provider (factory) * function. * @param {Object.=} [cache={}] Place where instances are saved for reuse. Can * 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) { providers = providers || angularService; cache = cache || {}; 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){ var returnValue, provider; if (isString(value)) { @@ -51,7 +55,7 @@ function createInjector(providerScope, providers, cache) { returnValue.push(inject(name)); }); } else if (isFunction(value)) { - returnValue = inject(value.$inject || []); + returnValue = inject(injectionArgs(value)); returnValue = value.apply(scope, concat(returnValue, arguments, 2)); } else if (isObject(value)) { forEach(providers, function(provider, name){ @@ -80,3 +84,33 @@ function injectUpdateView(fn) { function angularServiceInject(name, fn, inject, 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; +}; -- cgit v1.2.3