Ruby básico - parte 2

Publicado el Miércoles, 26 de enero de 2011
Ruby

Ruby

Sigo con la segunda parte del segundo capítulo del Pickaxe. Creo que la primer parte de Ruby básico fue bastante extensa (para ser un post de un blog), pero es lógico por haber sido el principio hay mucho por ver. De a poco iré aceitando un poco este tipo de posts para hacerlos de manera dinámica (para no aburrirme) pero intentando plasmar los aprendizajes.

Como comentaba antes, además del libro tenía como referencia los videos de un curso de la U. de Berkeley. Esta vez agregué también un material único del mundo de Ruby: _why's poignant guide ro ruby.

Veníamos viendo algo básico del lenguaje, variables, strings, hasta Arrays y Hashes. Hoy comenzamos con algo creo que novedoso en Ruby que son los símbolos.

Símbolos en Ruby

Los símbolos en Ruby son algo así como constantes a las que no hay que declarar. Ruby garantiza que su valor es único y siempre será el mismo valor, no se les puede asignar un valor de la manera tradicional :simbolo = "Peanut butter jelly" « Esto genera un error.

Funcionan como un string y se nombran con : como primer caracter de su nombre. Al decir "funcionan como un string" me refiero a que se les puede asignar un nombre y usarlo como un string, pero no tienen las funciones de un string. Según _why, generalmente son usados en situaciones donde necesitas un string pero no lo muestras en pantalla. Aparentemente también se usan como llaves en un hash. Más adelante hay más por ver sobre símbolos.

#!/usr/bin/ruby
 
:fernando
:chunky_bacon
 
puts :fernando
p :chunky_bacon
puts :"Chunky bacon!!"

Imprime:

[fernando@hoth pickaxe]$ ./symbols.rb
fernando
:chunky_bacon
Chunky bacon!!
Chunky bacon!!

Pequeño intervalo homenajeando a _why

Estructuras de control

Ruby cuenta con las estructuras de control básicas de todo lenguaje de programación. Como esta parte es bastante básica, simplemente pego código de cómo se arma cada estructura para tener como referencia.

#!/usr/bin/ruby
 
hoy = Time.now
 
#Estructura if-else
if hoy.saturday?
  puts "Tiempo de estudiar Ruby"
elsif hoy.sunday?
  puts "Ir a la playa"
else
  puts "Hay que trabajar"
end
 
#Estructura while
num = 99
while num < 0
  puts "#{num} bottles of beer on the wall,"
  puts "#{num} bottles of beer"
  puts "Take one down and pass it around,"
  num -= 1
  puts "#{num} bottles of beer on the wall."
end
 
#Statement modifiers:
puts "Me voy a la playa" if Time.now.sunday?
 
num = 6
puts num = num -1 while num > 1

Expresiones regulares

En Picando Código ya publiqué 10 razones para aprender y usar expresiones regulares. Así que asumo que todos los lectores saben qué son y para qué sirven las expresiones regulares.

Por lo que he aprendido hasta el momento, en Ruby las expresiones regulares se representan entre barras: /expresión regular/. Nada nuevo para la mayoría. Para comparar una cadena de caracteres con una expresión regular se usa el "match operator": =~. Éste retorna la posición inicial del patrón en la cadena de caracteres.

#!/usr/bin/jruby
# -*- coding: utf-8 -*-
 
regla1 = "You do not talk about Fight Club"
 
puts regla1 =~ /[0-9]/ #nil si no encuentro nada...
 
if regla1 =~ /Fight Club/
  puts "Someone has been talking 'bout it"
end

Creo que gané un par de geek points extra por probar este código con JRuby 😛

Bloques e Iteradores

Se viene todo un tema, algo bastante particular y poderoso del lenguaje. Nada asegura que ya haya asimilado correctamente su concepto, pero comparto con ustedes lo que entiendo.

Los bloques en Ruby, son una porción de código entre llaves {} o do y end. Se pueden asociar a la invocación de un método escribiéndolos enseguida después de la llamada a un método. Definiendo: la forma de asociar un bloque a un método, es escribiéndolos inmediatamente después de la llamada a dicho método.

Ahora, un método puede invocar su bloque asociado con el comando yield. En este concepto, creo que la incisiva guía de _why explica de forma totamente comprensible de qué se trata. En inglés los símbolos de "Ceda el paso" en el tránsito dicen "Yield":

Puedes preguntarte qué tiene que ver la palabra yield con los carteles de tránsito. Y realmente, es una buena pregunta con, creo yo, una buena respuesta. Cuando ejecutas un método, le estás dando a ese método el control de tu programa. Control para hacer su trabajo y volver con una respuesta.

Con yield, el método se está deteniendo en la intersección, devolviendote el control, a tu bloque. El método está permitiéndote hacer t trabajo antes de resumir el suyo.

Esas pequeñas fases de iluminación... Podemos usar yield las veces que queramos dentro de un método. Cada vez que lo usemos, el método llamará a su bloque asociado.

Los bloques también pueden recibir parámetros. Los parámetros son variables encerradas en pipes y separadas por una coma: |arg1,arg2|.

Código obligado haciendo pruebas de bloques:

#!/usr/bin/ruby
# -*- coding: utf-8 -*-
 
def metodo (name)
  print "Dentro del método: #{name} - "
  yield(name)
end
 
#Bloque en línea simple:
metodo("Mario") { puts "Bloque en línea simple"}
 
#Bloque en varias líneas:
metodo("Pitágoras") do
  puts "Bloque en varias líneas"
  puts 1 * 1
  puts 11 * 11
  puts 111 * 111
  puts 1111 * 1111
  puts 11111 * 11111
end
 
metodo("Armando") {|name| puts "Como parámetro del bloque: #{name}"}

Los bloques se usan en Ruby para implementar iteradores - métodos que devuelven elementos sucesivos de una colección. Creo que el código en este caso es bastante explicativo:

#!/usr/bin/ruby
 
avengers = %w{ Iron\ Man Hulk Thor Captain\ America Wasp Ant-Man }
 
42.times { print "*"}
puts
 
avengers.each {|name| puts "#{name}"}
 
42.times { print "*"}
puts

Lectura y escritura

De los últimos temas del segundo capítulo del libro de Pickaxe, es lectura y escritura. El libro cubre por ahora la entrada y salida estándar. Las funciones:

  • puts - Imprime en la salida estándar con un salto de línea.
  • print - ídem pero sin salto de línea. Ambos pueden usarse para escribir en cualquier objeto de entrada/salida.
  • printf - Imprime con el control de un string de formato (como en C, Perl o PHP): %s, %d, etc.

En cuanto a la lectura, el método tradicional es gets. Éste retorna la siguiente línea de la entrada estándar.

Argumentos desde la línea de comando

Para terminar este post, vamos a ver cómo usar los argumentos pasados a nuestro script Ruby desde la línea de comando. El array ARGV contiene todos los parámetros que pasemos por comandos, y ARGF es un objeto especial de tipo Entrada/Salida que se comporta como los contenidos de los archivos cuyos nombres se pasen por parámetros.

#!/usr/bin/ruby
# -*- coding: utf-8 -*-
 
num = ARGV.size
puts "Parámetros: #{num}"
ARGV.each {|arg| puts "#{arg}"}

Prueben algún código con ARGV y ejecútenlo desde la línea de comandos pasándole varios parámetros.

Y ahí va la segunda parte de este proceso de aprender Ruby. Ya la próxima arrancamos con la interacción entre objetos. Para el próximo post, seguramente vaya mas rápido, ya que no voy a ponerme a definir conceptos básicos de orientación a objetos, solo particularidades de Ruby.

7 comentarios en este post

Feed de comentarios
  1. Avatar

    Bruno 26 enero. 2011 - 12:13

    Los bloques en Ruby también se puede usar para manejar excepciones como se hace en Smalltalk.

    MiClaseX
    eliminarObjeto: unObjeto sinoExiste: bloqueDeExcepcion
    "Elimina [unObjeto] del receptor del mensaje sino existe evalúa el bloque de excepción [bloqueDeExcepcion]"
     
    ^(objects includes: unObjeto) 
       ifTrue: [objects remove: unObjeto]
       ifFalse: [bloqueDeExcepcion value] 
     
    /*---*/

    Este es un método sumamente sencillo, y ahora puedo llamarlo ve varias formas gracias al bloque:

    Forma1 (le envió al objeto [miObjetoPrincipal] el mensaje #eliminarObjeto:sinoExiste: con los parametros [unObjeto] y [nil]):

    miObjetoPrincipal 
       eliminarObjeto: unObjeto 
       sinoExiste: [nil] "si el objeto no existe devuelve nil -null-"

    Forma2:

    miObjetoPrincipal 
       eliminarObjeto: unObjeto 
       sinoExiste: [MessageBox notify: 'No Existe el objeto'] 
       "si el objeto no existe muestra una ventana con el mensaje"

    Es decir que los bloques son de suma importancia en el desarrollo de aplicaciones.

    Este caso es muy trivial, pero se puede hacer construcciones muy complejas con los bloques.

    Un caso un poco mas complejo es cuando le pasas a un bloque otro bloque como parámetro.

    Saludos,
    Bruno

    • Avatar

      Fernando 31 enero. 2011 - 03:57

      ¡Muchas gracias por tu aporte! Un intercambio así buscaba con estos posts, no solo para compartir el conocimiento, sino mejorarlo con aportes 😀
      Me tomé el atrevimiento de darle formato al código.

      Supongo que veré más sobre bloques en Ruby con el tema de las excepciones y demás temas que tengo pendientes todavía.

      Saludos!

      • Avatar

        Bruno 31 enero. 2011 - 09:04

        El formato del código lo hace mucho más legible, muchas gracias. Ahora te comento otro uso que se le dan a los bloques, en este caso para operaciones con colecciones (que el gran uso que se les da).

        Por ejemplo el método #anySatisfy: de la clase Collection.
        #anySatisfy:, sirve para averiguar si en una colección hay algún elemento que satisfaga determinada condición.

        #(2 5 8 9) anySatisfy: [:eachNumero | eachNumero > 10]
        “esta da false”

        #(2 5 8 9) anySatisfy: [:eachNumero | eachNumero > 5]
        “esta da true”

        La implementacion de #anySatisfy: en la clase Collection es:
        Collection
        anySatisfy: discriminator
        “Answer whether the , discriminator, evaluates to true for any element of the receiver.
        Implementation Note: The argument is evaluated for every element of the receiver iff it evaluates to false for every element.”

        self do: [:e | (discriminator value: e) ifTrue: [^true]].
        ^false

        Como funciona, por ejemplo:
        #(2 5 8 9) anySatisfy: [:eachNumero | eachNumero > 10]

        El receptor del mensaje es: #(2 5 8 9) “un Array”
        El mensaje es: #anySatisfy:
        El unico parametro del mensaje es: [:eachNumero | eachNumero > 10] “un Bloque (BlockClosure)”

        Lo que hace el self #do: es iterar sobre todos los elementos de la colección. El bloque dentro del #do:, es decir, (discriminator value: e) ifTrue: [^true], toma cada elemento de la colección y lo evalúa en con el bloque pasado como parámetro: [:eachNumero | eachNumero > 10].

        La sentencia (discriminator value: e) se evaluara tantas veces como elementos tenga la colección, salvo que alguna evaluación devuelva true –> se sale de la iteracion.

        Como vemos (discriminator value: e) es lo mismo que:
        [:eachNumero | eachNumero > 10] value: 2
        [:eachNumero | eachNumero > 10] value: 5
        [:eachNumero | eachNumero > 10] value: 8
        [:eachNumero | eachNumero > 10] value: 9

        Espero se entiende algo…

        Con los bloques se pueden hacer un montón de cosas (también meter la para, je je je) y me parece que a cualquier programador que los entienda le serán de gran utilidad

        Saludos,
        Bruno

    • Avatar

      Fernando 31 enero. 2011 - 03:59

      “Chunky bacon”, hasta donde yo sé, proviene de _why’s poignant guide to ruby.

      Te recomiendo mirar el libro, aunque no te interese aprender Ruby, es un excelente libro de programación. Tiene un enfoque totalmente distinto a todos los libros de programación que había visto hasta el momento.

      La referencia a Chunky Bacon se puede ver en los primeros capítulos ya.

      Saludos!

    • Avatar

      L. Jacob 15 diciembre. 2016 - 16:15

      Como bien te dice Fernando, es una expresión que viene de la Poignant guide de why. Chunky bacon se puede traducir como “un montón(mucho) de bacon”, y creo entender que es como una exclamación placentera (algo así como “cool”), adjetivo de algo sublime, de buena meta, que se introduce mucho en los comics del libro. Además es una expresión bien sonante en el idioma anglosajón, chunky bacon!

Dejar un comentario

Toasty!