@spalger/kibana
Version:
Kibana is an open source (Apache Licensed), browser based analytics and search dashboard for Elasticsearch. Kibana is a snap to setup and start using. Kibana strives to be easy to get started with, while also being flexible and powerful, just like Elastic
192 lines (166 loc) • 5.74 kB
JavaScript
define(function (require) {
/**
* # `Private()`
* Private module loader, used to merge angular and require js dependency styles
* by allowing a require.js module to export a single provider function that will
* create a value used within an angular application. This provider can declare
* angular dependencies by listing them as arguments, and can be require additional
* Private modules.
*
* ## Define a private module provider:
* ```js
* define(function (require) {
* return function PingProvider($http) {
* this.ping = function () {
* return $http.head('/health-check');
* };
* };
* });
* ```
*
* ## Require a private module:
* ```js
* define(function (require) {
* return function ServerHealthProvider(Private, Promise) {
* var ping = Private(require('ui/ping'));
* return {
* check: Promise.method(function () {
* var attempts = 0;
* return (function attempt() {
* attempts += 1;
* return ping.ping()
* .catch(function (err) {
* if (attempts < 3) return attempt();
* })
* }())
* .then(function () {
* return true;
* })
* .catch(function () {
* return false;
* });
* })
* }
* };
* });
* ```
*
* # `Private.stub(provider, newInstance)`
* `Private.stub()` replaces the instance of a module with another value. This is all we have needed until now.
*
* ```js
* beforeEach(inject(function ($injector, Private) {
* Private.stub(
* // since this module just exports a function, we need to change
* // what Private returns in order to modify it's behavior
* require('ui/agg_response/hierarchical/_build_split'),
* sinon.stub().returns(fakeSplit)
* );
* }));
* ```
*
* # `Private.swap(oldProvider, newProvider)`
* This new method does an 1-for-1 swap of module providers, unlike `stub()` which replaces a modules instance.
* Pass the module you want to swap out, and the one it should be replaced with, then profit.
*
* Note: even though this example shows `swap()` being called in a config
* function, it can be called from anywhere. It is particularly useful
* in this scenario though.
*
* ```js
* beforeEach(module('kibana', function (PrivateProvider) {
* PrivateProvider.swap(
* // since the courier is required automatically before the tests are loaded,
* // we can't stub it's internal components unless we do so before the
* // application starts. This is why angular has config functions
* require('ui/courier/_redirect_when_missing'),
* function StubbedRedirectProvider($decorate) {
* // $decorate is a function that will instantiate the original module when called
* return sinon.spy($decorate());
* }
* );
* }));
* ```
*
* @param {[type]} prov [description]
*/
var _ = require('lodash');
var nextId = _.partial(_.uniqueId, 'privateProvider#');
function name(fn) {
return fn.name || fn.toString().split('\n').shift();
}
require('ui/modules').get('kibana')
.provider('Private', function () {
var provider = this;
// one cache/swaps per Provider
var cache = {};
var swaps = {};
// return the uniq id for this function
function identify(fn) {
if (typeof fn !== 'function') {
throw new TypeError('Expected private module "' + fn + '" to be a function');
}
if (fn.$$id) return fn.$$id;
else return (fn.$$id = nextId());
}
provider.stub = function (fn, instance) {
cache[identify(fn)] = instance;
return instance;
};
provider.swap = function (fn, prov) {
var id = identify(fn);
swaps[id] = prov;
};
provider.$get = ['$injector', function PrivateFactory($injector) {
// prevent circular deps by tracking where we came from
var privPath = [];
var pathToString = function () {
return privPath.map(name).join(' -> ');
};
// call a private provider and return the instance it creates
function instantiate(prov, locals) {
if (~privPath.indexOf(prov)) {
throw new Error(
'Circular refrence to "' + name(prov) + '"' +
' found while resolving private deps: ' + pathToString()
);
}
privPath.push(prov);
var context = {};
var instance = $injector.invoke(prov, context, locals);
if (!_.isObject(instance)) instance = context;
privPath.pop();
return instance;
}
// retrieve an instance from cache or create and store on
function get(id, prov, $delegateProv, $delegateId) {
if (cache[id]) return cache[id];
var instance;
if ($delegateId != null && $delegateProv != null) {
instance = instantiate(prov, {
$decorate: _.partial(get, $delegateId, $delegateProv)
});
} else {
instance = instantiate(prov);
}
return (cache[id] = instance);
}
// main api, get the appropriate instance for a provider
function Private(prov) {
var id = identify(prov);
var $delegateId;
var $delegateProv;
if (swaps[id]) {
$delegateId = id;
$delegateProv = prov;
prov = swaps[$delegateId];
id = identify(prov);
}
return get(id, prov, $delegateId, $delegateProv);
}
Private.stub = provider.stub;
Private.swap = provider.swap;
return Private;
}];
});
});