Bienvenidos una vez más a Ruby desde Cero. En los últimos capítulos estudiamos las clases y el paradigma orientado a objetos aplicados al lenguaje. Si aún no te has puesto al día con la serie te invito a echarle un vistazo a Ruby desde Cero

En este nuevo capítulo estaremos estudiando los módulos en Ruby, al igual que en los capítulos anteriores definiendo cada una de las características, mostrando la sintaxis y ejecutando ejemplos básicos para comprender mejor el tema.

¿Qué son los módulos?

Un módulo es una colección de métodos y constantes. Mediante el uso de módulos, podemos dividir el sistema o el programa en partes independientes para facilitarnos el uso de los métodos para reutilizarlos, es decir, los módulos podrían ser paquetes de métodos y clases relacionados que nos facilitarán encontrarlos más rápido.

Aunque el concepto de módulos se asemeja bastante al de clases que también tiene métodos, clases y constantes, se diferencian básicamente en que no se pueden crear objetos de un módulo, es decir, no se instancian los módulos.

Otra ventaja, es que podemos almacenar nuestros programas de forma modular: cada módulo añade una característica. Esto también lo permitían las clases, pero la ventaja de los módulos, es que no hace falta crear una serie de jerarquías, que podría llegar a ser engorroso.

Lo primero que debemos hacer para adentrarnos en el concepto y comenzar a elaborar algunos ejemplos es conocer la sintaxis:

module Identificador
  declaracion1
  declaracion2
  . . .
end

Al igual que con los métodos de clase, se llama a un método del módulo precediendo su nombre con el nombre módulo y un punto ( . ), y se hace referencia a una constante utilizando el nombre del módulo y el signo de dos puntos ( : ).

Principales usos de los módulos

Los módulos en Ruby básicamente se utilizan para definir espacios de nombres (‘namespace’) que básicamente nos agrupa todas las clases, métodos, variables y otros elementos, dentro de un especie de grupo o paquete. Otro de los usos es el ‘mixins’ que nos permite agregar funcionalidad extras a una clase. Ésto lo definiremos mejor a continuación:

Espacios de nombres (‘namespace’)

Cuando estamos desarrollando algún proyecto grande y las lineas de código crecen desenfrenadamente, surge la necesidad de organizar de alguna forma nuestro código para poder manipularlo con facilidad, y es aquí donde nos es útil este tipo de implementación de los módulos.

Con los módulos es posible agrupar una serie de métodos y clases relacionadas de alguna manera en un archivo independiente, de tal manera que podamos utilizar estos métodos como una librería independiente. Un caso típico de un módulo es ‘Math’: este módulo cuenta con una serie de funciones trigonométricas agrupadas en un sólo paquete.

Los espacios de nombres también evitan el problema de que surja una ambiegüedad en el caso de que haya dos componentes con un mismo nombre. Por ejemplo, podemos tener dentro de un programa varias clases con el nombre “Settings”, pero cada una estará referida a algo concreto. Incluyendo esas clases en distintos módulos, conseguimos que puedan ser identificadas de forma unívoca.

Luego de tanta descripción veamos un ejemplo y así seguramente entenderemos mejor el concepto de namespace:

module Semana
  PRIMER_DIA = "lunes"
  def Semana.semanas_en_mes
    puts "un mes tiene cuatro semanas"
    return 4
  end
  def Semana.semanas_en_anio
    puts "un anio tiene 52 semanas"
  end
end

class Codehero
  N_MESES = 10
  def n_de_meses
    puts "las semanas inician el #{Semana::PRIMER_DIA}"
    number=10 * Semana::semanas_en_mes
    puts "cantidad de semanas en 10 meses es #{number}"
  end
end

puts Semana::PRIMER_DIA
Semana.semanas_en_mes
Semana.semanas_en_anio
puts "==================="
d1=Codehero.new
d1.n_de_meses

En este ejemplo creamos un módulo ‘Semana’ que agrupa una serie de métodos y constantes relacionadas a una semana, que posteriormente utilizamos en una clase de prueba y fuera de ella. El resultado de esta ejecución lo podemos observar a continuación:

lunes
un mes tiene cuatro semanas
un anio tiene 52 semanas
===================
las semanas inician el lunes
un mes tiene cuatro semanas
cantidad de semanas en 10 meses es 40

Mixins

Esta implementación de los módulos nos da una forma bastante elegante de agregarle funcionalidad a las clases. Sin embargo, su verdadero poder viene cuando el código en el mixin comienza a interactuar con el código de la clase que lo utiliza.

Vamos a ver un ejemplo en el que añadimos un método a la clase String que elimina los espacios en blanco de principio y fin de una cadena de caracteres.

module UtilidadesString
  def quitar_espacios
    self.to_s.strip.gsub(' ', '')
  end
end

class String
  include UtilidadesString
end

puts " Hola CodeHero, El Mejor Portal De Aprendizaje En Espaniol ".quitar_espacios

El resultado de la ejecución del programa es una cadena sin espacios:

HolaCodeHero,ElMejorPortalDeAprendizajeEnEspaniol

En el ejemplo vimos como le agregamos un método de instancia a la clase String, con esta herramienta también es posible extender una clase con métodos de clases, haciendo uso del ‘extend’. Haciendo posible incluir varios módulos en una misma clase, consiguiendo un efecto similar a una herencia múltiple no permitida por Ruby. Veamos un ejemplo sencillo de esto:

module Calendario
  def self.included(base)
    base.send :include, Dia
    base.send :extend, Semana
  end

  module Dia
    def dia_en_anio
      "un anio tiene 365 dias"
    end
  end

  module Semana
    PRIMER_DIA = "lunes"

    def semanas_x_mes(number)
      "#{number} meses tiene #{number * 4} semanas"
    end
  end
end

class MiClase
  include Calendario
end

#llamada a las clases

puts MiClase.semanas_x_mes(4)
puts MiClase.new.dia_en_anio

Como podemos ver en el ejemplo al agregar en un módulo el método ‘included’, éste se ejecutará cada vez que sea incluido por otro módulo o clase. En este ejemplo, cuando se incluye el módulo, añadimos los métodos de instancia(include) y de clase(extend). Dándonos como resultado una clase con comportamientos diferentes de dos módulos, el resultado de ejecutar el programa es el siguiente:

4 meses tiene 16 semanas
un anio tiene 365 dias

Conclusión

En este capítulo aprendimos un concepto básico de Ruby como lo son los módulos, abarcando el concepto principal, ventajas, sintaxis, usos y manipulación de esta útil característica del lenguaje.

Si te surgen dudas con nuestros cursos, no te detengas y danos tus comentarios, que con gusto estamos dispuestos a resolver tus inquietudes.

¡Hasta el próximo capítulo!