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>'); | 
