Vicente Rodríguez

Nov. 2, 2016

Metaprogramación en ruby parte 1

Ruby aunque no es muy popular es un lenguaje sencillo y muy poderoso, es el lenguaje que usa rails(ruby on rails), framework en el que esta hecho este blog.

Este es el repositorio de github donde están los archivos del tutorial.

La metaprogramación se puede definir como la capacidad de que un programa escriba otros programas, ruby al ser un lenguaje interpretado y que va compilando a medida de que se necesiten las instrucciones, nos permite realizar cosas realmente cool, y como verán en este tutorial la metaprogramación no es mas que programar, solo que a un nivel mas avanzado.

Iniciando

Trabajaremos con la version 2.2.0 de ruby, no hay muchas diferencias con respecto a versiones 2.x.x pero por cualquier posible error es mejor trabajar con la misma version.

vamos a empezar con una clase sencilla, creamos un archivo de ruby y ponemos la clase:


class Fabrica

 def initialize(nombre, producto)

  @nombre = nombre

  @producto = producto

 end

end

Como vemos es una clase que solo tiene su constructor pero no tiene ningún método util.

El primer concepto que veremos es open class, en ruby puedes abrir cualquier clase para agregarle métodos o incluso sobre escribirlos, probemos con la clase que creamos:


class Fabrica

 def do?

  "La fabrica se llama: #{@nombre}, y tiene el producto: #{@producto}"

 end

end



nissan = Fabrica.new("Nissan", "coches")



puts nissan.do?



Este nuevo método retorna un string donde se usan las variables de instancia que definimos en el constructor.

Prueben abriendo una clase como String y vuelvan a definir alguno de sus métodos.

Para ver los métodos de una clase se usa Clase.methods, para buscar por referencia puedes usar Clase.methods.grep /referencia/

Es importante saber que los métodos de un objeto viven en la clase no en el objeto y allí son llamados métodos de instancia.

Las variables si son guardadas en los objetos.

Prueben imprimiendo esto:


String.instance_methods == "abc".methods

Ancestros

Una manera de acceder a constantes dentro de clases o módulos es con la sintaxis constante::constante


class H

 X = "Hola x"

end

puts H::X



Y = "Hola y"



module M

 class C

  puts ::Y

 end

end

Existen diferentes maneras de cargar archivos o librerías de ruby.

Una de ellas es load


load("nombre del archivo", true)

al pasar la opción true se crea un namespace para que no choquen los métodos y variables que se llamen igual en el archivo actual.

Cuando ejecutas un método en un objeto o clase, ruby lo busca primero en la clase actual y después en las clases de las que hereda, estas clases se llaman ancestors, ruby busca el método por cada clase hasta que lo encuentra y lo ejecuta.

Podemos agregar módulos a clases de ruby con prepend o include, la diferencia de estos dos es que prepend agregara el modulo abajo de la clase en la lista de ancestors, entonces primero buscara el método a ejecutar en el modulo y después en la clase, include es lo contrario, coloca el modulo arriba en la lista de ancestors y lo empieza a buscar por la clase.


module M2

 def something;end

end



class C2

 include(M2) #prepend

end



class G2 < C2; end



puts G2.ancestors

Si ejecutamos este código veremos la lista de ancestors que tiene la clase G2, intenta imprimir cambiando include por prepend.

Refine

Al principio del tutorial vimos como podemos abrir cualquier clase (open class) para agregar o redefinir sus métodos, pues esta es una practica poco segura porque tal vez nosotros solo queremos abrir una clase para agregar un nuevo método o redefinirlo una única vez, pero si abrimos la clase y lo hacemos, automáticamente todos los objetos que hereden de esa clase tendrán el método nuevo o sobre escrito pero por eso llega al rescate un método llamado refine que permite que solo usemos la clase modificada dentro de un modulo, clase o un scope.


module NewString

 refine String do

  def length

    "es muy grande tu frase!"

  end

 end

end



class Check

 using NewString

 puts "abcd".length

end



puts "abcd".length

Terminamos

Se que pareciera que no vimos nada sobre metaprogramación, pero es importante saber muchas cosas antes de meternos en ese mundo, se tiene que conocer el lenguaje y unos cuantos métodos que son muy útiles, podría poner todo en un solo tutorial pero seria demasiado grande, entonces iremos parte por parte hasta realizar un proyecto donde se muestre todo el potencial de la metaprogramación, espero que les haya gustado y los siguientes tutoriales estarán aquí en mi blog pronto.

Si tienes alguna duda o comentario no dudes en contactarme ya sea via twitter o en los comentarios. Gracias por ver el tutorial completo, ya aprendiste algo nuevo, felicidades!