Skip to content

Commit 4ed5ab2

Browse files
committed
Release v0.2
1 parent f3a8d4d commit 4ed5ab2

18 files changed

+247
-277
lines changed

README.md

+71-47
Original file line numberDiff line numberDiff line change
@@ -17,40 +17,63 @@ Bootstrapping a simple server using Express.js:
1717
var wire = require('nwire');
1818
var config = require('./config');
1919

20-
wire(config, function(err, app){ // Composite root
21-
if (err) throw err; // Something happened while building dependencies
22-
app.packages.server.listen(3000);
20+
wire(config, function(err, app){ // Composite root
21+
if (err) throw err; // Handle errors
22+
app.server.listen(3000); // Start your server
2323
});
2424
```
2525
```js
2626
// server.js
27-
module.exports.needs = ['express'];
28-
module.exports.fn = function($){
27+
module.exports.needs = ['express']; // What your package needs
28+
module.exports.fn = function($){ // Dependencies are injected through $
2929
var app = $.express();
3030

3131
// Add your routes and configuration here
32-
33-
return app;
32+
33+
return app;
3434
}
3535
```
3636
```js
3737
// config.js
3838
module.exports = {
39-
url: __dirname, // Base URL
40-
packages: { // Packages to be injected
41-
'server': './server',
42-
'express': 'express'
43-
}
39+
'server': require('./server'), // Provide packages
40+
'express': require('express')
4441
}
4542
```
4643

4744
## Why?
4845

49-
Dependency injection shouldn't be complicated. `nwire.js` encourages loosely coupled functionality and simplifies the process of isolating your code for testing.
46+
Dependency injection shouldn't be complicated. `nwire` encourages loosely coupled functionality and simplifies the process of isolating your code for testing.
5047

51-
## Creating packages
48+
## Creating the container
5249

53-
### Package definition
50+
You must feed `nwire` a configuration object containing the packages you wish to provide for injection.
51+
52+
Consider this sample configuration object.
53+
```js
54+
// config.js
55+
module.exports = {
56+
'app': require('./server'),
57+
'redis-db': require('./db'),
58+
'express': require('express'),
59+
'morgan': require('morgan'),
60+
'passport': require('passport')
61+
};
62+
```
63+
64+
Here we can see that the packages `app`, `redis-db`, `express`, `morgan`, and `passport` are registered and are ready to be injected in packages that need them. `nwire` will then inject all other four packages through the `imports` parameter for packages that contain the properties `fn` and `needs`.
65+
66+
```js
67+
// server.js
68+
module.exports.needs = ['redis-db', 'express', 'morgan', 'passport'];
69+
module.exports.fn = function(import){ // You can use $ for short
70+
// import now contains four properties each named after the injected packages
71+
var app = import.express();
72+
import["redis-db"].open();
73+
}
74+
```
75+
76+
## Creating packages
5477
5578
Packages are comprised of two properties: `fn` and `needs`.
5679
@@ -62,63 +85,64 @@ module.exports.fn = function(imports) {
6285
var login = function login(username, password, callback){
6386
// Perform authentication here...
6487
}
65-
var logout = function logout(callback) { }
66-
67-
return {
88+
var logout = function logout(callback) { /*...*/ }
89+
90+
return {
6891
login: login,
69-
logout: logout
92+
logout: logout
7093
}
7194
}
7295
```
73-
This package resolves an object that exposes two functions: `login` and `logout`. The resolved object is then injected in other packages that require it through the `needs` property.
96+
This package returns an object that exposes two functions: `login` and `logout`. The returned object is then injected in other packages that require it through the `needs` property.
7497
7598
```js
7699
// server.js
77100
module.exports.needs = ['auth'];
78-
module.exports.fn = function(imports) { // You can use $ for short
79-
var auth = imports.auth; // The auth module is injected
80-
auth.login('testing', '123', function(err){
101+
module.exports.fn = function($) {
102+
$.auth.login('testing', '123', function(err, user){
81103
// Handle whether user is authorized
82104
});
83105
}
84106
```
85-
If the `fn` property is not provided, nwire.js will not perform any dependency injection. If the `needs` property is not provided, the `imports` parameter will be empty.
107+
If the `fn` and `needs` properties are not provided, `nwire` will not perform any dependency injection.
86108
87-
### Package discovery
109+
## Running the test suite
88110
89-
In order to perform dependency injection, you must feed nwire.js a configuration object containing the `url` and `packages` properties.
111+
```
112+
$ npm install
113+
$ npm test
114+
```
90115
91-
The `url` property allows nwire.js to resolve packages without needing their absolute paths. In most configurations, assigning `__dirname` to the `url` property will do. If this property is not provided, nwire.js will attempt to resolve modules from within its own directory.
116+
## Breaking changes from v0.1
92117
93-
The `packages` property assigns a name and location for every package. It must contain an object where property names define package names and property values are corresponding locations.
118+
Release `v0.2` did away with string declarations for `config.js` files. This is to allow `nwire` applications to work with bundlers like Browserify and `system.js`. If your `config.js` file looked like this:
94119
95-
Consider this sample configuration object.
96-
```js
97-
// config.js
98-
var path = require('path');
120+
```javascript
99121
module.exports = {
100-
url: path.join(__dirname, 'src'),
122+
url: __dirname,
101123
packages: {
102-
'app': './server',
103-
'database': './db',
104-
'express': 'express',
105-
'morgan': 'morgan',
106-
'passport': 'passport'
124+
'app': './app'
107125
}
108-
};
126+
}
109127
```
110128
111-
Here we can see that the packages `app`, `database`, `express`, `morgan`, and `passport` are registered and are ready to be injected in packages that need them. Assuming that the `app` package looks like the following code, nwire.js will inject all other four packages through the `imports` parameter.
129+
You will now need to use CommonJS (or equivalent) to load your application.
112130
113-
```js
114-
// server.js
115-
module.exports.needs = ['database', 'express', 'morgan', 'passport'];
116-
module.exports.fn = function(import){
117-
// import now contains four properties each named after the injected packages
118-
var app = import.express();
131+
```javascript
132+
module.exports = {
133+
'app': require('./app')
119134
}
120135
```
121136
137+
Also, packages are now properties of the container returned by `nwire` rather than living under a `packages` object.
138+
139+
```javascript
140+
wire({ /*...config...*/}, function(err, app) {
141+
// app.packages.server.bootstrap(3000);
142+
app.server.bootstrap(3000);
143+
});
144+
```
145+
122146
## Suggestions and questions
123147
124-
If you have any suggestions or questions regarding this project, please open an issue. If you feel that you have a feature that would be useful to add, fork it and open a pull request.
148+
If you have any suggestions or questions regarding this project, please open an issue. If you feel that you have a feature that would be useful to add, fork it and open a pull request.

examples/expressjs/config.js

+4-7
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
module.exports = {
2-
url: __dirname,
3-
packages: {
4-
'server': './server',
5-
'express': 'express',
6-
'winston': 'winston'
7-
}
8-
}
2+
'server': require('./server'),
3+
'express-app': require('express'),
4+
'winston': require('winston')
5+
}

examples/expressjs/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ var wire = require('../../');
22

33
wire(require('./config'), function(err, app) { // Composite root
44
if (err) throw err;
5-
app.packages.server.bootstrap(1337);
6-
});
5+
app.server.bootstrap(3000);
6+
});

examples/expressjs/server.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
module.exports.needs = ['express', 'winston'];
1+
module.exports.needs = ['express-app', 'winston'];
22
module.exports.fn = function($) {
3-
var app = $.express();
3+
var app = $["express-app"]();
44

55
var bootstrap = function(port) {
66
return app.listen(port, function() {
@@ -11,4 +11,4 @@ module.exports.fn = function($) {
1111
return {
1212
bootstrap: bootstrap
1313
};
14-
}
14+
}

examples/koajs/config.js

+5-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
module.exports = {
2-
url: __dirname,
3-
packages: {
4-
'server': './server',
5-
'koa': 'koa',
6-
'winston': 'winston',
7-
'http': 'http'
8-
}
9-
}
2+
'server': require('./server'),
3+
'koa': require('koa'),
4+
'winston': require('winston'),
5+
'http': require('http')
6+
}

examples/koajs/index.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ var wire = require('../../');
22

33
wire(require('./config'), function(err, app) { // Composite root
44
if (err) throw err;
5-
app.packages.server.bootstrap(1337);
6-
});
5+
app.server.bootstrap(3000);
6+
});

nwire.js

+33-81
Original file line numberDiff line numberDiff line change
@@ -1,98 +1,50 @@
1-
module.exports = function nwire(config, callback) {
2-
'use strict';
1+
var Container = function(config, callback) {
2+
if (typeof callback !== "function")
3+
throw new Error("Please provide a callback function.")
34

4-
// Set up a wiring container that injects all necessary components into
5-
// the packages provided
6-
var Wiring = function() {
7-
// Validate configuration object
8-
if (!config || typeof config !== 'object')
9-
throw "Please provide a valid configuration object.";
5+
var $ = {}; // Resolved packages
6+
var decls = config.packages || config;
7+
if (!decls) return callback(null, $);
108

11-
var path = require('path');
12-
var base = config.url || '';
13-
var definitions = config.packages || {};
9+
var resolve = function(decl) {
10+
if ($[decl]) return $[decl];
1411

15-
// Validate package definitions
16-
if (!definitions || definitions instanceof Array ||
17-
!(definitions instanceof Object)) definitions = {};
12+
var mod = decls[decl];
1813

19-
var self = this;
20-
self.packages = {};
14+
if (mod.fn && typeof mod.fn === "function" &&
15+
mod.needs && mod.needs instanceof Array && !mod.ignore) {
16+
var needs = {};
2117

22-
var load = function(name, skipNeeds) { // Responsible for loading packages
23-
if (typeof(name) !== 'string') throw "Invalid package definition.";
18+
$[decl] = {};
2419

25-
if (!definitions[name]) return undefined;
26-
27-
// If a package already exists with the same name, do not attempt to
28-
// overwrite it. Return the existing package.
29-
var loaded = self.packages[name];
30-
if (loaded) return loaded;
31-
32-
var pkg, imports = {};
33-
34-
var resolve = function(name) {
35-
try { // Try to load a system module first
36-
return require(name)
37-
} catch (e) {
38-
try { // Try to load an NPM module
39-
return require(path.join(base, 'node_modules', name));
40-
} catch (er) { // Try to load the module through the base directory
41-
try {
42-
return require(path.join(base, name));
43-
} catch (err) {
44-
return null;
45-
}
46-
}
47-
}
48-
}
49-
50-
pkg = resolve(definitions[name]);
51-
if (!pkg) return null;
52-
53-
// If a package is dependent on other packages, it's time to load them.
54-
if (pkg.hasOwnProperty('needs') && pkg.needs instanceof Array)
55-
pkg.needs.forEach(function(dependencyName) {
56-
var definition = resolve(definitions[dependencyName]);
57-
var skip = false;
58-
59-
if (definitions && definition.needs)
60-
for(var i = 0; i < definition.needs.length; i++){
61-
var need = definition.needs[i];
62-
if (need == name) skip = true;
63-
}
64-
65-
if (!skipNeeds) {
66-
self.packages[dependencyName] = load(dependencyName, skip);
67-
Object.defineProperty(imports, dependencyName, {
68-
get: function(){
69-
return self.packages[dependencyName];
70-
}
71-
});
20+
mod.needs.forEach(function(need) {
21+
Object.defineProperty(needs, need, {
22+
get: function() {
23+
if (!decls[need]) return null;
24+
return $[need] || resolve(need);
7225
}
7326
});
27+
});
7428

75-
// If package implements the fn function then inject the necessary
76-
// packages and replace the package signature with the object it
77-
// returns
78-
if (pkg.hasOwnProperty('fn')) pkg = pkg.fn(imports);
79-
80-
return pkg;
29+
if (!mod.construct) $[decl] = mod.fn(needs);
30+
else Object.defineProperty($, decl, {
31+
get: function() {
32+
return new mod.fn(needs);
33+
}
34+
});
8135
}
8236

83-
for (var definition in definitions) {
84-
if (!definition) continue;
85-
var fn = load(definition);
86-
if (fn) self.packages[definition] = fn;
87-
}
37+
$[decl] = $[decl] || mod;
38+
return $[decl];
8839
}
8940

9041
try {
91-
var app = new Wiring();
92-
if (!callback) return app;
93-
callback(null, app);
42+
for (var decl in decls) $[decl] = resolve(decl);
43+
callback(null, $);
9444
} catch (err) {
95-
if (!callback) throw err;
96-
callback(err);
45+
callback(err, null);
9746
}
9847
}
48+
49+
50+
module.exports = Container;

package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "nwire",
3-
"version": "0.1.4",
3+
"version": "0.2.0",
44
"description": "Simplified dependency injection in Node.js",
55
"main": "nwire.js",
66
"scripts": {
@@ -25,7 +25,6 @@
2525
"homepage": "https://github.com/divmgl/nwire#readme",
2626
"devDependencies": {
2727
"chai": "^3.2.0",
28-
"lodash": "^3.10.1",
2928
"mocha": "^2.2.5"
3029
}
3130
}

spec/fixtures/circular/config.js

-7
This file was deleted.

0 commit comments

Comments
 (0)