A better Stream abstraction for node.js. npm install pirandello


There's a bunch of ways to create a Stream.

Creates a stream that sends a single value and ends.

Stream.of("hello world")
//> hello world 

Just ends immediately.

Sends each item in the array, then ends.

Stream.fromArray(["hello ","world"])
//> hello world 

Takes a node Readable stream and sends it one data chunk at a time.


To construct your own Streams, call the constructor (new is optional) with a function that takes two arguments. Each argument is a function: call the first one with an object to send it over the stream, call the second one to end the stream. From the implementation of fromArray:

Stream.fromArray = function(arr) {
    return Stream(function(next,end) {

Pirandello Streams are immutable; the methods below return a new stream. Streams are a fantasy-land MonadPlus.

Returns a new stream that sends the contents of the current stream followed by the contents of the other stream.

Stream.of("hello ").concat(Stream.of("world"))
//> hello world 

Takes a function that operates on each chunk and should return a new Stream. Useful for concatenating lists.

function read(f) {
    return Stream.fromReadable(fs.createReadStream(f));

Maps over the chunk.

Stream.fromArray(["hello ","world"]).map(function(s) {return s.toUpperCase()})

Applies a stream of functions to a stream of inputs, returns a stream of outputs.

    function(s) { return s.toUpperCase(); },
    function(s) { return s.toLowerCase(); },
    function(s) { return s.substr(0,5); }
]).ap(Stream.of("Hello World "))
//> HELLO WORLD hello world Hello 

Converts a Stream of strings into a Stream of individual characters.

Given a number, returns a stream of the first n chunks. Useful with toCharstream.

Stream.of("hello world").toCharstream().take(5)
//> hello 

Given a number, returns a stream without the first n chunks. Useful with toCharstream.

Stream.of("hello world").toCharstream().drop(6)
//> world 

Mostly compatible with Readable::pipe, sends every chunk to the destination Writable.

When you really need low-level chunk functionality (maybe you're extending Pirandello? Good for you!), generator is what you want. It is, in fact, the function passed in when the Stream is instantiated; call it with two arguments, one function to deal with each chunk, and one which is called at the end. FUrom the implementation of pipe:

Stream.prototype.pipe = function(dest) {
        function(chunk) { dest.write(chunk) }
        function() { dest.end() }


I tried to make Readables look nice, I really did. The API is ugly, and the abstraction is leaky. Here's to a fresh start.