Skip to content

Commit

Permalink
fix(injector): allow multiple loading of function modules
Browse files Browse the repository at this point in the history
move the loadedModules lookup to be performed only on strings in order to allow loading functions that look the same. this issue caused only the first `angular.mock.module(object)` invocation to work since the loadModules lookup blocked all following invocations.

closes angular#7254
  • Loading branch information
shahata authored and caitp committed Jun 8, 2014
1 parent 751ebc1 commit 3bd94d3
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 33 deletions.
56 changes: 32 additions & 24 deletions src/Angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
-ngMinErr,
-angularModule,
-nodeName_,
-uid,
-uids,
-lowercase,
-uppercase,
Expand Down Expand Up @@ -164,7 +164,10 @@ var /** holds major version number for IE or NaN for real browsers */
angular = window.angular || (window.angular = {}),
angularModule,
nodeName_,
uid = ['0', '0', '0'];
uids = {
uid: ['0', '0', '0'],
moduleUid: ['0', '0', '0']
};

/**
* IE 11 changed the format of the UserAgent string.
Expand Down Expand Up @@ -281,6 +284,31 @@ function reverseParams(iteratorFn) {
return function(value, key) { iteratorFn(key, value); };
}

function genNextUid(name) {
return function() {
var uid = uids[name];
var index = uid.length;
var digit;

while(index) {
index--;
digit = uid[index].charCodeAt(0);
if (digit == 57 /*'9'*/) {
uid[index] = 'A';
return uid.join('');
}
if (digit == 90 /*'Z'*/) {
uid[index] = '0';
} else {
uid[index] = String.fromCharCode(digit + 1);
return uid.join('');
}
}
uid.unshift('0');
return uid.join('');
};
}

/**
* A consistent way of creating unique IDs in angular. The ID is a sequence of alpha numeric
* characters such as '012ABC'. The reason why we are not using simply a number counter is that
Expand All @@ -289,28 +317,8 @@ function reverseParams(iteratorFn) {
*
* @returns {string} an unique alpha-numeric string
*/
function nextUid() {
var index = uid.length;
var digit;

while(index) {
index--;
digit = uid[index].charCodeAt(0);
if (digit == 57 /*'9'*/) {
uid[index] = 'A';
return uid.join('');
}
if (digit == 90 /*'Z'*/) {
uid[index] = '0';
} else {
uid[index] = String.fromCharCode(digit + 1);
return uid.join('');
}
}
uid.unshift('0');
return uid.join('');
}

var nextUid = genNextUid('uid');
var nextModuleUid = genNextUid('moduleUid');

/**
* Set or clear the hashkey for an object.
Expand Down
17 changes: 10 additions & 7 deletions src/apis.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,18 @@
* @returns {string} hash string such that the same input will have the same hash string.
* The resulting string key is in 'type:hashKey' format.
*/
function hashKey(obj) {
function hashKey(obj, uidFn) {
var objType = typeof obj,
key;

if (objType == 'object' && obj !== null) {
uidFn = uidFn || nextUid;

if (objType === 'function' || (objType == 'object' && obj !== null)) {
if (typeof (key = obj.$$hashKey) == 'function') {
// must invoke on object to keep the right this
key = obj.$$hashKey();
} else if (key === undefined) {
key = obj.$$hashKey = nextUid();
key = obj.$$hashKey = uidFn();
}
} else {
key = obj;
Expand All @@ -34,7 +36,8 @@ function hashKey(obj) {
/**
* HashMap which can use objects as keys
*/
function HashMap(array){
function HashMap(array, uidFn){
this.uidFn = uidFn || nextUid;
forEach(array, this.put, this);
}
HashMap.prototype = {
Expand All @@ -44,23 +47,23 @@ HashMap.prototype = {
* @param value value to store can be any type
*/
put: function(key, value) {
this[hashKey(key)] = value;
this[hashKey(key, this.uidFn)] = value;
},

/**
* @param key
* @returns {Object} the value for the key
*/
get: function(key) {
return this[hashKey(key)];
return this[hashKey(key, this.uidFn)];
},

/**
* Remove the key/value pair
* @param key
*/
remove: function(key) {
var value = this[key = hashKey(key)];
var value = this[key = hashKey(key, this.uidFn)];
delete this[key];
return value;
}
Expand Down
2 changes: 1 addition & 1 deletion src/auto/injector.js
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ function createInjector(modulesToLoad, strictDi) {
var INSTANTIATING = {},
providerSuffix = 'Provider',
path = [],
loadedModules = new HashMap(),
loadedModules = new HashMap(null, nextModuleUid),
providerCache = {
$provide: {
provider: supportObject(provider),
Expand Down
9 changes: 9 additions & 0 deletions src/ngMock/angular-mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -2168,6 +2168,15 @@ if(window.jasmine || window.mocha) {
});
}
injector = currentSpec.$injector = angular.injector(modules, strictDi);
var afterFn = typeof this.after === 'function' ? angular.bind(this, this.after) :
typeof window.after === 'function' ? window.after : angular.noop;
afterFn(function() {
angular.forEach(modules, function(module) {
if (typeof module === 'function' || (module && typeof module === 'object')) {
delete module.$$hashKey;
}
});
});
currentSpec.$injectorStrict = strictDi;
}
for(var i = 0, ii = blockFns.length; i < ii; i++) {
Expand Down
11 changes: 11 additions & 0 deletions test/auto/injectorSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,17 @@ describe('injector', function() {
expect(log).toEqual('abc');
});

it('should not load dependent functions only once', function() {
function generateValueModule(name, value) {
return function ($provide) {
$provide.value(name, value);
};
}
var injector = createInjector([generateValueModule('name1', 'value1'),
generateValueModule('name2', 'value2')]);
expect(injector.get('name2')).toBe('value2');
});

it('should execute runBlocks after injector creation', function() {
var log = '';
angular.module('a', [], function(){ log += 'a'; }).run(function() { log += 'A'; });
Expand Down
3 changes: 2 additions & 1 deletion test/helpers/testabilityPatch.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ beforeEach(function() {
}

// This resets global id counter;
uid = ['0', '0', '0'];
uids.uid = ['0', '0', '0'];
uids.moduleUid = ['0', '0', '0'];

// reset to jQuery or default to us.
bindJQuery();
Expand Down

0 comments on commit 3bd94d3

Please sign in to comment.