DEV Community

Daniel
Daniel

Posted on

Bloques con Ruby

Hoy en día cuando hablamos de Ruby no podemos dejar de lado los bloques. Estos vienen a ser una parte súper importante al momento de estar (como se dice en mi barrio) tirando código y su complejidad puede variar dependiendo nuestras necesidades.

Lo básico

Comúnmente utilizamos bloques para iterar, generalmente sobre las vistas con objetos en Rails, por ejemplo:

<%= @elements.each do |e|%>
  <% e.inspect %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

Como podemos ver este es un bloque ejecutado desde una vista de Rails. Sin embargo transportando esto a un código sin frameworks, contamos con dos versiones para poder generar bloques los cuales son los siguientes:

* La versión larga
# Esta versión generalmente la uso cuando se que voy a realizar alguna operación dentro del bloque y se que voy a ocupar mas de una linea.
elements.each do |e|
  # operacion 1
  # operation 2
  # ........
end

* La versión corta
# Esta la utilizo cuando solo necesito una linea de retorno y la operacion no es muy compleja.
elements.each{|e| puts e}
Enter fullscreen mode Exit fullscreen mode

Profundizando un poco mas en bloques.

Sin embargo que pasa cuando deseo llamar a un método y ademas requiero pasar una serie de instrucciones extra durante su invocación, como es que puedo realizar esto?
Agradezcamos a yield que viene a ayudarnos a realizar este tipo de acciones.
Thanks
Supongamos que contamos con una tarea de convertir una cadena de asteriscos en una mitad de pirámide de caracteres, es decir:

half_pyramid_converter(*********) 
# Output deseado
*
**
***
****
.........n
Enter fullscreen mode Exit fullscreen mode

Para poder hacer esto crearemos un algoritmo que realice el trabajo y posteriormente refactorizaremos

# Version larga
def half_pyramid_converter(characters)
  index = 0
  piramid = ""
  while(index < characters.length)
    yield(piramid << characters[index]) if block_given?
    index+=1
  end
end

# Version refactorizada
def half_pyramid_converter_refactor(characters)
  piramid = ""
  characters.each_char {|char| yield( piramid << char) if block_given?}
end

# Llamadas 
half_pyramid_converter("*******"){|c| puts "#{c}"}
half_pyramid_converter_refactor("**********"){|c| puts "#{c}"}
Enter fullscreen mode Exit fullscreen mode

Como podemos ver en la primer versión lo que hacemos es comparar la variable index contra el tamaño de la cadena si es menor agregamos el carácter a la variable piramid y gracias a yield nuevamente estaremos ejecutando lo que se encuentra dentro de los bloques.
En la segunda versión refactorizada hacemos uso del método each_char que nos brinda la clase String de Ruby, por lo tanto como dice el dicho un poco modificado "you can have your cake and eat it too", es decir si ya esta ahí pues
hagamos uso de este.

Recomendaciones

  • Tal vez te pueda interesar echarle un ojo a el modulo Enumerable. Ya que en conjunto con los bloques es una gran herramienta para iterar y hacer cosas interesantes.
  • Utiliza el método block_given? para detectar si estamos pasando un bloque. De esta manera te evitaras el error "no block given (yield) (LocalJumpError)".
  • Ten en cuenta que el código que se vaya a ingresar en nuestro método iterador es el código de alguien mas, por lo tanto protegelo mediante excepciones.
  • Si vas a estar haciendo operaciones dentro de los métodos junto con bloques es recomendable utilizar el patrón compossed method, de esta manera el código queda mas legible para futuros devs que se montaran sobre este.

Top comments (0)