← Volver a la lista de posts

Manejo de dependencias en Ruby con Bundler

Bundler es una manejador de dependencias para Ruby. Aunque viene incluido con Rails, Bundler no es exclusivo de Rails, lo puedes usar para manejar las dependencias de cualquier proyecto de Ruby.

La mayoría de los proyectos en los que vas a trabajar van a utilizar una o más librerías. Una librería no es más que código empaquetado que alguien publica y que puedes utilizar en tus proyectos. Todos los lenguajes de programación tienen alguna forma de crear, distribur y usar librerías. En Ruby, a las librerías se les conoce con el nombre de gemas. Cualquier persona puede crear y publicar una gema.

Instalar una gema en tu máquina es muy fácil, solo debes ejectuar el comando gem install seguido del nombre de la gema. Por ejemplo, para instalar Ruby on Rails puedes ejecutar:

$ gem install rails

Este comando instalaría la versión más reciente de Rails, pero si deseas instalar otra versión lo puedes hacer con la opción -v. Por ejemplo:

$ gem install rails -v 4.2.7

Bundler

Instalar individualmente cada una de las gemas de las que depende un proyecto puede ser muy engorroso, además de que sería necesario mantener una documentación actualizada con la lista de gemas y la versión de cada una por si cambiamos de máquina o entra un nuevo integrante a nuestro equipo.

El segundo problema es que puedes tener varias versiones de la misma gema instalada. Por defecto Ruby utiliza la última versión de la gema, pero es posible que esa no sea la que tu proyecto necesite.

Veamos cómo Bundler nos ayuda a solucionar estos problemas.

Bundler es una gema, así que el primero paso es instalarlo con el siguiente comando:

$ gem install bundler

Para definir las dependencias de nuestro proyecto creamos un archivo de texto llamado Gemfile (sin extensión) en el que vamos a listar las gemas de las que depende nuestro proyecto:

source 'https://rubygems.org'

gem 'nokogiri'
gem 'rack', '~>1.1'
gem 'sinatra', '1.4.7'

La primera línea le dice a Bundler la URL del servidor desde donde se deben instalar las gemas. RubyGems es el servicio de Ruby en donde están almacenadas todas gemas públicas.

Las demás líneas definen las gemas de las que depende nuestro proyecto. Si omites la versión -como en el caso de nokogiri arriba- Bundler asume que deseas utilizar la última versión disponible. Existen varias formas de especificar la versión, veamos algunos ejemplos:

gem 'rails', '4.2.7' # la versión 4.2.7 exactamente
gem 'rails', '>=4.2.7' # cualquier versión igual o mayor que 4.2.7
gem 'rails', '>=4.2.7', '<5.0.0' # igual o mayor que 4.2.7, pero menor que 5.0.0

Los siguientes dos son casos especiales pero muy comunes, de hecho es una muy buena práctica defnir las versiones de esta forma:

gem 'rails', '~>4.2.7' # igual o mayor que 4.2.7, pero menor que 4.3.0
gem 'rails', '~>4.2' # igual o mayor que 4.2.0, pero menor que 5.0.0

La mayoría de gemas utilizan el siguiente esquema de versionamiento: dada una version X.Y.Z, X se incrementa cuando hay cambios mayores que son incompatibles con versiones anteriores, Y se incrementa cuando hay nuevas funcionalidades que son compatibles con versiones anteriores, Z se incrementa cuando se solucionan bugs y sigue siendo compatible con versiones anteriores.

A esto se le conoce como versionamiento semántico.

Cargar gemas de Github directamente

También es posible cargar una gema de su repositorio de Github directamente:

gem 'papertrail', github: 'germanescobar/papertrail'

En este caso se asumiría que quieres cargar el último commit de la rama master, pero puedes especificar cualquier rama:

gem 'papertrail', github: 'germanescobar/papertrail' branch: 'my-branch'

Esto es muy útil cuando necesitas funcionalidad que aún no está en la última versión de la gema, o cuando necesitas hacer cambios propios a la gema (p.e. para solucionar algún bug).

Instalar las gemas

Una vez que tienes las gemas definidas en el Gemfile, puedes instalarlas en tu máquina local con el siguiente comando:

$ bundle install

Este comando crea un archivo Gemfile.lock con las versiones de las gemas que se van a utilizar en el proyecto. Es buena práctica agregar este archivo al sistema de control de versiones. Recuerda volver a ejecutar este comando cada vez que hagas cambios al archivo Gemfile.

Configurar la aplicación

Nota: Esto solo es necesario cuando no estás utilizando Ruby on Rails.

El último paso es agregar la siguiente línea al punto de entrada de tu aplicación para asegurar que todas las gemas sean encontradas:

require 'bundler/setup'
# requiere las gemas que necesites normalmente

# el resto de tu aplicación ...

Si tu aplicación necesita muchos require puedes utilizar la siguiente línea para que Bundler lo haga por ti:

require 'bundler/setup'
Bundler.require(:default)

# el resto de tu aplicación ...

Usando grupos

Con Bundler puedes agrupar tus dependencias y de esa forma realizar operaciones sobre un grupo entero. Veamos el siguiente Gemfile de ejemplo:

# Estas gemas están en el grupo :default
gem 'nokogiri'
gem 'sinatra'

gem 'wirble', :group => :development

group :test do
  gem 'faker'
  gem 'rspec'
end

group :test, :development do
  gem 'capybara'
  gem 'rspec-rails'
end

gem 'cucumber', :group => [:cucumber, :test]

Ruby on Rails utiliza la agrupación de dependencias de Bundler para definir diferentes ambientes de la aplicación (desarrollo, producción y pruebas). Puedes hacer lo mismo en otros proyectos que no sean de Rails.

Por ejemplo, para requerir todas las gemas que están en el grupo :default y :development puedes hacer lo siguiente:

require 'bundler/setup'
Bundler.require(:default, :development)

# el resto de tu aplicación ...

Conclusión

Bundler es quizá una de las herramientas más importantes del ecosistema de Ruby, y de la programación en general porque inspiró otros sistemas de manejo de dependencias como npm (en Node JS) y pip (en Python).

Espero que este post te haya ayudado a aclarar qué es Bundler y su rol en Ruby on Rails; y que de esta forma puedas aprovechar todo su potencial!

comments powered by Disqus