Build chainable fluent interfaces the easy way in node.js.
With this meta-module you can write modules with chainable interfaces. Chainsaw takes care of all of the boring details and makes nested flow control super simple too.
Just call Chainsaw
with a constructor function like in the examples below.
In your methods, just do saw.next()
to move along to the next event and
saw.nest()
to create a nested chain.
This silly example adds values with a chainsaw.
var Chainsaw = require('chainsaw');
function AddDo (sum) {
return Chainsaw(function (saw) {
this.add = function (n) {
sum += n;
saw.next();
};
this.do = function (cb) {
saw.nest(cb, sum);
};
});
}
AddDo(0)
.add(5)
.add(10)
.do(function (sum) {
if (sum > 12) this.add(-10);
})
.do(function (sum) {
console.log('Sum: ' + sum);
})
;
Output: Sum: 5
This example provides a wrapper on top of stdin with the help of node-lazy for line-processing.
var Chainsaw = require('chainsaw');
var Lazy = require('lazy');
module.exports = Prompt;
function Prompt (stream) {
var waiting = [];
var lines = [];
var lazy = Lazy(stream).lines.map(String)
.forEach(function (line) {
if (waiting.length) {
var w = waiting.shift();
w(line);
}
else lines.push(line);
})
;
var vars = {};
return Chainsaw(function (saw) {
this.getline = function (f) {
var g = function (line) {
saw.nest(f, line, vars);
};
if (lines.length) g(lines.shift());
else waiting.push(g);
};
this.do = function (cb) {
saw.nest(cb, vars);
};
});
}
And now for the new Prompt() module in action:
var util = require('util');
var stdin = process.openStdin();
Prompt(stdin)
.do(function () {
util.print('x = ');
})
.getline(function (line, vars) {
vars.x = parseInt(line, 10);
})
.do(function () {
util.print('y = ');
})
.getline(function (line, vars) {
vars.y = parseInt(line, 10);
})
.do(function (vars) {
if (vars.x + vars.y < 10) {
util.print('z = ');
this.getline(function (line) {
vars.z = parseInt(line, 10);
})
}
else {
vars.z = 0;
}
})
.do(function (vars) {
console.log('x + y + z = ' + (vars.x + vars.y + vars.z));
process.exit();
})
;
With npm, just do: npm install chainsaw
or clone this project on github:
git clone http://github.com/substack/node-chainsaw.git
To run the tests with expresso, just do:
expresso
node-chainsaw
supports two different modes. In full mode, every
action is recorded, which allows you to replay actions using the
jump()
, trap()
and down()
methods.
However, if your chainsaws are long-lived, recording every action can consume a tremendous amount of memory, so we also offer a "light" mode where actions are not recorded and the aforementioned methods are disabled.
To enable light mode simply use Chainsaw.light()
to construct your
saw, instead of Chainsaw()
.