Creates an instance of the spur injector.
var spur = require("spur-ioc");
module.exports = function(){
var ioc = spur.create("mymodulename");
// ...
return ioc;
};
Register external node modules or already constructed objects or global dependencies which can be mocked in your tests
Register already constructed objects or global dependencies which can be mocked in your tests.
ioc.registerDependencies({
"express" : require("express"),
"methodOverride" : require("method-override"),
"cookieParser" : require("cookie-parser"),
"bodyParser" : require("body-parser"),
"path" : require("path"),
"fs" : require("fs"),
"JSON" : JSON,
"console" : console,
"nodeProcess" : process,
"Schema" : require("mongoose").Schema
});
This is useful to cover hard to test calls to the global process or global console object.
Note that we use camelCase
convention for dependency name as hiphens are not valid in javascript variable names
Registers folders for autoinjection, dirname will be parent folder and foldernames will be the sub folders to auto inject.
ioc.registerFolders(__dirname, [
"runtime",
"domain"
]);
Given this folder structure
+-- runtime
| +-- WebServer.js
+-- domain
| +-- Book.js
| +-- mappers
| | +-- BookMapper.js
The files WebServer.js
, Book.js
, BookMapper.js
will be autoinjected by their filename without extension.
All autoinjected files must have the following signature which exports a function with the dependencies it needs, spur will autoinject by name.
module.exports = function(Book, BookMapper, express){
//...
};
The singular version of register dependencies.
ioc.addDependency("console", console);
ioc.addDependency("console", console); //warns of overwritten dependency
ioc.addDependency("console", console, true); //surpress warning
Register a resolvable dependency function.
// function params will be autoinjected
ioc.addResolvableDependency("UncaughtHandler", function(nodeProcess, console){
nodeProcess.on("uncaughtException", function(err){
console.log(err);
nodeProcess.exit(0);
});
};
Use at startup or in your tests to bootstrap application.
var injector = require("./injector");
injector().inject(function(MyWebServer, MongooseManager){
MongooseManager.connect().then(function(){
MyWebServer.start();
});
});
var injector = require("../../lib/injector");
describe("Greeter", function(){
beforeEach(function(){
var _this = this;
injector().inject(function(Greeter){
_this.Greeter = Greeter;
})
});
it("should exist",function(){
expect(this.Greeter).to.exist;
});
it("should greet correctly", function(){
expect(this.Greeter.greet()).to.equal("Hello World!");
});
});
All autoinjected files must have the following signature which exports a function with the dependencies it needs, spur will autoinject by name.
module.exports = function(Book, BookMapper, express){
//...
};
Spur IoC allows you to split up injectors and create resuable modules, modules then can be either merged or linked.
Merging allows you to combine multiple injectors in to 1 bigger injector if you had core utilities you could merge them into your app injectors and use them within your business logic.
Note that merging will share 1 namespace and could overwrite dependencies with the same name.
var spur = require("spur-ioc");
module.exports = function(){
var ioc = spur.create("core-utilities");
ioc.registerFolders(__dirname, [
"utils"
]);
return ioc;
};
var spur = require("spur-ioc");
var CoreUtilitiesInjector = require("./CoreUtilitiesInjector");
module.exports = function(){
var ioc = spur.create("my-app");
ioc.registerFolders(__dirname, [
"domain"
]);
ioc.merge(CoreUtilitiesInjector());
return ioc;
};
Expose + link allows you to expose public dependencies to other injectors. All other dependencies will be private, and rather than merging spur-ioc will run both injectors side by side and pass exposed references to parent injectors.
var spur = require("spur-ioc");
module.exports = function(){
var ioc = spur.create("core-apis");
ioc.registerDependencies({
"request": require("request"),
"_" : require("lodash")
})
ioc.registerFolders(__dirname, [
"api"
])
//expose using array, the 2 apis which are defined in the api folder
ioc.expose(["UsersAPI", "ProjectsAPI"])
//we can also expose by regex or exposeAll
//ioc.expose(/.+API$/);
//ioc.exposeAll();
return ioc;
}
var spur = require("spur-ioc");
var CoreApisInjector = require("./CoreApisInjector");
module.exports = function(){
var ioc = spur.create("my-app");
ioc.registerFolders(__dirname, [
"webserver"
]);
ioc.link(CoreApisInjector());
// Now we can use UsersAPI, ProjectsAPI
ioc.addResolvableDependency("StatsAPI", function(UsersAPI, ProjectsAPI){
return {
counts:function(){
users:UsersAPI.count(),
projects:ProjectsAPI.count()
}
};
});
ioc.addResolvableDependency("WillBreak", function(_, request){
//will throw missing dependency exception because _ + request are private to CoreApisInjector
});
return ioc;
}
ioc.expose(["PathUtils", "MyLogger"]);
//dependencies ending with controller
ioc.expose(/.+Controller$/);
Expose all dependencies in the injector.
Will run other injector and inject exposed dependencies into current injector.
Alongside your register libraries and dependencies, spur-ioc provides a helper $injector which you can inject.
-
Note that $injector can only retrieve dependencies synchronously at startup.
-
This is because spur-ioc resolves dependencies only at startup and then gets out the way to let the app work normally with those references.
Sometimes you want to check get a dependency that you are not sure may exist, the get()
API allows you to do that. The main usecase for this is when you want to make the dependecy of other modules optional or based on configuration. An example would be the use of logger like statsd, winston, etc.
module.exports = function($injector){
var statsd = $injector.get("statsd");
if(statsd) {
// start using statsd
};
};
Sometimes you want to inject multiple dependencies without listing them all out. getRegex will return a key:value object with dependencies matching the regex.
module.exports = function($injector){
// inject controllers by regex, convention is to have this calls at the top
var controllers = $injector.getRegex(/Controller$/);
/* returns {
AppController:<AppControllerInstance>,
TasksController:<TasksControllerInstance>
...
} */
// this will fail!, injector is disposed at startup,
// cannot be used asynchronously
setTimeout(function(){
var controllers = $injector.getRegex(/Controller$/);
}, 100);
};