Skip to content

Instantly share code, notes, and snippets.

@ctrlplusb
Last active February 24, 2016 11:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ctrlplusb/59147d8e3be981a0cd4b to your computer and use it in GitHub Desktop.
Save ctrlplusb/59147d8e3be981a0cd4b to your computer and use it in GitHub Desktop.
NodeJS simple dependency management for modules.
// This gist illustrates a very simple strategy of declaring and exposing
// dependencies for your modules. Allowing them to be overridden for
// tests (or other), and providing a mechanism to restore the original
// dependencies.
// It's a work in progress, is very simple and naive, but its a simple
// mechanism to achieve required results without having to depend on
// any complex DI frameworks.
// Our custom and simple IOC util.
import { createIOC } from '_system/utils';
// Dependencies for foo-module.
import bob from './bob-dependency';
// Create an IOC container for the dependencies we wish to expose to tests
// or whatever else that cares about them.
// NOTE: Consider not exposing any dependencies that needn't be overridden.
const ioc = createIOC({ bob });
/**
* Our masterful foo function!
* @return {string} A surprising result!
*/
function foo() {
return ioc.bob(); // resolve deps via IOC.
}
// We export both our ioc container and foo...
export { ioc };
export default foo;
/**
* This is a very simple dependency.
*/
function bob() {
return 'real bob';
}
export default bob;
import { expect } from 'chai';
describe('Given a DI configuration', () => {
const { default: subject, ioc } = require('./foo-module.js');
describe('When executing the default', () => {
it('Should return the native result', () => {
const expected = 'real bob';
const actual = subject();
expect(actual).to.equal(expected);
});
});
describe('When doing dependency injection', () => {
before(() => {
ioc._inject({
bob: () => 'injected bob'
});
});
it('It should return the injected result after an injection', () => {
const expected = 'injected bob';
const actual = subject();
expect(actual).to.equal(expected);
});
it('Should return the native result after a restore', () => {
ioc._restore();
const expected = 'real bob';
const actual = subject();
expect(actual).to.equal(expected);
});
});
});
import debug from 'debug';
const warn = debug(`_system:utils:createIOC:warn`);
/**
* Create a basic IOC container, which allows for dependencies to be injected
* after initial registration (useful for testing) and restored back to their
* original dependencies.
*
* @example
* import { createIOC } from '_system/utils';
* import bobDependency from './bobDendency';
*
* const ioc = createIOC({ bobDendency });
*
* ioc.bobDendency; // returns original dependency.
*
* ioc._inject({ bobDendency: function mock() {} });
*
* ioc.bobDendency; // returns function mock() {}
*
* ioc._restore();
*
* ioc.bobDendency; // returns original dependency.
*
* @param deps
* The dependencies for the container.
*
* @return The IOC container object.
*/
function createIOC(deps: Object) {
const container = { ...deps };
let _original = {};
let _injected = [];
/**
* Allows you to inject custom dependencies, overriding any default
* dependencies.
*
* @param inj
* The dependencies to inject.
*/
container._inject = function _inject(inj: Object) {
Object.keys(inj).forEach(x => {
if (!container[x]) {
warn(`No dependency by the name of "${x}" exists in the IOC container.`);
} else {
_original[x] = container[x];
}
const injectedDep = inj[x];
if (!injectedDep) {
warn(`You are injecting an undefined/null value for "${x}" dependency.`);
}
container[x] = injectedDep;
_injected.push(x);
});
};
/**
* Restores all the original dependencies for the container.
*/
container._restore = function _restore() {
_injected.forEach(x => {
if (_original[x]) {
container[x] = _original[x];
}
});
_original = {};
_injected = [];
};
return container;
}
export default createIOC;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment