Si algo hemos aprendido de lo que hay detrás de la filosofía Unix al hacer programas, es que deben ser pequeños, tener un solo cometido y acoplarse fácilmente entre ellos. Esta misma dinámica podemos llevarla a nuestros programas usando los transform streams.

Ya hablamos hace tiempo en este blog sobre [cómo usar read streams](http://carlosvillu.com/aprende-a-usar-readstream-en-nodejs/, ahora iremos un paso más allá y combinaremos varios streams entre ellos para que funcionen como uno solo.

Un transform stream lee la salida de un read stream, hace algún cambio a cada "chunk" que le llega y lo devuelve como entrada de un write stream.

El método mágico que lleva a cabo esa transformación es _transform. Este método recibe tres parámetros:

  • chunk. Que puede ser un String o un Buffer

  • encoding. Codificación del chunk, puede ser cualquier codificación válida para un Buffer.

  • callback. Nuestra transformación, puede realizar algún tipo de operación asíncrona sobre los datos que le han llegado, y es por ello que no se considera que hemos acabado de transformar el chunk que nos ha llegado hasta que se llame al callback.

Con esto en mente, vamos a llevar a cabo un pequeño proyecto. Tomaremos un read stream como stdin, leeremos una cadena de texto, la pondremos en mayúsculas y luego la convertiremos a dot language (luego explicaré qué es exactamente). Por último, enviaremos el resultado de esas dos transformaciones a un write stream como stdout.

Convertir a mayúsculas

En este apartado vamos a crear nuestro primer transform stream. Se trata de una clase que hereda de stream.Transform e implementa el método _transform:

// upcase.js

var Transform = require( 'stream' ).Transform,  
    utils = require( 'util' );


var Upcase = function(){  
  Transform.call( this );
};

utils.inherits( Upcase, Transform );


Upcase.prototype._transform = function( chunk, encoding, cb ){  
  chunk = chuck.toString( 'utf8' ).toUpperCase();
  this.push( chunk );
  cb();
};

module.exports = Upcase;  

No hay nada especial en la forma de crear la clase. Lo realmente importante es el método _transform. Aunque esta implementación es muy simple, puede llegar a ser tan compleja como quieras. Es importante que notes que NO estás obligado a llamar a this.push si no deseas inyectar nada al siguiente actor en la cadena de streams, pero siempre deberás llamar al cb para que la operación se dé por concluída.

convertir a dot language

El dot language es extremadamente simple. Solo toma todos los caracteres que hay en una frase y coloca puntos entre ellos. Tal vez se vea más simple ver un ejemplo:

cadena original: We love JS  
cadena dot language: W.e. .l.o.v.e. .J.S.  

Simple, pero creo que sirve para el propósito de este ejemplo.
Por otra parte, como ya hemos visto cómo crear clases que heredan de stream.Transform, te voy a mostrar cómo reducir un poco la cantidad de código que tienes que escribir usando un módulo externo, through.

// dot-language.js

var through = require( 'through' );

var dotLanguage = through( function( chunk ){  
  chunk = chunk.toString( 'utf8' )
                .split('')
                .join('.');
  this.push( chunk );
} );

module.exports = dotLanguage;  

Como puedes ver, la cantidad de código que hemos tenido que escribir es sensiblemente menor.

Combinar streams

Ahora que ya tenemos nuestras dos transformaciones listas, solo tenemos que usarlas. Para ello, vamos a crear un script que consuma la entrada de consola, la transforme y el resultado lo envíe a la salida de la consola de vuelta.

var Upcase = require( './upcase' ),  
    dotLanguage = require( './dot-language' );

process.stdin  
  .pipe( new Upcase() )
  .pipe( dotLanguage )
  .pipe( process.stdout );

Así de simple es. Nuestra entrada de consola se pasa todo a mayúsculas, estás son traducidas a dot language y el resultado es enviado de vuelta a la salida. Al final, tras ejecutar nuestro script, tendríamos algo así:

Las posibilidades de esto son enormes. Tenemos desde transfomaciones de imágenes a compresión. Aquí solo hemos arañado la superficie, pero si crees que puede ser interesante no dejes de echarle un ojo a Stream Handbook.

Si te ha gustado este post, difunde la palabra. Tampoco dudes en dejar comentarios u observaciones. ¡Gracias! :)

Suscríbete a mi lista de correo

* Campos obligatorios