Hey everyone! This is the third post in my new node.js modules you should know about article series.
The first post was about dnode - the freestyle rpc library for node, the second was about optimist - the lightweight options parser for node.
This time I'll introduce you to one of my own modules called node-lazy - lazy lists module for node.
Basically you create a new lazy object, and pump data into it via data
events (it's an event emitter). Then you can manipulate this data via chaining by using various functional programming methods.
Here is a quick example. Here we create a new lazy object and define a filter
that returns only even integers, then we take
just 5 elements, then we apply map
on them, and finally we join
(think of threads) the result in a list:
var Lazy = require('lazy');
var lazy = new Lazy;
lazy
.filter(function (item) {
return item % 2 == 0
})
.take(5)
.map(function (item) {
return item*2;
})
.join(function (xs) {
console.log(xs);
});
You can return this object from your function and then later when someone pumps data into it via data
events, it will do the computation.
For example, if you do this:
[0,1,2,3,4,5,6,7,8,9,10].forEach(function (x) {
lazy.emit('data', x);
});
setTimeout(function () { lazy.emit('end') }, 100);
Then the output will be produced by the console.log
once 5 elements have reached the bottom of the chain.
The output is: [0, 4, 8, 12, 16]
.
Here is a real world example from node-iptables (another of my modules):
var Lazy = require('lazy');
var spawn = require('child_process').spawn;
var iptables = spawn('iptables', ['-L', '-n', '-v']);
Lazy(iptables.stdout)
.lines
.map(String)
.skip(2) // skips the two lines that are iptables header
.map(function (line) {
// packets, bytes, target, pro, opt, in, out, src, dst, opts
var fields = line.trim().split(/\s+/, 9);
return {
parsed : {
packets : fields[0],
bytes : fields[1],
target : fields[2],
protocol : fields[3],
opt : fields[4],
in : fields[5],
out : fields[6],
src : fields[7],
dst : fields[8]
},
raw : line.trim()
};
});
This code fragment takes output from iptables -L -n -v
and converts it into a data structure for later use.
Here a new Lazy object is created from an existing stream - the iptables.stdout
stream. Next, the special lines
getter is called that splits the stream on \n
char and converts it into a line-stream. Then this stream is mapped onto String
constructor to convert it to a string. Next, first two lines are skipped via skip(2)
and then all the other lines are converted into a data structure via map
.
You can also create all kinds of ranges with node-lazy, including infinite ranges. Check this out, ranges.js:
var Lazy = require('lazy');
Lazy.range('1..20').join(function (xs) {
console.log(xs);
});
Lazy.range('444..').take(10).join(function (xs) {
console.log(xs);
});
Lazy.range('2,4..20').take(10).join(function (xs) {
console.log(xs);
});
When you run it:
$ node ranges.js [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ] [ 2, 4, 6, 8, 10, 12, 14, 16, 18 ] [ 444, 445, 446, 447, 448, 449, 450, 451, 452, 453 ]
Here are all the possible ranges that node-lazy supports:
Lazy.range('10..') - infinite range starting from 10 Lazy.range('(10..') - infinite range starting from 11 Lazy.range(10) - range from 0 to 9 Lazy.range(-10, 10) - range from -10 to 9 (-10, -9, ... 0, 1, ... 9) Lazy.range(-10, 10, 2) - range from -10 to 8, skipping every 2nd element (-10, -8, ... 0, 2, 4, 6, 8) Lazy.range(10, 0, 2) - reverse range from 10 to 1, skipping every 2nd element (10, 8, 6, 4, 2) Lazy.range(10, 0) - reverse range from 10 to 1 Lazy.range('5..50') - range from 5 to 49 Lazy.range('50..44') - range from 50 to 45 Lazy.range('1,1.1..4') - range from 1 to 4 with increment of 0.1 (1, 1.1, 1.2, ... 3.9) Lazy.range('4,3.9..1') - reverse range from 4 to 1 with decerement of 0.1 Lazy.range('[1..10]') - range from 1 to 10 (all inclusive) Lazy.range('[10..1]') - range from 10 to 1 (all inclusive) Lazy.range('[1..10)') - range from 1 to 9 Lazy.range('[10..1)') - range from 10 to 2 Lazy.range('(1..10]') - range from 2 to 10 Lazy.range('(10..1]') - range from 9 to 1 Lazy.range('(1..10)') - range from 2 to 9 Lazy.range('[5,10..50]') - range from 5 to 50 with a step of 5 (all inclusive)
Install it via npm, as always:
npm install lazy
Awesome sauce!