A framework to define all the dependencies in One place, flexible to Hook functions and mock for Unit Tests.
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
tests
.gitignore
LICENSE
README.md
dependable.js
gulpfile.js
index.js
package.json

README.md

SummonJS

Define Node.js module dependencies in JSON format, and be able to resolve them using angular inject style. There is a tutorial introducing how to use SummonJS to create an Express App.

npm install summonjs

Define Dependency

Create a JSON file, define the mappings between dependency name and the source files.

"dependency": {
    "ClassA": "./src/class_a",
    "ClassB": "./src/class_b",
    "_": {
        path: "lodash",
        shim: true
    }
}

Init the dependency manager

Pass in the dependency definition JSON file to the summonjs module, it will make all the dependencies defined available via summonjs:

var summon = require('summonjs')({
    configs: require('./simple.json')
});

Auto inject dependencies by argument names

Take below function from ./src/class_a for example, ClassB is a function argument, and it maps to the source file ./src/class_b. When ClassA is loaded from SummonJS, the ClassB will be injected automatically, available to the scope of ClassA.

./src/class_a:

module.exports = function(ClassB) {
	this.name = "class_a";
	this.classB = ClassB;
	return this;
};

./src/class_b:

module.exports = function() {
	this.name = "class_b";
	return this;
};

shim the dependency without auto inject

If you don't want summon to auto inject dependencies, and want it to be initialized by a simple require operation, you can define the dependency to be shimmed:

"_": {
    path: "lodash",
    shim: true
}

Internally it wrap the dependency with an anonymous function with empty argument list, and to be registered in the dependency manager:

function() {
    return require('lodash');
}

Register dependency in code

It can either register object or function.

var obj = {};
summon.register('Class', {});

var func = function(){
    return 'test';
};
summon.register('Func', func);

If it is a function, when it loads by summon the first time, it will execute the function and store the returned object in the summon's factory. So for next time it loads, the registered function won't be executed again. Instead it returns the object returned at the first time load.

Summon spirits by their names

var classA = summon.get('ClassA');
assert.equal(classA.name, 'class_a');
assert.equal(classA.classB.name, 'class_b');

Invoke targeted modules

summon.invoke will call on the targeted modules. Internally it is call get on all the specified targets, while override the dependencies if the override param is defined.

summon.invoke({
    override: {ClassB: {}},
    targets: ['ClassA', 'ClassC']
})

Hook Dependency Functions

In some scenarios, there might be needs to add integrate intercept logics for a object's function, such as manipulate input arguments before passing them to an existing function, or adding data caching logics in the function. SummonJS has a way to create a pre/post logic hook for a dependency's function, making it easier to plug in or plug out the custom logics to a function.

The SummonJS definition below define a dependency with a hook object.

{
	"dependency": {
		"ClassB": {
            "path" : "./src/class_b",
            "hook" : {
                "main" : "./src/hook"
            }
        }
	}
}

The main key value under the hook property is the function needed to be hooked with the pre/post logics defined in the ./src/hook file. The hook object needs to have pre/post functions such as below:

module.exports = function(ClassA) {
	this.pre = function(arg, next) {
        next(arg + ' passed to pre hook;');
    };
    this.post = function(arg, next) {
        next(arg + ' passed to post hook;');
    };
	return this;
};

With the ClassB source code as below:

var classb = function() {
	return this;
};
classb.prototype.main = function(arg, callback) {
	callback(arg + ' passed to main func;');
};
module.exports = classb;

Note that in order for a function to be hooked, it has be defined as a prototype function.

The callback result of the main will be as below:

var mainCallback = function(arg1) {
    assert.equal(arg1, 'test passed to pre hook; passed to main func; passed to post hook;');
};
summon.get('ClassB').main('test', mainCallback);

Here is how the hook works:

  1. pre hook function will be called first when the main function is called.
  2. next function in the pre hook will call the ClassB.main with the arguments.
  3. The callback argument in the main function will call the post hook function with the arguments.
  4. The original mainCallback will be postponed to be the next callback function in the post hook.
  5. Assume if ClassA is defined in the dependency config json, it can be injected into the hook scope function and to be used by the pre/post hook functions.

Welcome Contributions

Feel free to fork and add features suit your needs.

Development Test

Run gulp, it should run all the unit tests and generate a coverage report.