Ruby Version Manager, o cómo tener múltiples intérpretes de Ruby en tu máquina al mismo tiempo

Ruby es un lenguaje que ha madurado muchísimo en los últimos años. Al principio sólo existía un intérprete, el de Matz, y su rendimiento no era lo que se dice espectacular (el propio Matz ha admitido en varias ocasiones que él no es un experto en la construcción de este tipo de software, y que buena parte del código debería ser revisado y optimizado).

Hoy en día hay un buen puñado de intérpretes diferentes para este maravilloso lenguaje: Ruby 1.8, Ruby 1.9, JRuby, Rubinius, MacRuby, Maglev, Ruby Enterprise Edition, IronRuby... Algunos de ellos llevan usándose en entornos de producción desde hace algún tiempo.

¿Por qué es útil RVM?

Siempre es más que recomendable que utilices el mismo intérprete que estés usando en producción, para evitar sorpresas. El problema viene cuando trabajas en varios proyectos escritos en Ruby al mismo tiempo, y cada uno de ellos utiliza un intérprete diferente. O también, utilizan versiones de gems diferentes, y parece que la única solución sea andar desinstalando e instalando versiones de dichas gems cada vez que cambias de uno a otro, lo cual es evidentemente poco práctico y nada razonable.

Imagina la situación: Empiezas la jornada trabajando en el Proyecto 1, el cual lleva en desarrollo bastante tiempo y aún se basa en la versión 2.3 de Rails. Dado que esta versión aún tenía problemas de compatibilidad con la serie 1.9 de Ruby (esta versión del intérprete aún no era muy popular por aquel entonces, pues se encontraba en un estado poco maduro), el proyecto utiliza Ruby Enterprise Edition, una variante del intérprete 1.8 con varias mejoras de rendimiento (en especial, en el plano de la gestión de memoria). De modo que en tu máquina local instalas Ruby Enterprise Edition, Rails 2.3 y todas las gems de las que depende el proyecto.

Más tarde, te pones a trabajar en el Proyecto 2, que acaba de comenzar, y con el que os habéis decidido a usar Rails 3.1 (que para cuando finalice el proyecto ya estará maduro) y Ruby 1.9.2. Necesitas poder instalar este segundo intérprete sin que pise los ejecutables del primero, y cambiar tu PATH si es necesario para que localice los nuevos binarios. Cada vez que cambies del primer proyecto al segundo, has de actualizar tu PATH para asegurarte que estás usando los binarios correctos. Si has de actualizar a una versión menor del intérprete, tendrás que repetir estas operaciones, y reinstalar todas las gems.

Por último, llama un cliente al que le desarrollásteis una aplicación en Rails 2.2 con Ruby Enterprise Edition, y que necesita un pequeño cambio urgente. Como vuestro REE lo tenéis configurado para el Proyecto 1, tenéis instaladas las gemas de Rails 2.3, así como las versiones de otras gemas que funcionan bien para esa aplicación. Cuando os ponéis a instalar las dependencias de esta vieja aplicación, e intentáis arrancarla, empiezan a llover errores de dependencias entre versiones (se intenta cargar una versión específica de una gem, pero alguna otra librería la ha cargado ya en otra versión, de modo que cuando intenta leer la más vieja devuelve un error). Dado que Rails 2.x aún no utilizaba bundler para la gestión de dependencias, tenéis que arremangaros y empezar a desinstalar las versiones de gems conflictivas, a sabiendas que cuando volváis a volcar vuestra atención en el Proyecto 1 tendréis que deshacer estos pasos.

¿Te suenan algunas de estas situaciones? Si te dedicas a programar aplicaciones en Ruby desde hace tiempo, seguro que sí. Y por eso Ruby Version Manager viene a nuestro rescate. Gracias a esta herramienta, podemos tener tantos intérpretes de Ruby como queramos, incluso diferentes versiones menores de un mismo intérprete, y cambiar de uno a otro tan sólo ejecutando un comando. Además, podemos definir un gemset (un conjunto de gemas) para cada proyecto, de modo que cuando nos cambiemos a un gemset en particular, éste contenga exclusivamente las gemas que hacen falta para correr la aplicación, en sus versiones apropiadas, sin que afecten a las otras aplicaciones que podamos tener.

Vale, me has convencido. ¿Cómo lo instalo?

En primer lugar, has de tener un sistema que ejecute alguna variante de Unix. RVM no funciona en máquinas Windows, aunque sí que se comporta perfectamente bajo Linux o Mac OS X. La instalación es sencillísima, tan sólo has de tener instalada la herramienta curl (en Mac OS X viene instalada por defecto), así como Git, y ejecutar el siguiente comando:

  $ bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

Una vez instalado y actualizado tu PATH para incluir la ruta a los binarios de RVM, tal y como te recomienda el proceso final de instalación, sólo has de instalarte los intérpretes de Ruby que consideres oportunos. En Mac OS X, necesitarás tener instalado el paquete de Xcode SDK, que es donde viene el compilador de C. En Linux, deberás instalar estas dependencias usando el administrador de paquetes de tu distribución. Si utilizas Debian o derivados (como Ubuntu), bastará normalmente con que instales el metapaquete build-essentials. Si algún intérprete requiere que se cumplan dependencias adicionales, se te informará sobre ello.

Por ejemplo, podemos instalar el intérprete REE y el 1.9.2, requisitos de los ejemplos que mencioné antes:

  $ rvm install ree
  $ rvm install 1.9.2

Para cambiar de uno a otro una vez instalados, tan sólo hay que hacer:

  $ rvm ree

Cómo crear un gemset

Como mencionaba anteriormente, podemos crear conjuntos de gemas separadas para cada proyecto. Tan sólo hay que especificar un nombre para ese gemset, y utilizar las herramientas que rvm proporciona (puedes escribir "rvm gemset" para ver todos los comandos disponibles). Por ejemplo, podemos crearnos un gemset para el proyecto 1, y cambiarnos a él:

  $ rvm gemset create proyecto1
  $ rvm gemset use proyecto1

Es importante entender que el gemset se crea para el intérprete que estemos usando en ese momento. De modo que antes de crear un gemset, selecciona el intérprete adecuado.

Cómo automatizar el cambio de intérprete y gemset

No quisiera finalizar el artículo sin mencionaros una vía rápida para que, al cambiar a la carpeta de un proyecto, RVM os seleccione el intérprete y gemset adecuados de forma automática. Para ello, sólo tenéis que crear un fichero de nombre ".rvmrc" en la carpeta en cuestión, y éste contendrá la serie de comandos necesarios para realizar estas operaciones. Cuando entréis en dicha carpeta desde línea de comandos, RVM ejecutará dichas acciones, y todo estará listo para empezar a trabajar. Por ejemplo, podéis tener algo como esto (que no es más que un atajo a la selección del intérprete y del gemset, creando este último en el camino en caso de que no exista, todo en un único comando):

  rvm --create 1.9.2@proyecto2

Conclusiones

Espero haber esclarecido las ventajas principales de usar una herramienta como RVM en tu entorno de trabajo. Por supuesto, RVM posee muchas más funcionalidades, que te invito a que conozcas visitando la web oficial.

¿Usas ya RVM? ¿Qué otros trucos similares conoces para llevar un control de los requisitos de tus proyectos?

Más información | Ruby Version Manager

Portada de Genbeta