diff options
| author | Misko Hevery | 2011-11-01 21:09:54 -0700 |
|---|---|---|
| committer | Misko Hevery | 2011-11-14 16:39:32 -0800 |
| commit | ed36b9da3be338fe9eb36f3eeea901d6f51cd768 (patch) | |
| tree | ffdc924e4b1fc1c6912674c82e029bf975ca9fca | |
| parent | c925f8a6578e05c8136c206f2fd98eeaaf1c0f16 (diff) | |
| download | angular.js-ed36b9da3be338fe9eb36f3eeea901d6f51cd768.tar.bz2 | |
refactor(injector): switch to injector 2.0 introduce modules
30 files changed, 239 insertions, 333 deletions
diff --git a/example/personalLog/test/personalLogSpec.js b/example/personalLog/test/personalLogSpec.js index cf80a420..2e93925c 100644 --- a/example/personalLog/test/personalLogSpec.js +++ b/example/personalLog/test/personalLogSpec.js @@ -2,7 +2,7 @@ describe('example.personalLog.LogCtrl', function() { var logCtrl; function createNotesCtrl() { - var injector = angular.injector(); + var injector = angular.injector('NG'); var scope = injector('$rootScope'); scope.$cookies = injector('$cookies'); return scope.$new(example.personalLog.LogCtrl); @@ -121,4 +121,4 @@ describe('example.personalLog.LogCtrl', function() { expect(logCtrl.$cookies.logs).not.toBeDefined(); }); }); -});
\ No newline at end of file +}); diff --git a/src/Angular.js b/src/Angular.js index bbd43d3b..4344425a 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -100,6 +100,7 @@ var _undefined = undefined, /** @name angular */ angular = window[$angular] || (window[$angular] = {}), + angularModules = angular.modules || (angular.modules = {}), /** @name angular.markup */ angularTextMarkup = extensionMap(angular, 'markup'), /** @name angular.attrMarkup */ @@ -274,6 +275,7 @@ function inherit(parent, extra) { </pre> */ function noop() {} +noop.$inject = []; /** @@ -292,6 +294,7 @@ function noop() {} </pre> */ function identity($) {return $;} +identity.$inject = []; function valueFn(value) {return function() {return value;};} @@ -945,14 +948,20 @@ function encodeUriQuery(val, pctEncodeSpaces) { */ function angularInit(config, document){ var autobind = config.autobind; - + if (autobind) { - var element = isString(autobind) ? document.getElementById(autobind) : document, - injector = createInjector(angularService), - scope = injector('$rootScope'); - - injector('$compile')(element)(scope); - scope.$apply(); + var modules = [ngModule]; + forEach((config.modules || '').split(','), function(module){ + module = trim(module); + if (module) { + modules.push(module); + } + }); + createInjector(modules, angularModules)(['$rootScope', '$compile', function(scope, compile){ + scope.$apply(function(){ + compile(isString(autobind) ? document.getElementById(autobind) : document)(scope); + }); + }]); } } @@ -1017,13 +1026,11 @@ function assertArgFn(arg, name) { function publishExternalAPI(angular){ extend(angular, { - // disabled for now until we agree on public name - //'annotate': annotate, 'copy': copy, 'extend': extend, 'equals': equals, 'forEach': forEach, - 'injector': createInjector, + 'injector': function(){ return createInjector(arguments, angularModules); }, 'noop':noop, 'bind':bind, 'toJson': toJson, @@ -1041,6 +1048,15 @@ function publishExternalAPI(angular){ 'lowercase': lowercase, 'uppercase': uppercase }); + + angularModules.NG = ngModule; +} + +ngModule.$inject = ['$provide']; +function ngModule($provide) { + forEach(angularService, function(factory, name){ + $provide.factory(name, factory); + }); } diff --git a/src/Injector.js b/src/Injector.js index fe0cc5e9..12c2ffa6 100644 --- a/src/Injector.js +++ b/src/Injector.js @@ -22,108 +22,16 @@ * The injector function also has these properties: * * * An `invoke` property which can be used to invoke methods with dependency-injected arguments. - * `injector.invoke(self, fn, curryArgs)` + * `injector.invoke(self, fn, locals)` * * `self` - The "`this`" to be used when invoking the function. * * `fn` - The function to be invoked. The function may have the `$inject` property that * lists the set of arguments which should be auto-injected. * (see {@link guide/dev_guide.di dependency injection}). - * * `curryArgs(array)` - Optional array of arguments to pass to the function - * invocation after the injection arguments (also known as curry arguments or currying). + * * `locals(array)` - Optional array of arguments to pass to the function + * invocation after the injection arguments. * * An `eager` property which is used to initialize the eager services. * `injector.eager()` */ -function createInjector(factories) { - var instanceCache = { - $injector: injector - }; - factories = factories || angularService; - - injector.invoke = invoke; - - forEach(factories, function(factory, name){ - if (factory.$eager) - injector(name); - }); - return instanceCache.$injector; - - function injector(serviceId, path){ - if (typeof serviceId == 'string') { - if (!(serviceId in instanceCache)) { - var factory = factories[serviceId]; - path = path || []; - path.unshift(serviceId); - if (!factory) throw Error("Unknown provider for '" + path.join("' <- '") + "'."); - inferInjectionArgs(factory); - instanceCache[serviceId] = invoke(null, factory, [], path); - path.shift(); - } - return instanceCache[serviceId]; - } else { - return invoke(null, serviceId, path); - } - } - - function invoke(self, fn, args, path){ - args = args || []; - var injectNames; - var i; - if (typeof fn == 'function') { - injectNames = fn.$inject || []; - i = injectNames.length; - } else if (fn instanceof Array) { - injectNames = fn; - i = injectNames.length; - fn = injectNames[--i]; - } - assertArgFn(fn, 'fn'); - while(i--) { - args.unshift(injector(injectNames[i], path)); - } - return fn.apply(self, args); - } -} - -/** - * THIS IS NOT PUBLIC DOC YET! - * - * @name angular.annotate - * @function - * - * @description - * Annotate the function with injection arguments. This is equivalent to setting the `$inject` - * property as described in {@link guide.di dependency injection}. - * - * <pre> - * var MyController = angular.annotate('$location', function($location){ ... }); - * </pre> - * - * is the same as - * - * <pre> - * var MyController = function($location){ ... }; - * MyController.$inject = ['$location']; - * </pre> - * - * @param {String|Array} serviceName... zero or more service names to inject into the - * `annotatedFunction`. - * @param {function} annotatedFunction function to annotate with `$inject` - * functions. - * @returns {function} `annotatedFunction` - */ -function annotate(services, fn) { - if (services instanceof Array) { - fn.$inject = services; - return fn; - } else { - var i = 0, - length = arguments.length - 1, // last one is the destination function - $inject = arguments[length].$inject = []; - for (; i < length; i++) { - $inject.push(arguments[i]); - } - return arguments[length]; // return the last one - } -} function angularServiceInject(name, fn, inject, eager) { angularService(name, fn, {$inject:inject, $eager:eager}); @@ -156,22 +64,16 @@ function inferInjectionArgs(fn) { } /////////////////////////////////////// -function createInjector2(modulesToLoad, moduleRegistry) { +function createInjector(modulesToLoad, moduleRegistry) { var cache = {}, $injector = internalInjector(cache), providerSuffix = 'Provider', providerSuffixLength = providerSuffix.length; - function $provide(name) { - var provider = cache['#' + name + providerSuffix]; - if (provider) { - return provider; - } else { - throw Error("No provider for: " + name); - } - } + value('$injector', $injector); + value('$provide', {service: service, factory: factory, value: value}); - $provide.service = function(name, provider) { + function service(name, provider) { if (isFunction(provider)){ provider = $injector.instantiate(provider); } @@ -180,11 +82,8 @@ function createInjector2(modulesToLoad, moduleRegistry) { } cache['#' + name + providerSuffix] = provider; }; - $provide.factory = function(name, factoryFn) { $provide.service(name, { $get:factoryFn }); }; - $provide.value = function(name, value) { $provide.factory(name, valueFn(value)); }; - - $provide.value('$injector', $injector); - $provide.value('$provide', $provide); + function factory(name, factoryFn) { service(name, { $get:factoryFn }); }; + function value(name, value) { factory(name, valueFn(value)); }; function internalInjector(cache) { var path = []; @@ -194,9 +93,10 @@ function createInjector2(modulesToLoad, moduleRegistry) { case 'function': return invoke(null, value); case 'string': - var instanceKey = '#' + value; - if (cache[instanceKey]) { - return cache[instanceKey]; + var instanceKey = '#' + value, + instance = cache[instanceKey]; + if (instance !== undefined || cache.hasOwnProperty(instanceKey)) { + return instance; } try { path.unshift(value); @@ -219,28 +119,32 @@ function createInjector2(modulesToLoad, moduleRegistry) { } } - function invoke(self, fn){ + function invoke(self, fn, locals){ var args = [], $inject, - length; - switch(typeof fn){ - case 'function': - $inject = inferInjectionArgs(fn); + length, + key; + + if (fn instanceof Function) { + $inject = inferInjectionArgs(fn); + length = $inject.length; + } else { + if (fn instanceof Array) { + $inject = fn; length = $inject.length; - break; - case 'object': - if (typeof fn.length == 'number') { - $inject = fn; - length = $inject.length; - fn = $inject[--length]; - } - default: - assertArgFn(fn, 'fn'); - }; + fn = $inject[--length]; + } + assertArgFn(fn, 'fn'); + } while(length--) { - args.unshift(injector($inject[length], path)); + key = $inject[length]; + args.unshift( + locals && locals.hasOwnProperty(key) + ? locals[key] + : injector($inject[length], path) + ); } switch (self ? -1 : args.length) { diff --git a/src/scenario/Runner.js b/src/scenario/Runner.js index d7e1a82b..fba076a8 100644 --- a/src/scenario/Runner.js +++ b/src/scenario/Runner.js @@ -163,7 +163,7 @@ angular.scenario.Runner.prototype.createSpecRunner_ = function(scope) { */ angular.scenario.Runner.prototype.run = function(application) { var self = this; - var $root = angular.injector()('$rootScope'); + var $root = angular.injector('NG')('$rootScope'); angular.extend($root, this); angular.forEach(angular.scenario.Runner.prototype, function(fn, name) { $root[name] = angular.bind(self, fn); diff --git a/src/scenario/dsl.js b/src/scenario/dsl.js index 13ae8b8f..97749787 100644 --- a/src/scenario/dsl.js +++ b/src/scenario/dsl.js @@ -103,25 +103,25 @@ angular.scenario.dsl('browser', function() { api.url = function() { return this.addFutureAction('$location.url()', function($window, $document, done) { - done(null, $window.angular.injector()('$location').url()); + done(null, $window.angular.injector('NG')('$location').url()); }); }; api.path = function() { return this.addFutureAction('$location.path()', function($window, $document, done) { - done(null, $window.angular.injector()('$location').path()); + done(null, $window.angular.injector('NG')('$location').path()); }); }; api.search = function() { return this.addFutureAction('$location.search()', function($window, $document, done) { - done(null, $window.angular.injector()('$location').search()); + done(null, $window.angular.injector('NG')('$location').search()); }); }; api.hash = function() { return this.addFutureAction('$location.hash()', function($window, $document, done) { - done(null, $window.angular.injector()('$location').hash()); + done(null, $window.angular.injector('NG')('$location').hash()); }); }; diff --git a/src/service/compiler.js b/src/service/compiler.js index c1728f7d..0bd3e54d 100644 --- a/src/service/compiler.js +++ b/src/service/compiler.js @@ -22,14 +22,15 @@ angularServiceInject('$compile', function($injector, $exceptionHandler, $textMar Template.prototype = { link: function(element, scope) { - var childScope = scope; + var childScope = scope, + locals = {$element: element}; if (this.newScope) { childScope = isFunction(this.newScope) ? scope.$new(this.newScope(scope)) : scope.$new(); element.data($$scope, childScope); } forEach(this.linkFns, function(fn) { try { - childScope.$service.invoke(childScope, fn, [element]); + $injector.invoke(childScope, fn, locals); } catch (e) { $exceptionHandler(e); } @@ -54,6 +55,10 @@ angularServiceInject('$compile', function($injector, $exceptionHandler, $textMar addLinkFn:function(linkingFn) { if (linkingFn) { + //TODO(misko): temporary hack. + if (isFunction(linkingFn) && !linkingFn.$inject) { + linkingFn.$inject = ['$element']; + } this.linkFns.push(linkingFn); } }, diff --git a/src/widget/form.js b/src/widget/form.js index 065ee74d..4608efc1 100644 --- a/src/widget/form.js +++ b/src/widget/form.js @@ -56,7 +56,7 @@ angularWidget('form', function(form){ this.descend(true); this.directives(true); - return annotate('$formFactory', function($formFactory, formElement) { + return ['$formFactory', '$element', function($formFactory, formElement) { var name = formElement.attr('name'), parentForm = $formFactory.forElement(formElement), form = $formFactory(parentForm); @@ -74,7 +74,7 @@ angularWidget('form', function(form){ formElement[value ? 'addClass' : 'removeClass']('ng-' + name); }); } - }); + }]; }); angularWidget('ng:form', angularWidget('form')); diff --git a/src/widget/input.js b/src/widget/input.js index cf29d0f1..5108a4e4 100644 --- a/src/widget/input.js +++ b/src/widget/input.js @@ -569,7 +569,7 @@ angularInputType('radio', function(inputElement) { function numericRegexpInputType(regexp, error) { - return function(inputElement) { + return ['$element', function(inputElement) { var widget = this, min = 1 * (inputElement.attr('min') || Number.MIN_VALUE), max = 1 * (inputElement.attr('max') || Number.MAX_VALUE); @@ -598,7 +598,7 @@ function numericRegexpInputType(regexp, error) { widget.$viewValue = '' + widget.$modelValue; } }; - }; + }]; } @@ -713,7 +713,7 @@ angularWidget('input', function(inputElement){ this.descend(true); var modelExp = inputElement.attr('ng:model'); return modelExp && - annotate('$defer', '$formFactory', function($defer, $formFactory, inputElement){ + ['$defer', '$formFactory', '$element', function($defer, $formFactory, inputElement){ var form = $formFactory.forElement(inputElement), // We have to use .getAttribute, since jQuery tries to be smart and use the // type property. Trouble is some browser change unknown to text. @@ -761,14 +761,16 @@ angularWidget('input', function(inputElement){ } } - !TypeController.$inject && (TypeController.$inject = []); + //TODO(misko): setting $inject is a hack + !TypeController.$inject && (TypeController.$inject = ['$element']); widget = form.$createWidget({ scope: modelScope, model: modelExp, onChange: inputElement.attr('ng:change'), alias: inputElement.attr('name'), controller: TypeController, - controllerArgs: [inputElement]}); + controllerArgs: {$element: inputElement} + }); watchElementProperty(this, widget, 'value', inputElement); watchElementProperty(this, widget, 'required', inputElement); @@ -830,7 +832,7 @@ angularWidget('input', function(inputElement){ } }); } - }); + }]; }); diff --git a/src/widget/select.js b/src/widget/select.js index 2e328b26..c70b5ded 100644 --- a/src/widget/select.js +++ b/src/widget/select.js @@ -131,7 +131,7 @@ angularWidget('select', function(element){ this.directives(true); this.descend(true); return element.attr('ng:model') && - annotate('$formFactory', '$compile', function($formFactory, $compile, selectElement){ + ['$formFactory', '$compile', '$element', function($formFactory, $compile, selectElement){ var modelScope = this, match, form = $formFactory.forElement(selectElement), @@ -433,5 +433,5 @@ angularWidget('select', function(element){ } }; } - }); + }]; }); diff --git a/src/widgets.js b/src/widgets.js index 11d9a2f0..6ecd27a1 100644 --- a/src/widgets.js +++ b/src/widgets.js @@ -90,7 +90,7 @@ angularWidget('ng:include', function(element){ this.directives(true); } else { element[0]['ng:compiled'] = true; - return extend(function(xhr, element){ + return ['$xhr.cache', '$element', function(xhr, element){ var scope = this, changeCounter = 0, releaseScopes = [], @@ -129,7 +129,7 @@ angularWidget('ng:include', function(element){ element.html(''); } }); - }, {$inject:['$xhr.cache']}); + }]; } }); @@ -555,7 +555,7 @@ angularWidget('ng:view', function(element) { if (!element[0]['ng:compiled']) { element[0]['ng:compiled'] = true; - return annotate('$xhr.cache', '$route', function($xhr, $route, element){ + return ['$xhr.cache', '$route', '$element', function($xhr, $route, element){ var template; var changeCounter = 0; @@ -578,7 +578,7 @@ angularWidget('ng:view', function(element) { element.html(''); } }); - }); + }]; } else { compiler.descend(true); compiler.directives(true); @@ -759,7 +759,7 @@ angularWidget('ng:pluralize', function(element) { whenExp = element.attr('when'), offset = element.attr('offset') || 0; - return annotate('$locale', function($locale, element) { + return ['$locale', '$element', function($locale, element) { var scope = this, whens = scope.$eval(whenExp), whensExpFns = {}; @@ -783,5 +783,5 @@ angularWidget('ng:pluralize', function(element) { }, function(scope, newVal) { element.text(newVal); }); - }); + }]; }); diff --git a/test/AngularSpec.js b/test/AngularSpec.js index a957fcf7..8902c2a9 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -375,9 +375,9 @@ describe('angular', function() { describe('angular service', function() { - it('should override services', inject(function(service){ - service('fake', function() { return 'old'; }); - service('fake', function() { return 'new'; }); + it('should override services', inject(function($provide){ + $provide.value('fake', 'old'); + $provide.value('fake', 'new'); }, function(fake) { expect(fake).toEqual('new'); })); @@ -401,22 +401,23 @@ describe('angular', function() { expect(result.third).toBeTruthy(); }); - it('should inject dependencies specified by $inject', function() { - angular.service('svc1', function() { return 'svc1'; }); - angular.service('svc2', function(svc1) { return 'svc2-' + svc1; }, {$inject: ['svc1']}); - expect(createInjector()('svc2')).toEqual('svc2-svc1'); - }); - it('should inject dependencies specified by $inject and ignore function argument name', function() { - angular.service('svc1', function() { return 'svc1'; }); - angular.service('svc2', function(foo) { return 'svc2-' + foo; }, {$inject: ['svc1']}); - expect(createInjector()('svc2')).toEqual('svc2-svc1'); + expect(angular.injector(function($provide){ + $provide.factory('svc1', function() { return 'svc1'; }); + $provide.factory('svc2', ['svc1', function(s) { return 'svc2-' + s; }]); + })('svc2')).toEqual('svc2-svc1'); }); it('should eagerly instantiate a service if $eager is true', function() { var log = []; - angular.service('svc1', function() { log.push('svc1'); }, {$eager: true}); - createInjector(angularService); + angular.injector(function($provide){ + $provide.service('svc1', function() { + this.$get = function(){ + log.push('svc1'); + } + this.$eager = true; + }); + }); expect(log).toEqual(['svc1']); }); }); diff --git a/test/BinderSpec.js b/test/BinderSpec.js index 6a459074..495d98a8 100644 --- a/test/BinderSpec.js +++ b/test/BinderSpec.js @@ -222,8 +222,8 @@ describe('Binder', function() { })); it('IfTextBindingThrowsErrorDecorateTheSpan', inject( - function(service){ - service('$exceptionHandler', $exceptionHandlerMockFactory); + function($provide){ + $provide.factory('$exceptionHandler', $exceptionHandlerMockFactory); }, function($rootScope, $exceptionHandler, $compile) { $compile('<div>{{error.throw()}}</div>', null, true)($rootScope); @@ -245,8 +245,8 @@ describe('Binder', function() { }) ); - it('IfAttrBindingThrowsErrorDecorateTheAttribute', inject(function(service){ - service('$exceptionHandler', $exceptionHandlerMockFactory); + it('IfAttrBindingThrowsErrorDecorateTheAttribute', inject(function($provide){ + $provide.factory('$exceptionHandler', $exceptionHandlerMockFactory); }, function($rootScope, $exceptionHandler, $compile) { $compile('<div attr="before {{error.throw()}} after"></div>', null, true)($rootScope); var errorLogs = $exceptionHandler.errors; @@ -387,8 +387,8 @@ describe('Binder', function() { })); it('ActionOnAHrefThrowsError', inject( - function(service){ - service('$exceptionHandler', $exceptionHandlerMockFactory); + function($provide){ + $provide.factory('$exceptionHandler', $exceptionHandlerMockFactory); }, function($rootScope, $exceptionHandler, $compile) { var input = $compile('<a ng:click="action()">Add Phone</a>')($rootScope); @@ -471,8 +471,8 @@ describe('Binder', function() { })); it('ItShouldDisplayErrorWhenActionIsSyntacticlyIncorrect', inject( - function(service){ - service('$exceptionHandler', $exceptionHandlerMockFactory); + function($provide){ + $provide.factory('$exceptionHandler', $exceptionHandlerMockFactory); }, function($rootScope, $exceptionHandler, $log, $compile) { var element = $compile( diff --git a/test/InjectorSpec.js b/test/InjectorSpec.js index 8c36677d..3ba819b8 100644 --- a/test/InjectorSpec.js +++ b/test/InjectorSpec.js @@ -4,10 +4,12 @@ describe('injector', function() { var providers; var injector; - beforeEach(function() { - providers = extensionMap({}, 'providers'); - injector = createInjector(providers); - }); + beforeEach(inject(function($injector, $provide) { + providers = function(name, factory, decoration){ + $provide.factory(name, extend(factory, decoration||{})); + }; + injector = $injector; + })); it("should return same instance from calling provider", function() { var instance = {}, @@ -29,10 +31,10 @@ describe('injector', function() { it('should resolve dependency graph and instantiate all services just once', function() { var log = []; -// s1 -// / |\ -// / s2\ -// / / | \\ +// s1 +// / | \ +// / s2 \ +// / / | \ \ // /s3 < s4 > s5 // // // s6 @@ -58,15 +60,24 @@ describe('injector', function() { }); it('should proved path to the missing provider', function() { + providers('a', function(idontexist) {return 1;}); + providers('b', function(a) {return 2;}); expect(function() { - injector('idontexist', ['a', 'b']); + injector('b'); }).toThrow("Unknown provider for 'idontexist' <- 'a' <- 'b'."); }); it('should autostart eager services', function() { var log = ''; - providers('eager', function() {log += 'eager;'; return 'foo';}, {$eager: true}); - injector = createInjector(providers); + injector = createInjector([function($provide){ + $provide.service('eager', function() { + this.$eager = true; + this.$get = function(){ + log += 'eager;'; + return 'foo'; + }; + }); + }]); expect(log).toEqual('eager;'); expect(injector('eager')).toBe('foo'); }); @@ -88,20 +99,22 @@ describe('injector', function() { it('should call function', function() { - fn.$inject = ['a', 'b']; - injector.invoke({name:"this"}, fn, [3, 4]); + fn.$inject = ['a', 'b', 'c', 'd']; + injector.invoke({name:"this"}, fn, {c:3, d:4}); expect(args).toEqual([{name:'this'}, 1, 2, 3, 4]); }); it('should treat array as annotations', function() { - injector.invoke({name:"this"}, ['a', 'b', fn], [3, 4]); + injector.invoke({name:"this"}, ['a', 'b', 'c', 'd', fn], {c:3, d:4}); expect(args).toEqual([{name:'this'}, 1, 2, 3, 4]); }); it('should invoke the passed in function with all of the dependencies as arguments', function(){ - expect(injector(['a', 'b', fn], [3, 4])).toEqual(10); + providers('c', function() {return 3;}); + providers('d', function() {return 4;}); + expect(injector(['a', 'b', 'c', 'd', fn])).toEqual(10); }); @@ -159,38 +172,17 @@ describe('injector', function() { }).toThrow(); }); - it('should infer injection on services', function() { - var $injector = createInjector({ - a: function() { return 'a';}, - b: function(a) { return a + 'b';} - }); - expect($injector('b')).toEqual('ab'); - }); - }); - - describe('inject', function() { - it('should inject names', function() { - expect(annotate('a', {}).$inject).toEqual(['a']); - expect(annotate('a', 'b', {}).$inject).toEqual(['a', 'b']); - }); - - it('should inject array', function() { - expect(annotate(['a'], {}).$inject).toEqual(['a']); - expect(annotate(['a', 'b'], {}).$inject).toEqual(['a', 'b']); - }); }); -}); -describe('injector2', function() { it('should have $injector', function() { - var $injector = createInjector2(); + var $injector = createInjector(); expect($injector('$injector')).toBe($injector); }); it('should define module', function() { var log = ''; - var injector = createInjector2([function($provide) { + var injector = createInjector([function($provide) { $provide.value('value', 'value;'); $provide.factory('fn', valueFn('function;')); $provide.service('service', function() { @@ -208,7 +200,7 @@ describe('injector2', function() { describe('module', function() { it('should provide $injector and $provide even when no module is requested', function() { var $provide, - $injector = createInjector2([ + $injector = createInjector([ angular.extend(function(p) { $provide = p; }, {$inject: ['$provide']}) ]); expect($injector('$injector')).toBe($injector); @@ -218,7 +210,7 @@ describe('injector2', function() { it('should load multiple function modules and infer inject them', function() { var a = 'junk'; - var $injector = createInjector2([ + var $injector = createInjector([ function() { a = 'A'; // reset to prove we ran }, @@ -239,7 +231,7 @@ describe('injector2', function() { it('should run symbolic modules', function() { - var $injector = createInjector2(['myModule'], { + var $injector = createInjector(['myModule'], { myModule: ['$provide', function(provide) { provide.value('a', 'abc'); }] @@ -251,7 +243,7 @@ describe('injector2', function() { describe('$provide', function() { describe('value', function(){ it('should configure $provide values', function() { - expect(createInjector2([function($provide) { + expect(createInjector([function($provide) { $provide.value('value', 'abc'); }])('value')).toEqual('abc'); }); @@ -260,7 +252,7 @@ describe('injector2', function() { describe('factory', function(){ it('should configure $provide factory function', function() { - expect(createInjector2([function($provide) { + expect(createInjector([function($provide) { $provide.factory('value', valueFn('abc')); }])('value')).toEqual('abc'); }); @@ -269,7 +261,7 @@ describe('injector2', function() { describe('service', function(){ it('should configure $provide service object', function() { - expect(createInjector2([function($provide) { + expect(createInjector([function($provide) { $provide.service('value', { $get: valueFn('abc') }); @@ -283,7 +275,7 @@ describe('injector2', function() { expect(this instanceof Type).toBe(true); return 'abc'; }; - expect(createInjector2([function($provide) { + expect(createInjector([function($provide) { $provide.service('value', Type); }])('value')).toEqual('abc'); }); @@ -294,7 +286,7 @@ describe('injector2', function() { describe('error handling', function() { it('should handle wrong argument type', function() { expect(function() { - createInjector2([ + createInjector([ {} ], {}); }).toThrow("Argument 'module' is not a function, got Object"); @@ -303,7 +295,7 @@ describe('injector2', function() { it('should handle exceptions', function() { expect(function() { - createInjector2([function() { + createInjector([function() { throw 'MyError'; }], {}); }).toThrow('MyError'); @@ -312,7 +304,7 @@ describe('injector2', function() { it('should handle no module alias', function() { expect(function() { - createInjector2([function(dontExist) { + createInjector([function(dontExist) { }], {}); }).toThrow("Unknown provider for 'dontExist'."); }); @@ -326,7 +318,7 @@ describe('injector2', function() { $provide; beforeEach(function() { - $injector = createInjector2([ ['$provide', function(provide) { + $injector = createInjector([ ['$provide', function(provide) { ($provide = provide).value('instance', instance = {name:'angular'}); }]]); }); @@ -350,7 +342,7 @@ describe('injector2', function() { var $injector; beforeEach(function() { - $injector = createInjector2([ function($provide) { + $injector = createInjector([ function($provide) { $provide.value('book', 'moby'); $provide.value('author', 'melville'); }]); @@ -365,6 +357,16 @@ describe('injector2', function() { }); + it('should invoke method with locals', function() { + expect($injector(function(book, author) { return author + ':' + book;})).toEqual('melville:moby'); + expect($injector.invoke($injector, + function(book, author, chapter) { + expect(this).toEqual($injector); + return author + ':' + book + '-' + chapter; + }, {author:'m', chapter:'ch1'})).toEqual('m:moby-ch1'); + }); + + it('should invoke method which is annotated', function() { expect($injector(extend(function(b, a) { return a + ':' + b}, {$inject:['book', 'author']}))). toEqual('melville:moby'); @@ -395,7 +397,7 @@ describe('injector2', function() { var $injector; beforeEach(function() { - $injector = createInjector2([ function($provide) { + $injector = createInjector([ function($provide) { $provide.value('book', 'moby'); $provide.value('author', 'melville'); }]); @@ -433,7 +435,19 @@ describe('injector2', function() { }); }); - describe('injector chaining', function() { - + describe('$eager', function(){ + it('should eagerly instantiate a service if $eager is true', function() { + var log = []; + createInjector([function($provide){ + $provide.service('svc1', function() { + this.$get = function(){ + log.push('svc1'); + } + this.$eager = true; + }); + }]); + expect(log).toEqual(['svc1']); + }); }); + }); diff --git a/test/ResourceSpec.js b/test/ResourceSpec.js index 928b4f6c..f648eb1b 100644 --- a/test/ResourceSpec.js +++ b/test/ResourceSpec.js @@ -4,9 +4,9 @@ describe("resource", function() { var resource, CreditCard, callback; beforeEach(inject( - function(service) { - service('$xhr.error', function(){return jasmine.createSpy('xhr.error')}); - service.alias('$xhr.error', '$xhrError'); + function($provide) { + $provide.value('$xhr.error', jasmine.createSpy('xhr.error')); + $provide.factory('$xhrError', ['$xhr.error', identity]); }, function($xhr) { resource = new ResourceFactory($xhr); diff --git a/test/markupSpec.js b/test/markupSpec.js index c23cc62d..f93acb98 100644 --- a/test/markupSpec.js +++ b/test/markupSpec.js @@ -150,7 +150,7 @@ describe("markups", function() { it('should bind Text with no Bindings', inject(function($compile) { var $rootScope; function newScope (){ - return $rootScope = angular.injector()('$rootScope'); + return $rootScope = angular.injector('NG')('$rootScope'); } forEach(['checked', 'disabled', 'multiple', 'readonly', 'selected'], function(name) { var element = $compile('<div ng:' + name + '="some"></div>')(newScope()) diff --git a/test/scenario/dslSpec.js b/test/scenario/dslSpec.js index 6ecc386d..411320e8 100644 --- a/test/scenario/dslSpec.js +++ b/test/scenario/dslSpec.js @@ -10,7 +10,7 @@ describe("angular.scenario.dsl", function() { document: _jQuery("<div></div>"), angular: new angular.scenario.testing.MockAngular() }; - $root = angular.injector()('$rootScope'); + $root = angular.injector('NG')('$rootScope'); $root.emit = function(eventName) { eventLog.push(eventName); }; diff --git a/test/service/compilerSpec.js b/test/service/compilerSpec.js index 4e0dbed6..ccf70aaf 100644 --- a/test/service/compilerSpec.js +++ b/test/service/compilerSpec.js @@ -3,7 +3,7 @@ describe('compiler', function() { var compiler, textMmarkup, attrMarkup, directives, widgets, compile, log, $rootScope; - beforeEach(inject(function(service){ + beforeEach(inject(function($provide){ textMmarkup = []; attrMarkup = []; widgets = extensionMap({}, 'widget'); @@ -26,10 +26,10 @@ describe('compiler', function() { }; log = ""; - service('$textMarkup', valueFn(textMmarkup)); - service('$attrMarkup', valueFn(attrMarkup)); - service('$directive', valueFn(directives)); - service('$widget', valueFn(widgets)); + $provide.value('$textMarkup', textMmarkup); + $provide.value('$attrMarkup', attrMarkup); + $provide.value('$directive', directives); + $provide.value('$widget', widgets); })); diff --git a/test/service/cookiesSpec.js b/test/service/cookiesSpec.js index 2569645b..66bdc504 100644 --- a/test/service/cookiesSpec.js +++ b/test/service/cookiesSpec.js @@ -1,8 +1,8 @@ 'use strict'; describe('$cookies', function() { - beforeEach(inject(function(service) { - service('$browser', function(){ + beforeEach(inject(function($provide) { + $provide.factory('$browser', function(){ return angular.extend(new MockBrowser(), {cookieHash: {preexisting:'oldCookie'}}); }); })); diff --git a/test/service/deferSpec.js b/test/service/deferSpec.js index 98ddeac5..2468512d 100644 --- a/test/service/deferSpec.js +++ b/test/service/deferSpec.js @@ -1,8 +1,8 @@ 'use strict'; describe('$defer', function() { - beforeEach(inject(function(service) { - service('$exceptionHandler', function(){ + beforeEach(inject(function($provide) { + $provide.factory('$exceptionHandler', function(){ return jasmine.createSpy('$exceptionHandler'); }); })); diff --git a/test/service/exceptionHandlerSpec.js b/test/service/exceptionHandlerSpec.js index 3bfb70c0..821ad7b8 100644 --- a/test/service/exceptionHandlerSpec.js +++ b/test/service/exceptionHandlerSpec.js @@ -4,9 +4,9 @@ describe('$exceptionHandler', function() { it('should log errors', inject( - function(service){ - service('$exceptionHandler', $exceptionHandlerFactory); - service('$log', valueFn($logMock)); + function($provide){ + $provide.factory('$exceptionHandler', $exceptionHandlerFactory); + $provide.value('$log', $logMock); }, function($log, $exceptionHandler) { $log.error.rethrow = false; diff --git a/test/service/locationSpec.js b/test/service/locationSpec.js index 38df2619..65ca36a7 100644 --- a/test/service/locationSpec.js +++ b/test/service/locationSpec.js @@ -308,13 +308,9 @@ describe('$location', function() { function initService(html5Mode, hashPrefix, supportHistory) { - return function(service){ - service('$locationConfig', function(){ - return {html5Mode: html5Mode, hashPrefix: hashPrefix}; - }); - service('$sniffer', function(){ - return {history: supportHistory}; - }); + return function($provide){ + $provide.value('$locationConfig', {html5Mode: html5Mode, hashPrefix: hashPrefix}); + $provide.value('$sniffer', {history: supportHistory}); }; } function initBrowser(url, basePath) { @@ -580,7 +576,7 @@ describe('$location', function() { var root, link, originalBrowser, lastEventPreventDefault; function configureService(linkHref, html5Mode, supportHist, attrs, content) { - return function(service){ + return function($provide){ var jqRoot = jqLite('<div></div>'); attrs = attrs ? ' ' + attrs + ' ' : ''; link = jqLite('<a href="' + linkHref + '"' + attrs + '>' + content + '</a>')[0]; @@ -588,9 +584,9 @@ describe('$location', function() { jqLite(document.body).append(jqRoot); - service('$document', function(){ return jqRoot; }); - service('$sniffer', function(){ return {history: supportHist}; }); - service('$locationConfig', function(){ return {html5Mode: html5Mode, hashPrefix: '!'}; }); + $provide.value('$document', jqRoot); + $provide.value('$sniffer', {history: supportHist}); + $provide.value('$locationConfig', {html5Mode: html5Mode, hashPrefix: '!'}); }; } diff --git a/test/service/logSpec.js b/test/service/logSpec.js index 8c56d99e..3b860756 100644 --- a/test/service/logSpec.js +++ b/test/service/logSpec.js @@ -9,12 +9,12 @@ describe('$log', function() { function info() { logger+= 'info;'; } function error() { logger+= 'error;'; } - beforeEach(inject(function(service){ + beforeEach(inject(function($provide){ $window = {}; logger = ''; - service('$log', $logFactory); - service('$exceptionHandler', valueFn(rethrow)); - service('$window', valueFn($window)); + $provide.factory('$log', $logFactory); + $provide.value('$exceptionHandler', rethrow); + $provide.value('$window', $window); })); it('should use console if present', inject( diff --git a/test/service/scopeSpec.js b/test/service/scopeSpec.js index 2cd2f635..b7f50edb 100644 --- a/test/service/scopeSpec.js +++ b/test/service/scopeSpec.js @@ -2,8 +2,8 @@ describe('Scope', function() { - beforeEach(inject(function(service) { - service('$exceptionHandler', $exceptionHandlerMockFactory); + beforeEach(inject(function($provide) { + $provide.factory('$exceptionHandler', $exceptionHandlerMockFactory); })); @@ -66,7 +66,7 @@ describe('Scope', function() { this.callCount = 0; this.name = name; } - Cntl.$inject = ['$browser']; + Cntl.$inject = ['$browser', 'name']; Cntl.prototype = { myFn: function() { @@ -75,7 +75,7 @@ describe('Scope', function() { } }; - var cntl = $rootScope.$new(Cntl, ['misko']); + var cntl = $rootScope.$new(Cntl, {name:'misko'}); expect($rootScope.$browser).toBeUndefined(); expect($rootScope.myFn).toBeUndefined(); @@ -285,7 +285,7 @@ describe('Scope', function() { it('should return a function that allows listeners to be unregistered', inject(function($rootScope) { - var root = angular.injector()('$rootScope'), + var root = angular.injector('NG')('$rootScope'), listener = jasmine.createSpy('watch listener'), listenerRemove; @@ -470,7 +470,7 @@ describe('Scope', function() { it('should add listener for both $emit and $broadcast events', inject(function($rootScope) { var log = '', - root = angular.injector()('$rootScope'), + root = angular.injector('NG')('$rootScope'), child = root.$new(); function eventFn() { @@ -490,7 +490,7 @@ describe('Scope', function() { it('should return a function that deregisters the listener', inject(function($rootScope) { var log = '', - root = angular.injector()('$rootScope'), + root = angular.injector('NG')('$rootScope'), child = root.$new(), listenerRemove; @@ -669,7 +669,7 @@ describe('Scope', function() { describe('listener', function() { it('should receive event object', inject(function($rootScope) { - var scope = angular.injector()('$rootScope'), + var scope = angular.injector('NG')('$rootScope'), child = scope.$new(), event; @@ -685,7 +685,7 @@ describe('Scope', function() { it('should support passing messages as varargs', inject(function($rootScope) { - var scope = angular.injector()('$rootScope'), + var scope = angular.injector('NG')('$rootScope'), child = scope.$new(), args; diff --git a/test/service/xhr.bulkSpec.js b/test/service/xhr.bulkSpec.js index 6f273f64..6e55b387 100644 --- a/test/service/xhr.bulkSpec.js +++ b/test/service/xhr.bulkSpec.js @@ -3,12 +3,10 @@ describe('$xhr.bulk', function() { var log; - beforeEach(inject(function(service) { - service('$xhr.error', function(){ - return jasmine.createSpy('$xhr.error'); - }); - service.alias('$xhr.error', '$xhrError'); - service.alias('$xhr.bulk', '$xhrBulk'); + beforeEach(inject(function($provide) { + $provide.value('$xhr.error', jasmine.createSpy('$xhr.error')); + $provide.factory('$xhrError', ['$xhr.error', identity]); + $provide.factory('$xhrBulk', ['$xhr.bulk', identity]); log = ''; })); diff --git a/test/service/xhr.cacheSpec.js b/test/service/xhr.cacheSpec.js index 328dfe3a..b6eeb6aa 100644 --- a/test/service/xhr.cacheSpec.js +++ b/test/service/xhr.cacheSpec.js @@ -3,13 +3,11 @@ describe('$xhr.cache', function() { var log; - beforeEach(inject(function(service) { - service('$xhr.error', function(){ - return jasmine.createSpy('$xhr.error'); - }); - service.alias('$xhr.cache', '$xhrCache'); - service.alias('$xhr.bulk', '$xhrBulk'); - service.alias('$xhr.error', '$xhrError'); + beforeEach(inject(function($provide) { + $provide.value('$xhr.error', jasmine.createSpy('$xhr.error')); + $provide.factory('$xhrError', ['$xhr.error', identity]); + $provide.factory('$xhrBulk', ['$xhr.bulk', identity]); + $provide.factory('$xhrCache', ['$xhr.cache', identity]); log = ''; })); diff --git a/test/service/xhr.errorSpec.js b/test/service/xhr.errorSpec.js index 0ed5ab59..f9ce2b72 100644 --- a/test/service/xhr.errorSpec.js +++ b/test/service/xhr.errorSpec.js @@ -3,11 +3,9 @@ describe('$xhr.error', function() { var log; - beforeEach(inject(function(service) { - service('$xhr.error', function(){ - return jasmine.createSpy('$xhr.error'); - }); - service.alias('$xhr.error', '$xhrError'); + beforeEach(inject(function($provide) { + $provide.value('$xhr.error', jasmine.createSpy('$xhr.error')); + $provide.factory('$xhrError', ['$xhr.error', identity]); log = ''; })); diff --git a/test/service/xhrSpec.js b/test/service/xhrSpec.js index 997994d7..83c5f93f 100644 --- a/test/service/xhrSpec.js +++ b/test/service/xhrSpec.js @@ -4,12 +4,10 @@ describe('$xhr', function() { var log; - beforeEach(inject(function(service) { + beforeEach(inject(function($provide) { log = ''; - service('$xhr.error', function(){ - return jasmine.createSpy('xhr.error'); - }); - service.alias('$xhr.error', '$xhrError'); + $provide.value('$xhr.error', jasmine.createSpy('xhr.error')); + $provide.factory('$xhrError', ['$xhr.error', identity]); })); diff --git a/test/testabilityPatch.js b/test/testabilityPatch.js index 3e68fbed..eb98cb6f 100644 --- a/test/testabilityPatch.js +++ b/test/testabilityPatch.js @@ -88,33 +88,9 @@ function inject(){ var blockFns = sliceArgs(arguments); return function(){ var spec = this; + spec.$injector = spec.$injector || angular.injector('NG'); angular.forEach(blockFns, function(fn){ - fn.$inject = inferInjectionArgs(fn); - if (equals(fn.$inject, [])) { - fn.apply(spec); - } else if (equals(fn.$inject, ['service'])) { - if (spec.$injector) { - throw Error('$injector already created for this test'); - } - if (!spec.$service) { - spec.$service = function(name, fn) { - if (fn) { spec.$service[name] = fn; } - return spec.$service[name]; - } - spec.$service.alias = function (name, alias) { - spec.$service(alias, extend(function(x){ return x; }, {$inject:[name]})); - }; - forEach(angularService, function(value, key){ - spec.$service(key, value); - }); - } - fn.call(spec, spec.$service); - } else { - if (!spec.$injector) { - spec.$injector = angular.injector(spec.$service || angular.service); - } - spec.$injector.invoke(spec, fn); - } + spec.$injector.invoke(spec, fn); }); }; } diff --git a/test/widget/inputSpec.js b/test/widget/inputSpec.js index 6ab53ab0..8d409b25 100644 --- a/test/widget/inputSpec.js +++ b/test/widget/inputSpec.js @@ -460,12 +460,12 @@ describe('widget: input', function() { describe('scope declaration', function() { it('should read the declaration from scope', inject(function($rootScope, $compile) { var input, $formFactory; - element = angular.element('<input type="@MyType" ng:model="abc">'); + var element = angular.element('<input type="@MyType" ng:model="abc">'); $rootScope.MyType = function($f, i) { input = i; $formFactory = $f; }; - $rootScope.MyType.$inject = ['$formFactory']; + $rootScope.MyType.$inject = ['$formFactory', '$element']; $compile(element)($rootScope); @@ -475,7 +475,7 @@ describe('widget: input', function() { it('should throw an error of Controller not declared in scope', inject(function($rootScope, $compile) { var input, $formFactory; - element = angular.element('<input type="@DontExist" ng:model="abc">'); + var element = angular.element('<input type="@DontExist" ng:model="abc">'); var error; try { $compile(element)($rootScope); diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js index b7ef16a4..ef28ea77 100644 --- a/test/widgetsSpec.js +++ b/test/widgetsSpec.js @@ -487,7 +487,7 @@ describe("widget", function() { })); it('should be possible to nest ng:view in ng:include', inject(function() { - var injector = createInjector(angularService); + var injector = angular.injector('NG'); var myApp = injector('$rootScope'); var $browser = myApp.$service('$browser'); $browser.xhr.expectGET('includePartial.html').respond('view: <ng:view></ng:view>'); |
