NodeJS y el tipo de valores retornados por la función require
Programar para NodeJS implica casi por definición utilizar su gestor de paquetes, NPM, y por ello utilizar la instrucción require() para utilizar las funcionalidades de esos paquetes en nuestro código.
Por el grado de madurez en el que está actualmente NodeJS (aunque en principio la versión 0.12 será la staging version para la 1.0), hay ciertos patrones y directrices en la estructura de los módulos que quedan abiertos por ahora. Uno de ellos es el funcionamiento de require() y de lo que retorna esta función.
Retornando valores en nodeJS con require()
En principio la función require es fácil de usar:
var elementoRetornado = require('/ruta/a/archivo.js');
Para que el módulo de nodeJS retorne algo, debe existir una instrucción del tipo:
Pero claro, ¿Qué contiene la variable
elementoRetornado? Pues depende de cada módulo. Esto afecta a la estandarización de la operativa, pero también abre un campo de posibilidades para encapsular funcionalidades en los paquetes de NodeJS.
En el blog de goodegs han explicado los principales casos de elementos a retornar con require() y algunos ejemplos. Sólo para resumir brevemente, los casos que comenta son los siguientes.
Namespace
Es un caso interesante para un conjunto de prototipos que están incluidos en un paquete. Así, el valor retornado por require da acceso a una serie de propiedades de un objeto, que a su vez son prototipos que pueden ser instanciados. Este es el ejemplo más habitual de las bibliotecas del núcleo de NodeJS, como por ejemplo filesystem (fs).
Un patrón del require para este caso es:
var ns = require('/ruta/a/namespace.js');
var utilidadDelNamespace = ns.Utilidad;
Función
Se puede facilitar una función que actúe como intermediario con el resto de funciones del módulo.
El patrón para require es:
var proxyFunction = require('modulo.js');
var modulo = proxyFunction();
En cierto sentido guarda similitud con un constructor, aunque no es exactamente lo mismo.
Función de orden superior
Se trata de retornar una función que adapta su comportamiento a otra función de entrada. Este patrón permite flexibilizar el comportamiento de un módulo.
var functor = require('modulo.js'); // Retorna la función
var adaptador = require('modulo2.js');
var item = functor(adaptador);
Constructor
Es el caso más clásico, el módulo retorna un constructor a un prototipo, por lo que el retorno del require puede instanciarse para crear un objeto a usar en el código de la aplicación de nodeJS.
var Blog = require('blog.js');
var miBlog = new Blog('sopadebits.com');
Singleton
En algunos casos interesa que todos los elementos del módulo compartan el mismo estado y datos de un módulo externo. Si es así, hablamos de un Singleton. En resumen el módulo retorna una clase ya instanciada.
var singleton = require('singleton-module.js');
singleton.method(arg);
Como extensión de un objeto Global
En algunos casos (los mínimos posibles ya que a menudo esto no es un buen patrón de diseño) nos interesará extender algunos objetos globales (o incluso Object). Esto permite que algunos elementos incorporen métodos inexistentes. Por ejemplo, es el caso de
should.
Aunque el patrón puede variar sensiblemente, el ejemplo de uso sería:
require('should');
var user = {
name: 'Juan'
};
user.name.should.equal('Juan');
El método should ha sido generado al importar el módulo should.js.
Monkey Patch
Como simplificación del caso anterior, se refiere a modificaciones que se hacen de forma dinámica para corregir (
patching) alguna funcionalidad defectuosa. En esos casos el patrón de require pasa por:
- Require de la clase/módulo a parchear.
- Require del parche.
El primer
require devolverá alguno de los casos anteriores.
Y hasta aquí los patrones de require que podemos encontrar más habitualmente. No descartes leer el artículo en inglés, que es el que realmente tiene el mérito, y más detalles.