Remove aux test
This commit is contained in:
parent
bd2bf60467
commit
ac656b51e8
|
@ -0,0 +1,11 @@
|
||||||
|
.DS_Store
|
||||||
|
*.seed
|
||||||
|
*.log
|
||||||
|
*.csv
|
||||||
|
*.dat
|
||||||
|
*.out
|
||||||
|
*.pid
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
node_modules/
|
||||||
|
.idea
|
|
@ -0,0 +1,246 @@
|
||||||
|
# sl-module-loader
|
||||||
|
v0.0.1
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
The `sl-module-loader` allows your program to register classes (or types) that are instantiated via configuration files. Configuration files point to an implementation `module` constructor. The `module`'s job is to construct a useful instance with the given configuration options. This allows programs to be free from bootstrapping code and manageable via config.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
slnode install sl-module-loader
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
Given a simple `Dog` module:
|
||||||
|
|
||||||
|
function Dog(options) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
Dog.prototype.speak = function() {
|
||||||
|
console.log('roof', 'my name is', this.options.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Dog;
|
||||||
|
|
||||||
|
And a set of `config.json` files:
|
||||||
|
|
||||||
|
/my-app
|
||||||
|
/fido
|
||||||
|
config.json
|
||||||
|
/santas-little-helper
|
||||||
|
config.json
|
||||||
|
/rex
|
||||||
|
config.json
|
||||||
|
/node_modules
|
||||||
|
/dog
|
||||||
|
index.js
|
||||||
|
package.json
|
||||||
|
|
||||||
|
Where a `config.json` looks like this:
|
||||||
|
|
||||||
|
{
|
||||||
|
"module": "dog", // the "dog" module
|
||||||
|
"options": {
|
||||||
|
"name": "fido"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
We can load up all the dogs like so (app.js):
|
||||||
|
|
||||||
|
var moduleLoader = require('sl-module-loader').create('my-app');
|
||||||
|
|
||||||
|
moduleLoader.load(function (err, modules) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
moduleLoader
|
||||||
|
.instanceOf('dog') // a module in node_modules or declared as a dependency in package.json
|
||||||
|
.forEach(function (m) {
|
||||||
|
m.speak();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
The above calls a method on all module instances that inherit from `Dog` and outputs:
|
||||||
|
|
||||||
|
roof my name is fido
|
||||||
|
roof my name is santa's little helper
|
||||||
|
roof my name is rex
|
||||||
|
|
||||||
|
## Creating Module Classes
|
||||||
|
|
||||||
|
The purpose of a module class is to take meaningful input (configuration, options, dependencies) and create a useful output: a module instance.
|
||||||
|
|
||||||
|
### Module Classes
|
||||||
|
|
||||||
|
A module class is a `node_module` that exports a constructor inheriting from the `Module` class.
|
||||||
|
|
||||||
|
var inherits = require('util').inherits;
|
||||||
|
var Module = require('sl-module-loader').Module;
|
||||||
|
|
||||||
|
module.exports = Dog;
|
||||||
|
|
||||||
|
function Dog(options) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(Dog, Module);
|
||||||
|
|
||||||
|
Dog.prototype.speak = function() {
|
||||||
|
console.log('roof', 'my name is', this.options.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Module classes may define dependency contracts that tell the module loader to provide dependencies of a given module class during construction.
|
||||||
|
|
||||||
|
function MyComplexModule() {
|
||||||
|
Module.apply(this, arguments);
|
||||||
|
console.log('loaded dependencies', this.dependencies); // {'my-dependency': <module instance>}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyComplexModule.dependencies = {
|
||||||
|
'my-dependency': 'another-module-class'
|
||||||
|
}
|
||||||
|
|
||||||
|
#### Module Class Options
|
||||||
|
|
||||||
|
Module classes may also describe the options they accept. This will validate the configuration of module instance and guarantee the module class constructor has enough information to construct an instance.
|
||||||
|
|
||||||
|
Here is an example options description for a database connection module class.
|
||||||
|
|
||||||
|
DatabaseConnection.options = {
|
||||||
|
'hostname': {type: 'string', required: true},
|
||||||
|
'port': {type: 'number', min: 10, max: 99999},
|
||||||
|
'username': {type: 'string'},
|
||||||
|
'password': {type: 'string'}
|
||||||
|
};
|
||||||
|
|
||||||
|
**key** the option name given in `config.json`.
|
||||||
|
|
||||||
|
**type** must be one of:
|
||||||
|
|
||||||
|
- string
|
||||||
|
- boolean
|
||||||
|
- number
|
||||||
|
- array
|
||||||
|
|
||||||
|
**min/max** depend on the option type
|
||||||
|
|
||||||
|
{
|
||||||
|
min: 10, // minimum length or value
|
||||||
|
max: 100, // max length or value
|
||||||
|
}
|
||||||
|
|
||||||
|
#### Module Events
|
||||||
|
|
||||||
|
Module classes may also emit and listen to events. By default a Module will emit the following events:
|
||||||
|
|
||||||
|
**destroy**
|
||||||
|
|
||||||
|
Emitted when a module instance is being destroyed during a `moduleLoader.reset()`. Modules should cleanup any connections and unbind all event listeners.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
Each module instance is defined by creating a `config.json` file in a directory with the module's name.
|
||||||
|
|
||||||
|
/my-module-instance
|
||||||
|
config.json
|
||||||
|
other-files.txt
|
||||||
|
index.js
|
||||||
|
|
||||||
|
This directory should contain files related to the module instance. For example it might contain a script that `require()`s the module instance.
|
||||||
|
|
||||||
|
#### config.module
|
||||||
|
|
||||||
|
The node module name that exports the module class that constructs the config's module instance.
|
||||||
|
|
||||||
|
{
|
||||||
|
"module": "my-module-class"
|
||||||
|
}
|
||||||
|
|
||||||
|
#### config.options
|
||||||
|
|
||||||
|
Defines arbitrary options. A `file-upload` module might have an `uploads` option.
|
||||||
|
|
||||||
|
{
|
||||||
|
"module": "file-upload",
|
||||||
|
"options": {
|
||||||
|
"uploads": "/tmp"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#### config.dependencies
|
||||||
|
|
||||||
|
Defines other module instances the configured instance depends on.
|
||||||
|
|
||||||
|
{
|
||||||
|
"module": "collection"
|
||||||
|
"dependencies": {
|
||||||
|
"db": "my-db-module"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"collection-name": "my-collection"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Where `my-db-module`'s config looks like this:
|
||||||
|
|
||||||
|
{
|
||||||
|
"module": "couchdb-connector",
|
||||||
|
"options": {
|
||||||
|
"database": "my-db"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#### config.env.json
|
||||||
|
|
||||||
|
Separate file that overrides `config.json` depending on the current `NODE_ENV`. Useful for including config information that is environment specific or should not be committed to source control.
|
||||||
|
|
||||||
|
{
|
||||||
|
// overrides for all envs
|
||||||
|
"*": {
|
||||||
|
"options": {
|
||||||
|
"upload-dir": "/uploads"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dev": {
|
||||||
|
"options": {
|
||||||
|
"upload-dir": "/dev-uploads"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
## Requiring Modules
|
||||||
|
|
||||||
|
To use module instances, you can `require()` them anywhere in your program like you normally would require a node module. For example, you can get a reference to the `fido` object like this:
|
||||||
|
|
||||||
|
var fido = require('fido'); // `fido` is the directory name containing the fido module config
|
||||||
|
|
||||||
|
### Require Behavior
|
||||||
|
|
||||||
|
After your program runs `require('sl-module-loader')` the `require()` function's behavior will change slightly to make referencing module instances simpler. Since some module instances may not have any program specific code, they can't be `require()`d with `node`'s existing require() implementation.
|
||||||
|
|
||||||
|
## Config Loader
|
||||||
|
|
||||||
|
`sl-module-loader` inherits from [sl-config-loader](https://github.com/strongloop/sl-config-loader).
|
||||||
|
|
||||||
|
|
||||||
|
## Bundled Modules / Aliasing
|
||||||
|
|
||||||
|
Some modules need to be distributed together. For example, you have a set of related modules that all live under a single version number since they depend on features from each other. In this case you should bundle your sub modules using the package.json `bundledDependencies` array.
|
||||||
|
|
||||||
|
Reference bundled modules by relative location (just like require).
|
||||||
|
|
||||||
|
// config.json
|
||||||
|
{
|
||||||
|
"module": "myBundle/node_modules/foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
You may also provide aliases to any module path when creating a `ModuleLoader`.
|
||||||
|
|
||||||
|
var moduleLoader = require('sl-module-loader').create('my-app', {alias: {'foo': 'myBundle/node_modules/foo'}});
|
||||||
|
|
||||||
|
Now the config can reference `foo` instead of the qualified path.
|
||||||
|
|
||||||
|
// config.json
|
||||||
|
{
|
||||||
|
"module": "foo"
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
/**
|
||||||
|
* Main application
|
||||||
|
*/
|
||||||
|
|
||||||
|
var express = require('express')
|
||||||
|
, http = require('http')
|
||||||
|
, path = require('path');
|
||||||
|
|
||||||
|
var app = express();
|
||||||
|
|
||||||
|
var ModuleLoader = require('../../');
|
||||||
|
|
||||||
|
var ml = ModuleLoader.create('.', {ttl: 0, ignore: ['node_modules']});
|
||||||
|
|
||||||
|
var options = {};
|
||||||
|
|
||||||
|
app.set('port', process.env.PORT || 3000);
|
||||||
|
|
||||||
|
app.use(function (req, res, next) {
|
||||||
|
ml.load(function (err, config) {
|
||||||
|
if(err) {
|
||||||
|
throw err;
|
||||||
|
} else {
|
||||||
|
// simple routing
|
||||||
|
var module = ml.getByName(req.url.replace('/', ''));
|
||||||
|
|
||||||
|
if(module) {
|
||||||
|
module.handle(req, res, next);
|
||||||
|
} else {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(app.router);
|
||||||
|
|
||||||
|
http.createServer(app).listen(app.get('port'), function(){
|
||||||
|
console.log("express-app listening on port " + app.get('port'));
|
||||||
|
});
|
||||||
|
|
7
node_modules/sl-module-loader/example/express-app/models/user/config.env.json
generated
vendored
Normal file
7
node_modules/sl-module-loader/example/express-app/models/user/config.env.json
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"prod": {
|
||||||
|
"dependencies": {
|
||||||
|
"store": "mongo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
node_modules/sl-module-loader/example/express-app/models/user/config.json
generated
vendored
Normal file
9
node_modules/sl-module-loader/example/express-app/models/user/config.json
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
{
|
||||||
|
"module": "data-model",
|
||||||
|
"options": {
|
||||||
|
"collection": "users"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"store": "memory"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"name": "express-app",
|
||||||
|
"description": "express-app",
|
||||||
|
"private": true,
|
||||||
|
"version": "1.0.0",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node app"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "latest",
|
||||||
|
"ejs": "latest",
|
||||||
|
"mongodb": "~1.2.14"
|
||||||
|
}
|
||||||
|
}
|
6
node_modules/sl-module-loader/example/express-app/routes/bar/config.json
generated
vendored
Normal file
6
node_modules/sl-module-loader/example/express-app/routes/bar/config.json
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"module": "responder",
|
||||||
|
"options": {
|
||||||
|
"msg": "this is bar"
|
||||||
|
}
|
||||||
|
}
|
12
node_modules/sl-module-loader/example/express-app/routes/foo/config.env.json
generated
vendored
Normal file
12
node_modules/sl-module-loader/example/express-app/routes/foo/config.env.json
generated
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"*": {
|
||||||
|
"options": {
|
||||||
|
"msg": "foo bar"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dev": {
|
||||||
|
"options": {
|
||||||
|
"msg": "foo bar dev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
6
node_modules/sl-module-loader/example/express-app/routes/foo/config.json
generated
vendored
Normal file
6
node_modules/sl-module-loader/example/express-app/routes/foo/config.json
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"module": "responder",
|
||||||
|
"options": {
|
||||||
|
"msg": "this is foo"
|
||||||
|
}
|
||||||
|
}
|
6
node_modules/sl-module-loader/example/express-app/routes/hello/config.json
generated
vendored
Normal file
6
node_modules/sl-module-loader/example/express-app/routes/hello/config.json
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"module": "responder",
|
||||||
|
"options": {
|
||||||
|
"msg": "hello"
|
||||||
|
}
|
||||||
|
}
|
6
node_modules/sl-module-loader/example/express-app/routes/users/config.json
generated
vendored
Normal file
6
node_modules/sl-module-loader/example/express-app/routes/users/config.json
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"module": "./users-route.js",
|
||||||
|
"dependencies": {
|
||||||
|
"user": "user"
|
||||||
|
}
|
||||||
|
}
|
27
node_modules/sl-module-loader/example/express-app/routes/users/users-route.js
generated
vendored
Normal file
27
node_modules/sl-module-loader/example/express-app/routes/users/users-route.js
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
var MODULE_LOADER = '../../../../';
|
||||||
|
var Module = require(MODULE_LOADER).Module;
|
||||||
|
var inherits = require('util').inherits;
|
||||||
|
|
||||||
|
module.exports = UsersRoute;
|
||||||
|
|
||||||
|
function UsersRoute(options) {
|
||||||
|
Module.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(UsersRoute, Module);
|
||||||
|
|
||||||
|
UsersRoute.prototype.handle = function (req, res, next) {
|
||||||
|
var user = this.dependencies.user;
|
||||||
|
|
||||||
|
user.getAll(function (err, users) {
|
||||||
|
if(err) {
|
||||||
|
next(err);
|
||||||
|
} else {
|
||||||
|
res.send(users);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
UsersRoute.dependencies = {
|
||||||
|
'user': 'data-model'
|
||||||
|
}
|
6
node_modules/sl-module-loader/example/express-app/stores/memory/config.json
generated
vendored
Normal file
6
node_modules/sl-module-loader/example/express-app/stores/memory/config.json
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"module": "memory-store",
|
||||||
|
"options": {
|
||||||
|
"database": "my-memory-db"
|
||||||
|
}
|
||||||
|
}
|
8
node_modules/sl-module-loader/example/express-app/stores/mongo/config.json
generated
vendored
Normal file
8
node_modules/sl-module-loader/example/express-app/stores/mongo/config.json
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"module": "mongo-store",
|
||||||
|
"options": {
|
||||||
|
"database": "sl-module-loader-testing-db",
|
||||||
|
"host": "127.0.0.1",
|
||||||
|
"port": "27017"
|
||||||
|
}
|
||||||
|
}
|
9
node_modules/sl-module-loader/example/module-script/another-module/another-module-class.js
generated
vendored
Normal file
9
node_modules/sl-module-loader/example/module-script/another-module/another-module-class.js
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
module.exports = AnotherModuleClass;
|
||||||
|
|
||||||
|
function AnotherModuleClass(options) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnotherModuleClass.prototype.foo = function () {
|
||||||
|
console.log('foo', this.options.msg);
|
||||||
|
}
|
7
node_modules/sl-module-loader/example/module-script/another-module/config.json
generated
vendored
Normal file
7
node_modules/sl-module-loader/example/module-script/another-module/config.json
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"module": "./another-module-class.js",
|
||||||
|
"options": {
|
||||||
|
"msg": "bar bat baz",
|
||||||
|
"name": "another-module"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
var ml = require('../../').create('.');
|
||||||
|
|
||||||
|
ml.load(function () {
|
||||||
|
console.log('module loaded...');
|
||||||
|
});
|
8
node_modules/sl-module-loader/example/module-script/my-module/config.json
generated
vendored
Normal file
8
node_modules/sl-module-loader/example/module-script/my-module/config.json
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"module": "./my-module-class.js",
|
||||||
|
"main": "main.js",
|
||||||
|
"options": {
|
||||||
|
"msg": "hello world",
|
||||||
|
"name": "my-module"
|
||||||
|
}
|
||||||
|
}
|
7
node_modules/sl-module-loader/example/module-script/my-module/main.js
generated
vendored
Normal file
7
node_modules/sl-module-loader/example/module-script/my-module/main.js
generated
vendored
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
var myModule = require('./');
|
||||||
|
|
||||||
|
myModule.hello(); // hello world (via config.json's options.msg)
|
||||||
|
|
||||||
|
var anotherModule = require('../another-module');
|
||||||
|
|
||||||
|
anotherModule.foo();
|
9
node_modules/sl-module-loader/example/module-script/my-module/my-module-class.js
generated
vendored
Normal file
9
node_modules/sl-module-loader/example/module-script/my-module/my-module-class.js
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
module.exports = MyModuleClass;
|
||||||
|
|
||||||
|
function MyModuleClass(options) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
MyModuleClass.prototype.hello = function () {
|
||||||
|
console.log(this.options.msg);
|
||||||
|
}
|
6
node_modules/sl-module-loader/example/sample-app/custom-scripts/config.json
generated
vendored
Normal file
6
node_modules/sl-module-loader/example/sample-app/custom-scripts/config.json
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"module": "module",
|
||||||
|
"scripts": {
|
||||||
|
"constructed": "construction.js"
|
||||||
|
}
|
||||||
|
}
|
9
node_modules/sl-module-loader/example/sample-app/custom-scripts/construction.js
generated
vendored
Normal file
9
node_modules/sl-module-loader/example/sample-app/custom-scripts/construction.js
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
/**
|
||||||
|
* not yet supported...
|
||||||
|
*/
|
||||||
|
|
||||||
|
var modules = require('modules');
|
||||||
|
var currentModule = modules(__dirname);
|
||||||
|
|
||||||
|
console.log('this script is executed after a module is constructed');
|
||||||
|
console.log('currentModule', currentModule);
|
6
node_modules/sl-module-loader/example/sample-app/default/config.json
generated
vendored
Normal file
6
node_modules/sl-module-loader/example/sample-app/default/config.json
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"module": "../my-module-type",
|
||||||
|
"options": {
|
||||||
|
"msg": "this module uses the default my-module-type"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
var ModuleLoader = require('../../');
|
||||||
|
var moduleLoader = ModuleLoader.create('.');
|
||||||
|
|
||||||
|
moduleLoader.load(function (err, modules) {
|
||||||
|
if(err) throw err;
|
||||||
|
|
||||||
|
console.log('loaded modules...');
|
||||||
|
|
||||||
|
moduleLoader.instanceOf('MyModuleType').forEach(function (m) {
|
||||||
|
m.speak();
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"module": "./hello.js",
|
||||||
|
"options": {
|
||||||
|
"msg": "world"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
var MyModuleType = require('../my-module-type');
|
||||||
|
var util = require('util');
|
||||||
|
|
||||||
|
module.exports = HelloModule;
|
||||||
|
|
||||||
|
function HelloModule(options) {
|
||||||
|
MyModuleType.call(this, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(HelloModule, MyModuleType);
|
||||||
|
|
||||||
|
HelloModule.prototype.speak = function () {
|
||||||
|
console.log('from hello module', this.options);
|
||||||
|
}
|
6
node_modules/sl-module-loader/example/sample-app/inter-deps/config.json
generated
vendored
Normal file
6
node_modules/sl-module-loader/example/sample-app/inter-deps/config.json
generated
vendored
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"module": "./my-module",
|
||||||
|
"dependencies": {
|
||||||
|
"custom-dep": "hello"
|
||||||
|
}
|
||||||
|
}
|
18
node_modules/sl-module-loader/example/sample-app/inter-deps/my-module.js
generated
vendored
Normal file
18
node_modules/sl-module-loader/example/sample-app/inter-deps/my-module.js
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
var Module = require('../../../').Module;
|
||||||
|
var inherits = require('util').inherits;
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = MyModule;
|
||||||
|
|
||||||
|
function MyModule(options) {
|
||||||
|
Module.apply(this, arguments);
|
||||||
|
|
||||||
|
console.log('the "inter-deps" module loads a dependency', this.dependencies['custom-dep']);
|
||||||
|
}
|
||||||
|
|
||||||
|
MyModule.dependencies = {
|
||||||
|
// the dep name and path to a module that exports its supported type
|
||||||
|
'custom-dep': '../my-module-type'
|
||||||
|
};
|
||||||
|
|
||||||
|
inherits(MyModule, Module);
|
|
@ -0,0 +1,9 @@
|
||||||
|
module.exports = MyModuleType;
|
||||||
|
|
||||||
|
function MyModuleType(options) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
MyModuleType.prototype.speak = function () {
|
||||||
|
console.log(this.options.msg || 'no message provided...');
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
/**
|
||||||
|
* sl-module-loader ~ public api
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = require('./lib/module-loader');
|
||||||
|
module.exports.Module = require('./lib/module');
|
|
@ -0,0 +1,283 @@
|
||||||
|
/**
|
||||||
|
* Expose `ModuleLoader`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = ModuleLoader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var ConfigLoader = require('sl-config-loader')
|
||||||
|
, PatchedModule = require('./patched-module')
|
||||||
|
, fs = require('fs')
|
||||||
|
, path = require('path')
|
||||||
|
, debug = require('debug')('sl-module-loader')
|
||||||
|
, util = require('util')
|
||||||
|
, inherits = util.inherits
|
||||||
|
, assert = require('assert');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new `ModuleLoader` with the given `options`.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {ModuleLoader}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function ModuleLoader(options) {
|
||||||
|
ConfigLoader.apply(this, arguments);
|
||||||
|
|
||||||
|
this.types = {};
|
||||||
|
this._modules = {};
|
||||||
|
|
||||||
|
// throw an error if args are not supplied
|
||||||
|
// assert(typeof options === 'object', 'ModuleLoader requires an options object');
|
||||||
|
|
||||||
|
this.options = options;
|
||||||
|
|
||||||
|
debug('created with options', options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inherit from `ConfigLoader`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
inherits(ModuleLoader, ConfigLoader);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simplified APIs
|
||||||
|
*/
|
||||||
|
|
||||||
|
ModuleLoader.create =
|
||||||
|
ModuleLoader.createModuleLoader = function (root, options) {
|
||||||
|
options = options || {};
|
||||||
|
options.root = root;
|
||||||
|
return new ModuleLoader(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load the configuration and build modules.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ModuleLoader.prototype.load = function (fn) {
|
||||||
|
if(this.remaining()) {
|
||||||
|
// wait until the current operation is finished
|
||||||
|
this.once('done', function () {
|
||||||
|
fn(null, this._files);
|
||||||
|
});
|
||||||
|
// callback with an error if it occurs
|
||||||
|
this.once('error', fn);
|
||||||
|
} else if(this.ttl() > 0) {
|
||||||
|
fn(null, this._modules);
|
||||||
|
} else {
|
||||||
|
this.reset();
|
||||||
|
|
||||||
|
this.once('error', fn);
|
||||||
|
|
||||||
|
this.bindListeners();
|
||||||
|
|
||||||
|
// load config files
|
||||||
|
this.task(fs, 'readdir', this.root);
|
||||||
|
this.once('done', function () {
|
||||||
|
this._mergeEnvConfigs();
|
||||||
|
// create instances from config
|
||||||
|
this._constructModules(this._files);
|
||||||
|
fn(null, this._modules);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load an sl module type from the given module name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ModuleLoader.prototype.loadType = function (name) {
|
||||||
|
// get alias if it exists
|
||||||
|
var alias = (this.options.alias && this.options.alias[name]) || name;
|
||||||
|
|
||||||
|
assert(alias, 'you must provide a name or alias when loading a type');
|
||||||
|
|
||||||
|
// use the root as the base dir for loading
|
||||||
|
var paths = PatchedModule.resolveLookupPaths(this.root)[1];
|
||||||
|
|
||||||
|
// add in node module paths
|
||||||
|
paths = PatchedModule.nodeModulePaths(this.root).concat(paths);
|
||||||
|
|
||||||
|
var Type = PatchedModule.load(PatchedModule.resolveFilename(alias, {paths: paths}));
|
||||||
|
|
||||||
|
// patch the module with a moduleName for reference
|
||||||
|
Type.moduleName = name;
|
||||||
|
|
||||||
|
return Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset the loaded modules and cache.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ModuleLoader.prototype.reset = function () {
|
||||||
|
// clear require cache
|
||||||
|
clearObject(require.cache);
|
||||||
|
|
||||||
|
// clear module cache
|
||||||
|
clearObject(this._modules, function (module) {
|
||||||
|
if(typeof module.destroy === 'function') {
|
||||||
|
module.destroy();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// clear type cache
|
||||||
|
clearObject(this.types);
|
||||||
|
|
||||||
|
ConfigLoader.prototype.reset.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build modules from a list of config files.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ModuleLoader.prototype._constructModules = function (configs) {
|
||||||
|
Object.keys(configs).forEach(function (p) {
|
||||||
|
this.constructModuleFromConfigAtPath(configs[p], p);
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleLoader.prototype.constructModuleFromConfigAtPath = function (config, p) {
|
||||||
|
config.options = config.options || {};
|
||||||
|
config.options._moduleLoader = this;
|
||||||
|
config.options._name = path.basename(path.dirname(p));
|
||||||
|
|
||||||
|
var Type = this.getTypeFromConfig(config, p);
|
||||||
|
|
||||||
|
assert(typeof Type === 'function', config.module + ' does not export a constructor');
|
||||||
|
|
||||||
|
// private options
|
||||||
|
config.options._path = p;
|
||||||
|
|
||||||
|
// cache discovered types
|
||||||
|
var T = Type;
|
||||||
|
|
||||||
|
while(T) {
|
||||||
|
this.types[T.name] = T;
|
||||||
|
|
||||||
|
T = T.super_;
|
||||||
|
}
|
||||||
|
|
||||||
|
var m = this._modules[p] = new Type(config.options, config.dependencies);
|
||||||
|
|
||||||
|
// create NodeModule
|
||||||
|
var nmFilename = path.resolve(path.dirname(p));
|
||||||
|
var nm = new PatchedModule(nmFilename, module);
|
||||||
|
nm.exports = m;
|
||||||
|
nm.filename = nmFilename;
|
||||||
|
nm.loaded = true;
|
||||||
|
require('module')._cache[nmFilename] = nm;
|
||||||
|
|
||||||
|
// load main
|
||||||
|
if(config.main) {
|
||||||
|
var mnmFilename = path.resolve(path.dirname(p), config.main);
|
||||||
|
var mnm = new PatchedModule(mnmFilename, nm);
|
||||||
|
mnm.load(mnmFilename);
|
||||||
|
}
|
||||||
|
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a module with the provided name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ModuleLoader.prototype.getByName = function (name) {
|
||||||
|
var paths = Object.keys(this._modules);
|
||||||
|
|
||||||
|
for (var i = 0; i < paths.length; i++) {
|
||||||
|
var n = path.basename(path.dirname(paths[i]));
|
||||||
|
|
||||||
|
if(n === name) {
|
||||||
|
return this._modules[paths[i]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a module config by module name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ModuleLoader.prototype.getConfigAndPathByName = function (name) {
|
||||||
|
var paths = Object.keys(this._files);
|
||||||
|
|
||||||
|
for (var i = 0; i < paths.length; i++) {
|
||||||
|
if(path.basename(path.dirname(paths[i])) === name) {
|
||||||
|
return {config: this._files[paths[i]], path: paths[i]};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleLoader.prototype.getTypeFromConfig = function (config, configPath) {
|
||||||
|
var ml = this;
|
||||||
|
var Type;
|
||||||
|
var typeName = config.module;
|
||||||
|
|
||||||
|
if(!typeName) return;
|
||||||
|
|
||||||
|
// pointing to a relative type file
|
||||||
|
if(typeName[0] === '.') {
|
||||||
|
try {
|
||||||
|
var relPath = path.join(path.dirname(configPath), typeName);
|
||||||
|
|
||||||
|
|
||||||
|
debug('requiring relative module %s', relPath);
|
||||||
|
Type = require(relPath);
|
||||||
|
} catch(e) {
|
||||||
|
fail(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// pointing to a module
|
||||||
|
try {
|
||||||
|
// load from the programs main module
|
||||||
|
Type = require('module')._load(typeName, process.mainModule);
|
||||||
|
} catch(e) {
|
||||||
|
fail(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Type) {
|
||||||
|
return Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
function fail(e) {
|
||||||
|
console.error('failed to load module at', configPath, typeName);
|
||||||
|
ml.emit('error', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all module instances that inherit from the given type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ModuleLoader.prototype.instanceOf = function (typeName) {
|
||||||
|
var Type = this.types[typeName];
|
||||||
|
var results = [];
|
||||||
|
|
||||||
|
if(!Type) {
|
||||||
|
throw new Error(typeName + ' is not a used type');
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(this._modules).forEach(function (k) {
|
||||||
|
if(this._modules[k] instanceof Type) {
|
||||||
|
results.push(this._modules[k]);
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearObject(obj, fn) {
|
||||||
|
Object.keys(obj).forEach(function (k) {
|
||||||
|
if(fn) {
|
||||||
|
fn(obj[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete obj[k];
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,209 @@
|
||||||
|
/**
|
||||||
|
* Expose `Module`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = Module;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var EventEmitter = require('events').EventEmitter
|
||||||
|
, debug = require('debug')('module')
|
||||||
|
, path = require('path')
|
||||||
|
, util = require('util')
|
||||||
|
, inherits = util.inherits
|
||||||
|
, assert = require('assert');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new `Module` with the given `options`.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Module}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function Module(options, dependencies) {
|
||||||
|
dependencies = dependencies || {};
|
||||||
|
|
||||||
|
EventEmitter.apply(this, arguments);
|
||||||
|
|
||||||
|
this.options = options;
|
||||||
|
|
||||||
|
if(this.constructor.dependencies) {
|
||||||
|
assert(typeof this.constructor.dependencies === 'object', this.constructor.name
|
||||||
|
+ '.dependencies does not allow any dependencies!');
|
||||||
|
|
||||||
|
// merge dependencies for inheritence chain
|
||||||
|
var constructor = this.constructor;
|
||||||
|
var mergedDeps = {};
|
||||||
|
|
||||||
|
while(constructor) {
|
||||||
|
var deps = constructor.dependencies;
|
||||||
|
|
||||||
|
if(deps) {
|
||||||
|
Object.keys(deps).forEach(function (key) {
|
||||||
|
if(!mergedDeps[key]) mergedDeps[key] = deps[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// move up the inheritence chain
|
||||||
|
constructor = constructor.super_;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.dependencies = this._resolveDependencies(dependencies, mergedDeps);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.constructor.options) {
|
||||||
|
assert(typeof this.constructor.options === 'object', this.constructor.name
|
||||||
|
+ '.options must be an object!');
|
||||||
|
|
||||||
|
// merge options for inheritence chain
|
||||||
|
var constructor = this.constructor;
|
||||||
|
var mergedOpts = {};
|
||||||
|
|
||||||
|
while(constructor) {
|
||||||
|
var opts = constructor.options;
|
||||||
|
|
||||||
|
if(opts) {
|
||||||
|
Object.keys(opts).forEach(function (key) {
|
||||||
|
if(!mergedOpts[key]) mergedOpts[key] = opts[key];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// move up the inheritence chain
|
||||||
|
constructor = constructor.super_;
|
||||||
|
}
|
||||||
|
|
||||||
|
validateOptions(options, mergedOpts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inherit from `EventEmitter`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
inherits(Module, EventEmitter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Build dependencies from constructor description (MyCustomModule.dependencies) and dependencie
|
||||||
|
* configuration (config.dependencies).
|
||||||
|
*/
|
||||||
|
|
||||||
|
Module.prototype._resolveDependencies = function (depsConfig, desc) {
|
||||||
|
var types = {};
|
||||||
|
var deps = {};
|
||||||
|
var moduleLoader = this.options._moduleLoader;
|
||||||
|
|
||||||
|
// iterate the class description of dependencies
|
||||||
|
Object.keys(desc).forEach(function (depName) {
|
||||||
|
var depRequired = true;
|
||||||
|
|
||||||
|
if(typeof desc[depName] === 'object' && desc[depName].optional) {
|
||||||
|
depRequired = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var depInstanceName = depsConfig[depName];
|
||||||
|
|
||||||
|
if(!depInstanceName) {
|
||||||
|
if(depRequired) {
|
||||||
|
throw new Error('Required dependency not defined: "' + depName + '"');
|
||||||
|
} else {
|
||||||
|
// don't load the optional dep
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// load the described type
|
||||||
|
try {
|
||||||
|
var modPath = desc[depName].module || desc[depName];
|
||||||
|
|
||||||
|
if(modPath[0] === '.') {
|
||||||
|
modPath = path.resolve('.', path.dirname(this.options._path), desc[depName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
types[depName] = require('module')._load(modPath, process.mainModule);
|
||||||
|
} catch(e) {
|
||||||
|
e.message = 'Failed to load dependency "' + depName + ': ' + modPath + '" for ' + this.options._path + '. ' + e.message;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
var configAndPath = moduleLoader.getConfigAndPathByName(depInstanceName);
|
||||||
|
var config = configAndPath && configAndPath.config;
|
||||||
|
var configPath = configAndPath && configAndPath.path;
|
||||||
|
|
||||||
|
// try to get the dependency by given dependency instance name
|
||||||
|
if(config) {
|
||||||
|
var m = moduleLoader.getByName(depInstanceName);
|
||||||
|
|
||||||
|
if(!m) {
|
||||||
|
// construct the module now
|
||||||
|
m = moduleLoader.constructModuleFromConfigAtPath(config, configPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!types[depName]) {
|
||||||
|
throw new Error(modPath + ' does not correctly export a constructor or does not exist.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!(m instanceof types[depName])) {
|
||||||
|
throw new Error('Dependency ' + depName + ' is not an instance of ' + types[depName].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
deps[depName] = m;
|
||||||
|
} else {
|
||||||
|
console.log(depsConfig);
|
||||||
|
|
||||||
|
throw new Error('Could not find dependency "'+ depInstanceName +'" config while resolving dependencies for ' + this.options._path);
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
return deps;
|
||||||
|
}
|
||||||
|
|
||||||
|
Module.prototype.destroy = function () {
|
||||||
|
this.emit('destroy');
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateOptions(options, def) {
|
||||||
|
if(!def) {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.keys(def).forEach(function (key) {
|
||||||
|
var val = options[key];
|
||||||
|
var keyDef = def[key] || {};
|
||||||
|
|
||||||
|
if(keyDef.required) {
|
||||||
|
assert(val, key + ' is required!');
|
||||||
|
}
|
||||||
|
|
||||||
|
if(typeof val === 'undefined') {
|
||||||
|
// stop validation if a value
|
||||||
|
// wasnt provided
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(keyDef.type === 'array') {
|
||||||
|
assert(Array.isArray(val), key + ' must be a ' + keyDef.type)
|
||||||
|
} else {
|
||||||
|
// type
|
||||||
|
assert(typeof val == keyDef.type, key + ' must be a ' + keyDef.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// size / length
|
||||||
|
if(typeof val.length === 'number') {
|
||||||
|
if(keyDef.min) {
|
||||||
|
assert(val.length >= keyDef.min, key + ' length must be greater than or equal to ', keyDef.min);
|
||||||
|
}
|
||||||
|
if(keyDef.max) {
|
||||||
|
assert(val.length <= keyDef.min, key + ' length must be less than or equal to ', keyDef.max);
|
||||||
|
}
|
||||||
|
} else if(typeof val === 'number') {
|
||||||
|
if(keyDef.min) {
|
||||||
|
assert(val >= keyDef.min, key + ' must be greater than or equal to ', keyDef.min);
|
||||||
|
}
|
||||||
|
if(keyDef.max) {
|
||||||
|
assert(val <= keyDef.max, ' must be less than or equal to ', keyDef.max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* Expose `PatchedModule`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
module.exports = PatchedModule;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Module dependencies.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Module = require('module')
|
||||||
|
, debug = require('debug')('configurable-module')
|
||||||
|
, path = require('path')
|
||||||
|
, util = require('util')
|
||||||
|
, inherits = util.inherits
|
||||||
|
, assert = require('assert');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new `PatchedModule` with the given `options`.
|
||||||
|
*
|
||||||
|
* @param {Object} options
|
||||||
|
* @return {Module}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function PatchedModule(id, parent) {
|
||||||
|
Module.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inherit from node's core `Module`.
|
||||||
|
*/
|
||||||
|
|
||||||
|
inherits(PatchedModule, Module);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Override the default require implementation to check the cache first.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PatchedModule.prototype.require = function (p) {
|
||||||
|
if(p === '.') p = './';
|
||||||
|
|
||||||
|
// for relative modules, check the cache first
|
||||||
|
var sub = p.substr(0, 2);
|
||||||
|
var isRelative = (sub === './' || sub === '..');
|
||||||
|
|
||||||
|
if(isRelative) {
|
||||||
|
var resolvedPath = path.resolve(path.dirname(this.filename), p);
|
||||||
|
|
||||||
|
// check cache first (node's implementation checks the file first)
|
||||||
|
var cached = Module._cache[resolvedPath];
|
||||||
|
if(cached) {
|
||||||
|
return cached.exports;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Module.prototype.require.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Alias functions in case they needs to be patched in the future.
|
||||||
|
*/
|
||||||
|
|
||||||
|
PatchedModule.resolveFilename = Module._resolveFilename;
|
||||||
|
PatchedModule.load = Module._load;
|
||||||
|
PatchedModule.resolveLookupPaths = Module._resolveLookupPaths;
|
||||||
|
PatchedModule.nodeModulePaths = Module._nodeModulePaths;
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,24 @@
|
||||||
|
var ModuleLoader = require('../');
|
||||||
|
|
||||||
|
// describe('ModuleLoader', function(){
|
||||||
|
// var moduleLoader;
|
||||||
|
//
|
||||||
|
// beforeEach(function(){
|
||||||
|
// moduleLoader = new ModuleLoader;
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// describe('.myMethod', function(){
|
||||||
|
// // example sync test
|
||||||
|
// it('should <description of behavior>', function() {
|
||||||
|
// moduleLoader.myMethod();
|
||||||
|
// });
|
||||||
|
//
|
||||||
|
// // example async test
|
||||||
|
// it('should <description of behavior>', function(done) {
|
||||||
|
// setTimeout(function () {
|
||||||
|
// moduleLoader.myMethod();
|
||||||
|
// done();
|
||||||
|
// }, 0);
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// });
|
|
@ -0,0 +1,48 @@
|
||||||
|
var Module = require('../lib/module.js');
|
||||||
|
var inherits = require('util').inherits;
|
||||||
|
|
||||||
|
describe('Module', function(){
|
||||||
|
var module;
|
||||||
|
|
||||||
|
beforeEach(function(){
|
||||||
|
module = new Module;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should merge all dependency objects', function() {
|
||||||
|
function FooModule() {
|
||||||
|
Module.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(FooModule, Module);
|
||||||
|
|
||||||
|
FooModule.dependencies = {
|
||||||
|
'foo': 'foo',
|
||||||
|
'baz': 'baz'
|
||||||
|
}
|
||||||
|
|
||||||
|
function BarModule() {
|
||||||
|
FooModule.apply(this, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
inherits(BarModule, FooModule);
|
||||||
|
|
||||||
|
BarModule.dependencies = {
|
||||||
|
'foo': 'complex-foo',
|
||||||
|
'bar': 'bar'
|
||||||
|
};
|
||||||
|
|
||||||
|
var called = false;
|
||||||
|
|
||||||
|
BarModule.prototype._resolveDependencies = function (depsConfig, desc) {
|
||||||
|
assert(desc.foo == 'complex-foo');
|
||||||
|
assert(desc.bar == 'bar');
|
||||||
|
assert(desc.baz == 'baz');
|
||||||
|
called = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var bar = new BarModule({}, {});
|
||||||
|
|
||||||
|
assert(called);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -0,0 +1,5 @@
|
||||||
|
/**
|
||||||
|
* sl-module-loader test setup and support.
|
||||||
|
*/
|
||||||
|
|
||||||
|
assert = require('assert');
|
|
@ -1,24 +1,2 @@
|
||||||
var Asteroid = require('../');
|
var Asteroid = require('../');
|
||||||
|
|
||||||
describe('Asteroid', function(){
|
|
||||||
var asteroid;
|
|
||||||
|
|
||||||
beforeEach(function(){
|
|
||||||
asteroid = new Asteroid;
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('.myMethod', function(){
|
|
||||||
// example sync test
|
|
||||||
it('should <description of behavior>', function() {
|
|
||||||
asteroid.myMethod();
|
|
||||||
});
|
|
||||||
|
|
||||||
// example async test
|
|
||||||
it('should <description of behavior>', function(done) {
|
|
||||||
setTimeout(function () {
|
|
||||||
asteroid.myMethod();
|
|
||||||
done();
|
|
||||||
}, 0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
Loading…
Reference in New Issue