Post on 27-Jun-2015
description
Ruby en Linux
Dependiendo de la distribución que utilices, hay varias maneras de instalar Ruby. La primer opción es simplemente bajar el código fuente
y compilarlo a mano. Pero en algunas plataformas, hay gestores de
paquetes que hacen la instalación de Ruby extremadamente sencilla.
Debian/Ubuntu:
% sudo apt-get install ruby irb rdoc
Archlinux:
# pacman -S ruby
Gentoo/Sabayon/Funtoo Linux:
# emerge ruby
Acerca de Ruby
¿Te preguntas por qué Ruby es tan popular? Sus fanáticos lo tienen como un lenguaje hermoso y artístico. Y todavía así, dicen que es
práctico y ameno. ¿Por qué?
Los ideales del creador de Ruby
Ruby es un lenguaje con un balance cuidado. Su creador, Yukihiro ―matz‖ Matsumoto, mezcló partes de sus lenguajes favoritos (Perl,
Smalltalk, Eiffel, Ada, y Lisp) para formar un nuevo lenguaje que incorporara tanto la programación funcional como la programación
imperativa.
A menudo ha manifestado que está ―tratando de hacer que Ruby sea
natural, no simple‖, de una forma que se asemeje a la vida real.
Continuando sobre esto, agrega:
Ruby es simple en apariencia, pero complejo por dentro, como el
cuerpo humano1.
Acerca del crecimiento de Ruby
Desde su liberación pública en 1995, Ruby ha atraído devotos desarrolladores de todo el mundo. En el 2006, Ruby alcanzó
reconocimiento masivo, formándose grupos de usuarios activos en las ciudades más importantes del mundo y llenando las capacidades de
las conferencias relacionadas a Ruby.
Ruby-Talk, la lista de correo más importante sobre el lenguaje Ruby
ha crecido hasta lograr un promedio de 200 mensajes por día.
El índice TIOBE, que mide el crecimiento de los lenguajes de
programación, ubica a Ruby en la posición #13 del ranking mundial. Refiriéndose a su crecimiento, predicen, ―Todo indica que Ruby
llegará a estar entre los 10 primeros en menos de 6 meses‖. Gran parte de su crecimiento se atribuye a la popularidad alcanzada por
aplicaciones desarrolladas con Ruby, en particular el framework de desarrollo web Ruby on Rails2.
Ruby es totalmente libre. No sólo gratis, sino también libre para usarlo, copiarlo, modificarlo y distribuirlo.
Viendo todo como un objeto
Inicialmente, Matz buscó en otros lenguajes para encontrar la sintaxis ideal. Recordando su búsqueda, dijo, ―quería un lenguaje que fuera
más poderoso que Perl, y más orientado a objetos que Python3‖.
En Ruby, todo es un objeto. Se le puede asignar propiedades y
acciones a toda información y código. La programación orientada a objetos llama a las propiedades variables de instancia y las acciones
son conocidas como métodos. La orientación a objetos pura de Ruby
se suele demostrar con un simple código que aplica una acción a un
número.
5.times { print "Nos *encanta* Ruby -- ¡es fuera de serie!" }
En muchos lenguajes, los números y otros tipos primitivos no son objetos. Ruby sigue la influencia del lenguaje Smalltalk pudiendo poner métodos y variables de instancia a todos sus tipos de datos.
Esto facilita el uso de Ruby, porque las reglas que se aplican a los objetos son aplicables a todo Ruby.
La flexibilidad de Ruby
Ruby es considerado un lenguaje flexible, ya que permite a sus
usuarios alterarlo libremente. Las partes esenciales de Ruby pueden ser quitadas o redefinidas a placer. Se puede agregar funcionalidad a
partes ya existentes. Ruby intenta no restringir al desarrollador.
Por ejemplo, la suma se realiza con el operador suma (+). Pero si
prefieres usar la palabra sumar, puedes agregar un método llamado
sumar a la clase Numeric que viene incorporada.
class Numeric
def sumar(x)
self.+(x)
end
end
y = 5.sumar 6
# ahora y vale 11
Los operadores de Ruby son simples conveniencias sintácticas para
los métodos. Los puedes redefinir como y cuando quieras.
Los Bloques, una funcionalidad realmente expresiva
Los bloques de Ruby son también vistos como una fuente de gran
flexibilidad. El desarrollador puede anexar una cláusula a cualquier método, describiendo cómo debe actuar. La cláusula es llamada
bloque y se ha convertido en una de las más famosas funcionalidades para los recién llegados a Ruby que vienen de otros lenguajes
imperativos como PHP o Visual Basic.
Los bloques están inspirados por los lenguajes funcionales. Matz dijo,
―en las cláusulas de Ruby, quise respetar la cultura de Lisp4‖.
motores_de_busqueda =
%w[Google Yahoo MSN].map do |motor|
"http://www." + motor.downcase + ".com"
end
En este código, el bloque está descrito entre la construcción do ...
end. El método map aplica el bloque a la lista de palabras provista.
Muchos otros métodos en Ruby dejan abierta la posibilidad al desarrollador para que escriba su propio bloque describiendo los
detalles de qué debe hacer ese método.
Ruby y el Mixin
A diferencia de otros lenguajes de programación orientada a objetos,
Ruby se caracteriza por su intencional herencia simple. Sin embargo, Ruby incorpora el concepto de módulos (llamados categorías en
Objective-C), que son colecciones de métodos.
Las clases pueden mezclar (mixin) un módulo e incorporar todos sus
métodos gratuitamente. Por ejemplo, cualquier clase que implemente
el método each puede incorporar el módulo Enumerable, que le agrega
un conjunto de métodos que usan each para recorrer sus elementos.
class MiArray
include Enumerable
end
En general, los Rubyistas ven esto como una forma mucho más clara de herencia múltiple, que es compleja e incluso puede ser restrictiva.
La apariencia visual de Ruby
A pesar de que Ruby utiliza la puntuación muy limitadamente y se
prefieren las palabras clave en inglés, se utiliza algo de puntuación para decorar el código. Ruby no necesita declaraciones de variables.
Se utilizan convenciones simples para nombrar y determinar el alcance de las mismas.
var puede ser una variable local.
@var es una variable de instancia.
$var es una variable global.
Estos detalles mejoran la legibilidad permitiendo que el desarrollador identifique fácilmente los roles de las variables. También se hace
innecesario el uso del molesto self. como prefijo de todos los
miembros de instancia.
Más allá de lo básico
Ruby tiene un conjunto de otras funcionalidades entre las que se encuentran las siguientes:
manejo de excepciones, como Java y Python, para facilitar el manejo de errores.
un verdadero mark-and-sweep garbage collector para todos los
objetos de Ruby. No es necesario mantener contadores de referencias en bibliotecas externas. Como dice Matz, ―Esto es mejor para tu
salud‖.
escribir extenciones en C para Ruby es más fácil que hacer lo mismo para Perl o Python, con una API muy elegante para utilizar Ruby
desde C. Esto incluye llamadas para embeber Ruby en otros programas, y así usarlo como lenguaje de scripting. También está disponible una interfaz SWIG.
puede cargar bibliotecas de extensión dinámicamente si lo permite el
sistema operativo.
tiene manejo de hilos (threading) independiente del sistema operativo. De esta forma, tienes soporte multi-hilo en todas las
plataformas en las que corre Ruby, sin importar si el sistema operativo lo soporta o no, ¡incluso en MS-DOS!
Ruby es fácilmente portable: se desarrolla mayoritariamente en
GNU/Linux, pero corre en varios tipos de UNIX, Mac OS X, Windows 95/98/Me/NT/2000/XP, DOS, BeOS, OS/2, etc.
Referencias
1 Matz, hablando en la lista de correo Ruby-Talk, 12 de mayo del 2000.
2 Mira la página de Ruby on Rails para averiguar más.
3 Matz, en An Interview with the Creator of Ruby, 29 de noviembre
del 2001.
4 Matz, en Blocks and Closures in Ruby, 22 de diciembre del 2003.
Ruby en 20 minutos
Introducción
Este es un pequeño tutorial de Ruby que no debería tomar más de 20
minutos completarlo. Se asume que ya tienes instalado Ruby. Si no tienes Ruby funcionando en tu PC, descárgalo e instálalo antes de
comenzar.
Ruby interactivo
Arranca el IRB.
Si estás usando Mac OS X abre una Terminal y escribe irb, después
presiona enter.
Si estás usando Linux, abre una Terminal y escribe irb, después
presiona enter.
Si estás usando Windows, abre fxri desde la sección Ruby de tu
Menú de Inicio.
irb(main):001:0>
Bien, ahora está abierto. ¿Y ahora qué?
Escribe esto: "Hola Mundo"
irb(main):001:0> "Hola Mundo"
=> "Hola Mundo"
¡Ruby te obedeció!
¿Qué fue lo que pasó? ¿Acaso acabamos de escribir el programa
―Hola Mundo‖ más corto del mundo? No exactamente. La segunda linea sólo es la forma que tiene IRB para decirnos el resultado de la
última expresión evaluada. Si queremos que el programa escriba ―Hola Mundo‖ necesitamos un poco más:
irb(main):002:0> puts "Hola Mundo"
Hola Mundo
=> nil
puts es el comando básico para escribir algo en Ruby. Pero entonces,
¿qué es ese => nil? Ese es el resultado de la expresión. puts siempre
retorna nil, que es el valor que significa ―absolutamente nada‖ en
Ruby.
Tu calculadora gratis está aquí
Pronto, tenemos suficiente para usar IRB como una calculadora
básica:
irb(main):003:0> 3+2
=> 5
Tres más dos. Bastante fácil. ¿Y qué tal tres veces dos? Podrías escribirlo, es bastante corto, pero también podrías subir y simplemente cambiar lo que ya ingresaste. Prueba presionando la
flecha hacia arriba en tu teclado y verifica si aparece la linea con
3+2 escrito. Si es así, puedes usar la flecha hacia la izquierda para
posicionarte junto al signo + y cambiarlo por un *.
irb(main):004:0> 3*2
=> 6
Ahora intentemos tres al cuadrado:
irb(main):005:0> 3**2
=> 9
En Ruby ** es la forma que tienes para decir ―elevado al‖. ¿Y qué tal
si quieres hacer lo inverso y encontrar la raíz cuadrada de algo?
irb(main):006:0> Math.sqrt(9)
=> 3.0
Bien, esperen, ¿qué fue eso? Si adivinaste, ―fue la forma de averiguar la raíz cuadrada de nueve‖, estás en lo cierto. Pero veamos las cosas
un poco más de cerca. Antes que nada, ¿qué es Math?
Módulos, agrupa el código por tópicos
Math es un módulo incluido para matemáticas. Los módulos tienen dos
roles en Ruby. Esto muestra uno de sus roles: agrupar métodos
similares bajo un nombre familiar. Math también tiene métodos como
sin() y tan().
Después de Math hay un punto. ¿Cuál es la función del punto? El
punto es la forma de identificar al receptor de un mensaje. ¿Qué es
un mensaje? En este caso es sqrt(9), que significa ―llama al método
sqrt‖, abreviación de ―square root‖ (raíz cuadrada) con el parámetro
9.
El resultado de la llamada a este método es el valor 3.0. Notarás que
no es simplemente 3. Eso es porque la mayoría de las veces la raíz
cuadrada de un número no será un número entero, así que el método
siempre retorna un número flotante.
¿Y qué pasa si queremos recordar el resultado de algunas de estas operaciones? Asigna el resultado a una variable.
irb(main):007:0> a = 3 ** 2
=> 9
irb(main):008:0> b = 4 ** 2
=> 16
irb(main):009:0> Math.sqrt(a+b)
=> 5.0
Por más bueno que esté esto de la calculadora, nos estamos alejando
del tradicional mensaje Hola Mundo en el que se supone que los cursos
para principiantes deben enfocarse… así que volvamos a eso.
¿Qué tal si queremos decir ―Hola‖ muchas veces sin cansar nuestros dedos con el teclado? ¡Necesitamos definir un método!
irb(main):010:0> def h
irb(main):011:1> puts "Hola Mundo"
irb(main):012:1> end
=> nil
La expresión def h inicia la definición del método. Le dice a Ruby que
estamos definiendo un método, cuyo nombre es h. La siguiente linea
es el cuerpo del método, la misma expresión que vimos
anteriormente: puts "Hola Mundo". Finalmente, la última linea end la
dice a Ruby que terminamos de definir el método. La respuesta de
Ruby => nil nos comunica que él sabe que terminamos de definir el
método.
Las breves y repetitivas vidas de un método
Ahora intentemos ejecutar ese método algunas veces:
irb(main):013:0> h
Hola Mundo
=> nil
irb(main):014:0> h()
Hola Mundo
=> nil
Bien, eso fue fácil. Ejecutar un método en Ruby es tan fácil como sólo mencionar su nombre. Si el método no requiere parámetros para ejecutarse, eso es todo lo que necesitas. Puedes agregar paréntesis
vacíos, pero no son necesarios.
¿Y qué tal si queremos saludar sólo a una persona y no a todo el
mundo? Simplemente redefine h para que tome un nombre como
parámetro.
irb(main):015:0> def h(nombre)
irb(main):016:1> puts "Hola #{nombre}"
irb(main):017:1> end
=> nil
irb(main):018:0> h("Matz")
Hola Matz
=> nil
Así que eso funciona… pero tomémonos un segundo para ver más en
detalle qué es lo que está sucediendo.
Reservando espacios en un String
¿Qué significa la expresión #{nombre}? Esa es la forma que tiene Ruby
para insertar algo en un String. La expresión entre las llaves es
transformada en un String (si todavía no lo es) y posteriormente sustituida en ese punto del String que la contiene. También puedes
usar esto para asegurarte que el nombre comience con mayúscula:
irb(main):019:0> def h(nombre = "Mundo")
irb(main):020:1> puts "Hola #{nombre.capitalize}"
irb(main):021:1> end
=> nil
irb(main):022:0> h "pedro"
Hola Pedro
=> nil
irb(main):023:0> h
Hola Mundo
=> nil
Algunos otros trucos para destacar. Uno es que otra vez estamos
llamando al método sin utilizar los paréntesis. Si lo que quieres hacer es obvio, los paréntesis son opcionales. El otro truco es el parámetro
por defecto Mundo. Esto significa ―si no se provee un nombre, utiliza el
nombre por defecto "Mundo"‖.
Convirtiéndolo en un Anfitrión
¿Qué hacemos si queremos tener un anfitrión más ―en serio‖? Uno que recuerde tu nombre, te dé la bienvenida y te trate con respeto.
Puedes querer utilizar un objeto para eso. Vamos a crear la clase ―Anfitrion‖.
irb(main):024:0> class Anfitrion
irb(main):025:1> def initialize(nombre = "Mundo")
irb(main):026:2> @nombre = nombre
irb(main):027:2> end
irb(main):028:1> def decir_hola
irb(main):029:2> puts "Hola #{@nombre}"
irb(main):030:2> end
irb(main):031:1> def decir_adios
irb(main):032:2> puts "Adiós #{@nombre}, vuelve pronto."
irb(main):033:2> end
irb(main):034:1> end
=> nil
La nueva palabra clave aquí es class. Esto define una nueva clase
llamada Anfitrion y un par de métodos para esa clase. También toma
nota de @nombre. Esta es una variable de instancia y está disponible
para todos los métodos de la clase. Como puedes ver es utilizada por
decir_hola y decir_adios.
¿Así que cómo hacemos para que esta clase Anfitrion nos sea de
utilidad? Crea un objeto.
Ahora vamos a crear y usar un objeto anfitrión:
irb(main):035:0> a = Anfitrion.new("Juan")
=> #<Anfitrion:0x16cac @nombre="Juan">
irb(main):036:0> a.decir_hola
Hola Juan
=> nil
irb(main):037:0> a.decir_adios
Adiós Juan, vuelve pronto.
=> nil
Una vez que el objeto a es creado, nos recuerda que el nombre es
Juan. Mmm, ¿y si queremos acceder al nombre directamente?
irb(main):038:0> a.@nombre
SyntaxError: compile error
(irb):52: syntax error
from (irb):52
No, no podemos.
Por debajo de la piel del objeto
Las variables de instancia se esconden dentro del objeto. No están
tan escondidas, las puedes ver cuando inspeccionas el objeto, y hay otras formas de acceder a ellas, pero Ruby es fiel a las buenas
costumbres de la programación orientada a objetos manteniendo los datos lo más privados posible.
Entonces, ¿qué métodos están disponibles para los objetos Anfitrion?
irb(main):039:0> Anfitrion.instance_methods
=> ["method", "send", "object_id", "singleton_methods",
"__send__", "equal?", "taint", "frozen?",
"instance_variable_get", "kind_of?", "to_a",
"instance_eval", "type", "protected_methods", "extend",
"eql?", "display", "instance_variable_set", "hash",
"is_a?", "to_s", "class", "tainted?", "private_methods",
"untaint", "decir_hola", "id", "inspect", "==", "===",
"clone", "public_methods", "respond_to?", "freeze",
"decir_adios", "__id__", "=~", "methods", "nil?", "dup",
"instance_variables", "instance_of?"]
Bien. Eso es un montón de métodos. Nosotros sólo definimos dos métodos. ¿Qué es lo que está sucediendo? Bueno, estos son todos
los métodos para los objetos Anfitrion, una lista completa, incluyendo los que están definidos en las superclases de Anfitrion. Si queremos
listar únicamente los métodos definidos para la clase Anfitrion podemos pedirle que no incluya sus ancestros pasándole el
parámetro false, que significa que no queremos los métodos
definidos por sus ancestros.
irb(main):040:0> Anfitrion.instance_methods(false)
=> ["decir_adios", "decir_hola"]
Ah, hay más cosas como esa. Veamos a qué métodos puede
responder nuestro objeto anfitrión:
irb(main):041:0> a.respond_to?("nombre")
=> false
irb(main):042:0> a.respond_to?("decir_hola")
=> true
irb(main):043:0> a.respond_to?("to_s")
=> true
Así que, sabe decir_hola, y to_s (que significa ―convertir algo en un
string‖, un método que está definido por defecto para todos los
objetos), pero no reconoce nombre como un método.
Modificando clases—Nunca es demasiado tarde
¿Pero qué pasa si quieres poder ver o modificar el nombre? Ruby provee una forma fácil para permitir acceder a las variables de un
objeto.
irb(main):044:0> class Anfitrion
irb(main):045:1> attr_accessor :nombre
irb(main):046:1> end
=> nil
En Ruby, puedes volver a abrir una clase y modificarla. Eso no
cambia objetos que ya existan, pero afecta a los nuevos objetos que puedas crear. Así que vamos a crear un nuevo objeto y juguemos con
su propiedad @nombre.
irb(main):047:0> a = Anfitrion.new("Pedro")
=> #<Anfitrion:0x3c9b0 @nombre="Pedro">
irb(main):048:0> a.respond_to?("nombre")
=> true
irb(main):049:0> a.respond_to?("nombre=")
=> true
irb(main):050:0> a.decir_hola
Hola Pedro
=> nil
irb(main):051:0> a.nombre="Matilde"
=> "Matilde"
irb(main):052:0> a
=> #<Anfitrion:0x3c9b0 @nombre="Matilde">
irb(main):053:0> a.nombre
=> "Matilde"
irb(main):054:0> a.decir_hola
Hola Matilde
=> nil
El uso de attr_accessor determinó que se definan dos nuevos métodos
por nosotros, nombre para obtener el valor, y nombre= para modificarlo.
Saludando a todo el mundo, ¡MegaAnfitrion no niega el saludo a
nadie!
De todas formas, este anfitrión no es tan interesante, sólo puede trabajar con una persona a la vez. ¿Qué pasaría si tuviéramos alguna
clase MegaAnfitrion que pudiera saludar al mundo, a una persona, o
una lista completa de personas?
Escribamos esto en un archivo en vez de usar directamente el
intérprete interactivo de Ruby IRB.
Para salir de IRB, escribe ―quit‖, ―exit‖ o simplemente presiona Control-D.
#!/usr/bin/env ruby
class MegaAnfitrion
attr_accessor :nombres
# Crear el objeto
def initialize(nombres = "Mundo")
@nombres = nombres
end
# Decirle hola a todos
def decir_hola
if @nombres.nil?
puts "..."
elsif @nombres.respond_to?("each")
# @nombres es una lista de algún tipo,
# ¡así que podemos iterar!
@nombres.each do |nombre|
puts "Hola #{nombre}"
end
else
puts "Hola #{@nombres}"
end
end
# Decirle adiós a todos
def decir_adios
if @nombres.nil?
puts "..."
elsif @nombres.respond_to?("join")
# Juntar los elementos de la lista
# usando la coma como separador
puts "Adiós #{@nombres.join(", ")}. Vuelvan pronto."
else
puts "Adiós #{@nombres}. Vuelve pronto."
end
end
end
if __FILE__ == $0
ma = MegaAnfitrion.new
ma.decir_hola
ma.decir_adios
# Cambiar el nombre a "Diego"
ma.nombres = "Diego"
ma.decir_hola
ma.decir_adios
# Cambiar el nombre a un vector de nombres
ma.nombres = ["Alberto", "Beatriz", "Carlos",
"David", "Ernesto"]
ma.decir_hola
ma.decir_adios
# Cambiarlo a nil
ma.nombres = nil
ma.decir_hola
ma.decir_adios
end
Guarda este archivo como ―ri20min.rb‖, y ejecútalo con ―ruby ri20min.rb‖. El resultado debería ser:
Hola Mundo
Adiós Mundo. Vuelve pronto.
Hola Diego
Adiós Diego. Vuelve pronto.
Hola Alberto
Hola Beatriz
Hola Carlos
Hola David
Hola Ernesto
Adiós Alberto, Beatriz, Carlos, David, Ernesto. Vuelvan pronto.
...
...
Hay un montón de cosas nuevas en este nuevo ejemplo en las que podemos echar una mirada más profunda.
Así que, investigando nuestro programa, notarás que las primeras
lineas comienzan con un numeral (#). En Ruby, todo lo que esté detrás de un numeral es un comentario y es ignorado por el
intérprete. La primer linea del archivo es un caso especial y en los sistemas operativos del estilo Unix determina cómo ejecutar el
archivo. El resto de los comentarios están únicamente para aportar claridad al significado del código.
Nuestro método decir_hola se ha vuelto un poco más complicado:
# Decirle hola a todos
def decir_hola
if @nombres.nil?
puts "..."
elsif @nombres.respond_to?("each")
# @nombres es una lista de algún tipo,
# ¡así que podemos iterar!
@nombres.each do |nombre|
puts "Hola #{nombre}"
end
else
puts "Hola #{@nombres}"
end
end
Ahora usa el atributo @nombres para tomar decisiones. Si es nil, sólo
imprime tres puntos. No hay razón para saludar a nadie, ¿cierto?
Iterando
Si el objeto @nombres responde al método each, es algo sobre lo que se
puede iterar, así que iteramos entre sus elementos y saludamos a
cada uno de sus integrantes. Finalmente, si @nombres es otra cosa,
dejamos que automáticamente se convierta en un string y usamos el
saludo por defecto.
Veamos ese iterador en más detalle:
@nombres.each do |nombre|
puts "Hola #{nombre}"
end
El método each acepta un bloque de código y lo ejecuta por cada
elemento de la lista, y el código entre do y end es el bloque en sí
mismo. Un bloque es como una función anónima o lambda. La variable
entre los pipes (|) es el parámetro para este bloque.
Lo que sucede es que por cada elemento en la lista, nombre va
tomando su valor y se ejecuta la expresión puts "Hola #{nombre}" con
ese nombre.
Muchos otros lenguajes de programación manejan la iteración de una
lista usando la clásica sintaxis for, que en C se ve así:
for (i=0; i<cantidad_de_elementos; i++)
{
hacer_algo_con(elementos[i]);
}
Esto funciona, pero no es muy elegante. Necesitas una variable
descartable como i, averiguar la cantidad de elementos de la lista, y
explicar cómo recorrerla. La costumbre Ruby (The Ruby Way) es
mucho más elegante, todos los detalles de infraestructura se ocultan
en el método each, todo lo que necesitas hacer es decirle qué hacer
con cada elemento. Internamente, el método each llamará yield
"Alberto", después yield "Beatriz", después yield "Carlos", y así
sucesivamente.
Los bloques, una de las funcionalidades más potentes de Ruby
El poder real de los bloques se disfruta al trabajar con cosas más complicadas que las listas. Más allá de manejar los detalles de infraestructura dentro del método, también puedes manejar la
inicialización, la finalización, y los errores—todos ocultos y
simplificados frente a las preocupaciones del desarrollador.
# Decirle adiós a todos
def decir_adios
if @nombres.nil?
puts "..."
elsif @nombres.respond_to?("join")
# Juntar los elementos de la lista
# usando la coma como separador
puts "Adiós #{@nombres.join(", ")}. Vuelvan pronto."
else
puts "Adiós #{@nombres}. Vuelve pronto."
end
end
El método decir_adios no usa each, en vez de eso se fija si @nombres
responde al método join, y si es así, lo usa. Si no es así, simplemente
imprime la variable como un string. Esta práctica de no preocuparse
sobre el tipo de objeto de una variable, y simplemente depender de los métodos que esta soporta, es conocida como ―Duck Typing‖. El
beneficio es que no limita innecesariamente los tipos de variables que son soportados. Si alguien inventa un nuevo tipo de lista, siempre y
cuando implemente el método join con la misma semántica que otras
listas, todo funcionará como fue planeado.
Arrancando el Script
Así que eso es la clase MegaAnfitrion, el resto del archivo sólo llama a los métodos de la clase. Hy un último truco para tener en cuenta, y
es la linea:
if __FILE__ == $0
__FILE__ es la variable mágica que contiene el nombre del archivo que
se está ejecutando en ese momento. $0 es el nombre del archivo
usado para iniciar el programa. Esta verificación dice ―si este es el
archivo principal…‖. Esto permite que un archivo sea utilizado como una biblioteca, y no ejecutar código en ese contexto. Pero si el
archivo está siendo usado como un ejecutable, entonces ejecuta ese código.
Considérate iniciado
Eso es todo en este rápido paseo por Ruby. Hay mucho más por explorar, las estructuras de control diferentes que ofrece Ruby; el uso
e los bloques y yield; módulos como mixins; y más. Espero que esta
pequeña muestra de Ruby te despierte el interés por saber más.
Si es así, por favor dirígete a nuestra area de Documentación, donde
encontrarás vínculos a cursos y manuales, todos disponibles gratuitamente en internet.
O si realmente te gustaría sumergirte en un libro, busca en el listado
de libros los títulos disponibles para venta en linea o en tu tienda
favorita.
Ruby desde otros lenguajes
Cuando te enfrentas por primera vez a código escrito en Ruby,
probablemente te recuerde otros lenguajes que hayas usado. Esto es a propósito. La mayor parte de la sintaxis es familiar para los
usuarios de Perl, Python, y Java (entre otros lenguajes), así que si has usado alguno de estos, aprender Ruby será muy fácil.
Este documento contiene dos secciones. La primera intenta ser un
resumen de lo que puedes esperar ver al aprender Ruby viniendo de
otro lenguaje. La segunda sección se enfoca en determinadas funcionalidades del lenguaje y cómo podrían compararse a lo que ya
puedas estar familiarizado.
Qué esperar: Lenguaje X a Ruby
A Ruby desde Java A Ruby desde PHP
Estamos en proceso de traducir todos estos artículos, pero mientras
lo hacemos no queremos privarte de que los leas en inglés:
To Ruby From C and C++ (en inglés) To Ruby From Java (en inglés)
To Ruby From Perl (en inglés) To Ruby From PHP (en inglés)
To Ruby From Python (en inglés)
Funcionalidades importantes del lenguaje y algunas advertencias
Aquí tienes algunas referencias y consejos sobre funcionalidades de Ruby que verás mientras lo aprendes.
Iteración
Dos funcionalidades de Ruby que se diferencian de lo que puedes haber visto previamente, y que toma cierto tiempo acostumbrarse a
ellas, son los ―bloques‖ e iteradores. En vez de recorrer un índice
(como con C, C++, o Java anterior al 1.5), o recorrer una lista (como
el for (@a) {...} de Perl, o for i in aList: ... en Python, con Ruby
verás muy frecuentemente código de este estilo:
una_lista.each do |este_item|
# Estamos dentro del bloque.
# Trabaja con este_item.
end
Para obtener más información sobre each (y sus amigos collect, find,
inject, sort, etc.), ejecuta ri Enumerable (y después ri
Enumerable#nombre_del_metodo).
Todo tiene un valor
No hay diferencia entre una expresión y un comando. Todo tiene un valor, incluso si ese valor es nil. Esto es posible:
x = 10
y = 11
z = if x < y
true
else
false
end
z # => true
Los symbols (símbolos) no son strings especiales
A muchos novatos en Ruby les cuesta entender qué son los symbols,
y qué utilidad pueden tener.
Los symbols pueden ser descritos como identidades. Lo importante de
un Symbol es quién es, no qué es. Arranca irb y experimenta la
diferencia:
irb(main):001:0> :jorge.object_id == :jorge.object_id
=> true
irb(main):002:0> "jorge".object_id == "jorge".object_id
=> false
irb(main):003:0>
El método object_id retorna la identidad de un objeto. Si dos objetos
tienen el mismo object_id, son el mismo objeto (apuntan al mismo
objeto en la memoria).
Como puedes ver, una vez que has usado un Symbol, cualquier otro
Symbol con los mismos caracteres referencia al mismo objeto en memoria. Para dos symbols que representan los mismos caracteres,
el object_id es el mismo.
Ahora veamos el String (―jorge‖). El object_id no es el mismo. Eso
significa que representan a dos objetos diferentes en memoria. Siempre que uses un nuevo String, Ruby reserva memoria para él.
Si tienes dudas sobre usar un Symbol o un String, considera qué es más importante: la identidad de un objeto (por ejemplo la Key de un
Hash), o el contenido (en nuestro ejemplo, ―jorge‖).
Todo es un objeto
―Todo es un objeto‖ no es una exageración. Incluso las clases y los
enteros son objetos, y puedes hacer con ellos las mismas cosas que con cualquier otro objeto:
# Esto es lo mismo que:
# class MiClase
# attr_accessor :variable_de_instancia
# end
MiClase = Class.new do
attr_accessor :variable_de_instancia
end
Constantes variables
Las constantes no son realmente… constantes. Si modificas una constante previamente inicializada, Ruby disparará una advertencia,
pero no detendrá tu programa. De todas formas, eso no quiere decir que deberías redefinir tus constantes.
Convenciones de sintaxis
Ruby impone algunas convenciones de sintaxis. Si un identificador comienza con una letra mayúscula, es una constante. Si comienza
con un símbolo de moneda ($), es una variable global. Si comienza
con @, es una variable de instancia. Si comienza con @@, es una
variable de clase.
Sin embargo, los nombres de los métodos tienen permitido comenzar
con letras mayúsculas. Esto puede confundirte, como muestra el siguiente ejemplo:
Constante = 10
def Constante
11
end
Ahora Constante vale 10, pero Constante() retorna 11.
Falsos parámetros nombrados
A diferencia de Python, Ruby no tiene parámetros nombrados. Sin
embargo, pueden ser emulados mediante el uso de symbols y hashes. Ruby on Rails, entre otros, usa esto a discreción. Por
ejemplo:
def parametros_con_nombre( params )
params
end
parametros_con_nombre( :param_uno => 10, :param_dos => 42 )
# => {:param_uno=>10, :param_dos=>42}
La verdad universal
En Ruby, todo excepto nil y false es considerado true. En C, Python
y muchos otros lenguajes, 0* y posiblemente otros valores, como listas vacías, son considerados *false. Examina el siguiente
código Python (el ejemplo aplica también a otros lenguajes):
# en Python
if 0:
print "0 es verdadero"
else:
print "0 es falso"
Esto imprimirá ―0 es falso‖. El equivalente en Ruby:
# en Ruby
if 0
puts "0 es verdadero"
else
puts "0 es falso"
end
Imprime ―0 es verdadero‖.
Los modificadores de acceso aplican hasta el fin del alcance
En el siguiente código Ruby,
class MiClase
private
def un_metodo; true; end
def otro_metodo; false; end
end
Puede ser que esperes que otro_metodo sea de alcance público. Esto
no es así. El modificador de acceso ‗private‘ continúa hasta el fin del
alcance, o hasta que aparezca un nuevo modificador de acceso, lo
que ocurra primero. Por defecto, los métodos son públicos:
class MiClase
# Ahora un_metodo es público
def un_metodo; true; end
private
# otro_metodo es privado
def otro_metodo; false; end
end
public, private y protected en realidad son métodos, así que pueden recibir
parámetros. Si pasas un símbolo a uno de ellos, la visibilidad de ese método
es alterada.
Acceso a los métodos
En Java, public significa que un método puede ser accedido por
cualquiera. protected significa que las instancias de la clase,
instancias de sus descendientes así como también de clases en el
mismo paquete, pueden accederlo, pero nadie más. Y private significa
que los métodos son accesibles únicamente desde las instancias de la
clase.
En Ruby esto es un poco diferente. public es, naturalmente, público.
private significa que los métodos son accesibles sólo cuando pueden
ser invocados sin un receptor explícito. Sólo self tiene permitido ser
el receptor de la invocación a un método privado.
Al que debemos estar atentos es a protected. Un método protegido
puede ser llamado desde una instancia de una clase o las instancias
de sus ancestros, pero también con otra instancia como su receptor.
Ejemplo, adaptado del Ruby FAQ:
$ irb
irb(main):001:0> class Test
irb(main):002:1> # public por defecto
irb(main):003:1* def func
irb(main):004:2> 99
irb(main):005:2> end
irb(main):006:1>
irb(main):007:1* def ==(otro)
irb(main):008:2> func == otro.func
irb(main):009:2> end
irb(main):010:1> end
=> nil
irb(main):011:0>
irb(main):012:0* t1 = Test.new
=> #<Test:0x34ab50>
irb(main):013:0> t2 = Test.new
=> #<Test:0x342784>
irb(main):014:0> t1 == t2
=> true
irb(main):015:0> # ahora haz 'func' protected, todavía funciona
irb(main):016:0* # porque protected permite la otra referencia
irb(main):017:0* class Test
irb(main):018:1> protected :func
irb(main):019:1> end
=> Test
irb(main):020:0> t1 == t2
=> true
irb(main):021:0> # ahora haz 'func' private
irb(main):022:0* class Test
irb(main):023:1> private :func
irb(main):024:1> end
=> Test
irb(main):025:0> t1 == t2
NoMethodError: private method `func' called for #<Test:0x342784>
from (irb):8:in `=='
from (irb):25
from :0
irb(main):026:0>
Las clases están abiertas
Las clases de Ruby están abiertas.Puedes abrirlas, agregarles
funcionalidad, y modificarlas en cualquier momento. Incluso las
clases principales, como Fixnum o incluso Object, el padre de todos los
objetos. Ruby on Rails define un montón de métodos para menejar el
tiempo y los horarios en Fixnum. Mira:
class Fixnum
def hours
self * 3600 # cantidad de segundos en una hora
end
alias hour hours
end
# 14 horas desde las 00:00 del 1ro de enero del 2006
Time.mktime(2006, 01, 01) + 14.hours # => Sun Jan 01 14:00:00
Nombres de métodos graciosos
En Ruby, los métodos tienen permitido terminar en signos de
exclamación o interrogación. Por convención, los métodos que
responden preguntas (i.e. Array#empty? retorna true si el receptor
está vacío) terminan con un signo de interrogación. Métodos potencialmente ―peligrosos‖ (i.e. métodos que modifican self o sus
argumentos, exit! etc.) por convención terminan en un signo de
exclamación.
De todas formas, no todos los métodos que modifican sus
argumentos terminan en signos de exclamación. Array#replace
reemplaza el contenido de un array co nel contenido de otro array.
No tiene mucho sentido tener un método como ese que no modifique
self.
Los métodos Singleton
Los métodos Singleton son métodos-por-objeto. Sólo están disponibles en el objeto en el que los defines.
class Automovil
def inspect
"Auto barato"
end
end
porsche = Automovil.new
porsche.inspect # => Auto barato
def porsche.inspect
"Auto muy caro"
end
porsche.inspect # => Auto muy caro
# Otros objetos no son afectados
otro_auto = Automovil.new
otro_auto.inspect # => Auto barato
Métodos faltantes
Ruby no se rinde si no puede encontrar un método que responda a un
mensaje en particular. Llama al método method_missing con el nómbre
del método que no pudo encontrar y sus argumentos. Por defecto,
method_missing lanza una excepción NameError, pero puedes
redefinirlo para que se ajuste mejor a tu aplicación, y muchas bibliotecas lo hacen. Aquí tienes un ejemplo:
# id es el nombre del método invocado, la sintaxis * recolecta
# todos los argumentos en un array llamado 'argumentos'
def method_missing( id, *argumentos )
puts "El método #{id} fue invocado, pero no existe. Tiene" +
"estos argumentos: #{argumentos.join(", ")}"
end
__ :a, :b, 10
# => El método __ fue invocado, pero no existe. Tiene estos
# argumentos: a, b, 10
Este código sólo imprime los detalles de la invocación, pero eres libre de manejar el mensaje como te parezca más apropiado.
Pasaje de mensajes, no llamadas a funciones
Una invocación a un método en realidad es un mensaje a otro
objeto:
# Esto
1 + 2
# Es lo mismo que esto ...
1.+(2)
# Que es lo mismo que esto:
1.send "+", 2
Los bloques son objetos, sólo que todavía no lo saben
Los bloques (cierres en realidad) son muy utilizados por la biblioteca
estandar. Para llamar a un bloque, puedes usar yield, o transformarlo
en un Proc al anexarle un parámetro especial a la lista de
argumentos, así:
def block( &el_bloque )
# Aquí dentro, el_bloque es el bloque pasado al método
el_bloque # retornar el bloque
end
sumador = block { |a, b| a + b }
# sumador ahora es un objeto Proc
sumador.class # => Proc
También puedes crear bloques fuera de las invocaciones a métodos,
utilizando Proc.new con un bloque o llamando al método lambda.
Similarmente, los métodos también pueden ser objetos:
method(:puts).call "¡puts es un objeto!"
# => ¡puts es un objeto!
Los operadores son comodidades sintácticas
La mayoría de los operadores en Ruby son simples simplificaciones
sintácticas (con algunas reglas de precedencia) para llamar a ciertos
métodos. Puedes, por ejemplo, redefinir el método Fixnum#+:
class Fixnum
# Puedes, pero por favor no lo hagas
def +( otro )
self - otro
end
end
No necesitas eloperator+ de C++, etc.
Incluso puedes tener acceso estilo array si defines los métodos [] y
[]=. Para definir los métodos unarios + y – (piensa en +1 y -2),
debes definir los métodos +@ and -@ respectivamente.
Sin embargo, los siguientes operadores no son simplificaciones
sintácticas. No son métodos, y no pueden ser redefinidos:
=, .., ..., !, not, &&, and, ||, or, !=, !~, ::
Además, +=, *= etc. sólo son abreviaciones para var = var + otra_var, var
= var * otra_var, etc. y por ende no pueden ser redefinidos.
Para saber más
Cuando estés listo para saber más sobre Ruby, visita nuestra sección
de Documentación.
Ruby es…
Un lenguaje de programación dinámico y de código abierto enfocado en la simplicidad y productividad. Su elegante sintaxis se siente natural al leerla y fácil al escribirla.
Leer más…
# Output "I love Ruby"
say = "I love Ruby"
puts say
# Output "I *LOVE* RUBY"
say['love'] = "*love*"
puts say.upcase
# Output "I *love* Ruby"
# five times
5.times { puts say }