feat(injector): add $provide.decorator

This commit is contained in:
Igor Minar 2011-12-02 19:38:39 -05:00
parent 5e4d59adf0
commit 4e3c05b99e
2 changed files with 155 additions and 1 deletions

View file

@ -251,7 +251,8 @@ function createInjector(modulesToLoad, moduleRegistry) {
value('$provide', {
service: service,
factory: factory,
value: value
value: value,
decorator: decorator
});
loadModule(modulesToLoad);
@ -274,6 +275,18 @@ function createInjector(modulesToLoad, moduleRegistry) {
function value(name, value) { factory(name, valueFn(value)); }
function decorator(name, decorFn) {
var origProvider = cache['#' + name + providerSuffix];
if (!origProvider) throw Error("Can't find provider for: " + name);
if (cache['#' + name]) throw Error("Service " + name + " already instantiated, can't decorate!");
var orig$get = origProvider.$get;
origProvider.$get = function() {
var origInstance = $injector.invoke(origProvider, orig$get);
return $injector.invoke(null, decorFn, {$delegate: origInstance});
};
}
function getService(value) {
if (typeof value !== 'string') {
throw Error('Service name expected');

View file

@ -280,6 +280,147 @@ describe('injector', function() {
}]).get('value')).toEqual('abc');
});
});
describe('decorator', function() {
var log, injector;
beforeEach(function() {
log = [];
});
it('should be called with the original instance', function() {
injector = createInjector([function($provide) {
$provide.value('myService', function(val) {
log.push('myService:' + val);
return 'origReturn';
});
$provide.decorator('myService', function($delegate) {
return function(val) {
log.push('myDecoratedService:' + val);
var origVal = $delegate('decInput');
return 'dec+' + origVal;
};
});
}]);
var out = injector.get('myService')('input');
log.push(out);
expect(log.join('; ')).
toBe('myDecoratedService:input; myService:decInput; dec+origReturn');
});
it('should allow multiple decorators to be applied to a service', function() {
injector = createInjector([function($provide) {
$provide.value('myService', function(val) {
log.push('myService:' + val);
return 'origReturn';
});
$provide.decorator('myService', function($delegate) {
return function(val) {
log.push('myDecoratedService1:' + val);
var origVal = $delegate('decInput1');
return 'dec1+' + origVal;
};
});
$provide.decorator('myService', function($delegate) {
return function(val) {
log.push('myDecoratedService2:' + val);
var origVal = $delegate('decInput2');
return 'dec2+' + origVal;
};
});
}]);
var out = injector.get('myService')('input');
log.push(out);
expect(log).toEqual(['myDecoratedService2:input',
'myDecoratedService1:decInput2',
'myService:decInput1',
'dec2+dec1+origReturn']);
});
it('should decorate services with dependencies', function() {
injector = createInjector([function($provide) {
$provide.value('dep1', 'dependency1');
$provide.factory('myService', ['dep1', function(dep1) {
return function(val) {
log.push('myService:' + val + ',' + dep1);
return 'origReturn';
}
}]);
$provide.decorator('myService', function($delegate) {
return function(val) {
log.push('myDecoratedService:' + val);
var origVal = $delegate('decInput');
return 'dec+' + origVal;
};
});
}]);
var out = injector.get('myService')('input');
log.push(out);
expect(log.join('; ')).
toBe('myDecoratedService:input; myService:decInput,dependency1; dec+origReturn');
});
it('should allow for decorators to be injectable', function() {
injector = createInjector([function($provide) {
$provide.value('dep1', 'dependency1');
$provide.factory('myService', function() {
return function(val) {
log.push('myService:' + val);
return 'origReturn';
}
});
$provide.decorator('myService', function($delegate, dep1) {
return function(val) {
log.push('myDecoratedService:' + val + ',' + dep1);
var origVal = $delegate('decInput');
return 'dec+' + origVal;
};
});
}]);
var out = injector.get('myService')('input');
log.push(out);
expect(log.join('; ')).
toBe('myDecoratedService:input,dependency1; myService:decInput; dec+origReturn');
});
it('should complain if the service to be decorated was already instantiated', function() {
injector = createInjector([function($provide, $injector) {
$provide.value('myService', function(val) {
log.push('myService:' + val);
return 'origReturn';
});
$injector.get('myService');
expect(function() {
$provide.decorator('myService', function($delegate) {
return function(val) {
log.push('myDecoratedService:' + val);
var origVal = $delegate('decInput');
return 'dec+' + origVal;
};
});
}).toThrow("Service myService already instantiated, can't decorate!");
}]);
});
});
});