|
|||
if,
asignaciones, y otros detalles, es difícil escribir ejemplos
de clases. A lo largo de nuestra descripción de arriba a abajo,
nos encontramos atravesando detalles de bajo nivel que necesitábamos cubrir para que
los ejemplos pudiesen tener sentido.
Así que nosotros trajimos un nuevo gran planta (no nos llaman
pragmáticos por nada). Describiríamos Ruby empezando por arriba. Pero
antes de hacerlo, añadiríamos un corto capítulo que describiese todas
las características comunes del lenguaje utilizadas a lo largo
de los ejemplos con el vocabulario especial de Ruby, un tipo de
minitutorial para iniciarnos en el resto del libro.
Cancion,
tendrías instancias para exitos populares como ``Ruby Tuesday,'' ``Enveloped in Python,''
``String of Pearls,'' ``Small talk,'' y así. La palabra
objeto es utilizada de manera indistinta con instancia de clase
(y siendo mecanógrafos perezosos, utilizaremos la palabra ``objeto''
más frecuentemente).
En Ruby, esos objetos son creados mediante la llamada a un constructor,
un método especial asociado con un clase. El constructor estándar es
llamado new.
song1 = Song.new("Ruby Tuesday")
song2 = Song.new("Enveloped in Python")
# and so on
|
"gin joint".length
|
» |
9
|
"Rick".index("c")
|
» |
2
|
-1942.abs
|
» |
1942
|
sam.play(aSong)
|
» |
"duh dum, da dum de dum ..."
|
number = Math.abs(number) // Java code |
abs al número y le dejas
hacer el trabajo.
number = number.abs |
strlen(name), mientras que en Ruby es name.lenght, y
así. Esto es parte de lo que queremos decir cuando decimos que Ruby
es un genuino lenguaje orientado a objetos.
def sayGoodnight(name)
result = "Goodnight, " + name
return result
end
# Time for bed...
puts sayGoodnight("John-Boy")
puts sayGoodnight("Mary-Ellen")
|
# y llegan hasta el final de la línea. La
distribución del código queda a tu elección; la indentación no es
significante.
Los métodos se definen con la palabra clave def, seguido
por el nombre del método (en este caso, ``sayGoddnight'') y
los parámetros del método entre paréntesis. Ruby no utiliza llaves para
delimitar los cuerpos de sentencias y definiciones compuestas. En cambio,
se finaliza simplemente finalizando el cuerpo con la palabra clave end.
El cuerpo de nuestro método es bastante simple. La primera línea concatena la
cadena literal ``Goodnight, '' al parametro name y
asigna el resultado a la variable local result. La siguiente línea devuelve el
resultado al invocador. Hay que darse cuenta que no declaramos la variable result;
comienza su existencia cuando la asignamos.
Una vez definido el método, nosotros lo llamados dos veces. En ambos casos
le pasamos el resultado al método puts, el cual simplemente
muestra su argumento seguido por una nueva línea.
Goodnight, John-Boy Goodnight, Mary-Ellen |
puts sayGoodnight("John-Boy")'' contiene dos llamadas a métodos,
una a sayGoodnight y la otra a puts. ¿Por qué una llamada tiene
sus argumentos entre paréntesis y la otra no? En este caso es simplemente un tema de
gusto personal. Las siguientes líneas son equivalentes.
puts sayGoodnight "John-Boy"
puts sayGoodnight("John-Boy")
puts(sayGoodnight "John-Boy")
puts(sayGoodnight("John-Boy"))
|
\n,
que es reemplazado con un carácter de línea nueva.
Cuando una cadena contiene una nueva línea, el ``\n fuerza
la ruptura de la línea.
puts "And Goodnight,\nGrandma" |
And Goodnight, Grandma |
#{
expresión
} es remplazada por el valor de
expresión. Podemos utilizar esto para rescribir el método previo.
def sayGoodnight(name)
result = "Goodnight, #{name}"
return result
end
|
name y lo sustituye dentro de la cadena. Expresiones
arbitrariamente complejas están permitidas en la construcción #{...}. Como
atajo, no necesitas utilizar llaves cuando la expresión es simplemente una
variable global, de instancia o de clase. Para más información sobre cadenas,
así como otros tipos estándar de Ruby, revisa el Capítulo 5, que comienza en la
pagina 47.
Finalmente, podemos simplificar este método algo más. El valor retornado
por un método en Ruby es el valor de la última expresión evaluada, así que
podemos deshacernos de la sentencia return entera.
def sayGoodnight(name)
"Goodnight, #{name}"
end
|
Example variable and class names
|
||||||||||||||||||||||||||||||||||||||||||||
a = [ 1, 'cat', 3.14 ] # array with three elements
|
||
# access the first element
|
||
a[0]
|
» |
1
|
# set the third element
|
||
a[2] = nil
|
||
# dump out the array
|
||
a
|
» |
[1, "cat", nil]
|
Array.new
.
empty1 = [] empty2 = Array.new |
%w
hace lo que nosotros queremos.
a = %w{ ant bee cat dog elk }
|
||
a[0]
|
» |
"ant"
|
a[3]
|
» |
"dog"
|
instSection = {
'cello' => 'string',
'clarinet' => 'woodwind',
'drum' => 'percussion',
'oboe' => 'woodwind',
'trumpet' => 'brass',
'violin' => 'string'
}
|
instSection['oboe']
|
» |
"woodwind"
|
instSection['cello']
|
» |
"string"
|
instSection['bassoon']
|
» |
nil
|
nil
cuando es indexado por una clave que no contiene. Normalmente esto es
conveniente ya que nil significa false cuando es utilizado
en expresiones condicionales. Algunas veces querrás cambiar este comportamiento
por defecto. Por ejemplo, si estás utilizando una tabla hash para contar
el número de veces que cada clave se repite, es conveniente tener el valor
por defecto a cero. Esto se consigue fácilmente especificando el valor por defecto
cuando creas una nueva tabla hash vacía.
histogram = Hash.new(0)
|
||
histogram['key1']
|
» |
0
|
histogram['key1'] = histogram['key1'] + 1
|
||
histogram['key1']
|
» |
1
|
if
y bucles while. Los programadores Java, C y Perl podrían verse sorprendidos
por la falta de llaves delimitando los cuerpos de esas cláusulas. A cambio,
Ruby utiliza la palabra clave end que delimita el final de un cuerpo.
if count > 10 puts "Try again" elsif tries == 3 puts "You lose" else puts "Enter a number" end |
while statements are terminated with end.
while weight < 100 and numPallets <= 30 pallet = nextPallet() weight += pallet.weight numPallets += 1 end |
if o while es una única expresión. Simplemente
escribe la expresión, seguida de if o while y la condición.
Por ejemplo, aquí tenemos una sencilla sentencia if.
if radiation > 3000 puts "Danger, Will Robinson" end |
puts "Danger, Will Robinson" if radiation > 3000 |
while
while square < 1000 square = square*square end |
square = square*square while square < 1000 |
/Perl|Python/ |
|'').
Se pueden utilizar paréntesis dentro de los patrones, como lo harías en
expresiones aritméticas, así que puedes escribir patrones como
/P(erl|ython)/ |
/ab+c/ encaja en una
cadena que contiene una ``a'' seguida por una o más ``b'', seguida por una ``c''.
Cambia el ``+'' por un ``*'', y /ab*c/ crea una
expresión regular que compara una ``a'', cero o más ``b'', y una ``c''.
También puedes comparar uno de un grupo de caracteres dentro de un patrón.
Algunos ejemplos corrientes son clases carácter como ``\s'', los cuales
encajan un carácter espacio en blanco (espacio, tabulador, nueva linea y demás),
``\d'', que encaja con cualquier dígito, y ``\w'', que encaja
con cualquier carácter que pudiera aparecer en una palabra. El carácter``.'' (punto)
encaja con cualquier carácter.
Podemos poner todo esto junto para producir algunas expresiones regulares útiles.
/\d\d:\d\d:\d\d/ # a time such as 12:34:56 /Perl.*Python/ # Perl, zero or more other chars, then Python /Perl\s+Python/ # Perl, one or more spaces, then Python /Ruby (Perl|Python)/ # Ruby, a space, and either Perl or Python |
=~'' puede ser utlizado para comparar una cadena
contra una expresión regular. Si el patrón es encontrado en la cadena, =~
devuelve su posición de comienzo, en otro caso devuelve nil. Esto
significa que puedes utilizar una expresión regular como condición en una clasula
if o while. Por ejemplo, el siguiente fragmento de código
escribe un emsenaje si la cadena contiene el texto 'Perl' o 'Python'.
if line =~ /Perl|Python/
puts "Scripting language mentioned: #{line}"
end
|
line.sub(/Perl/, 'Ruby') # replace first 'Perl' with 'Ruby' line.gsub(/Python/, 'Ruby') # replace every 'Python' with 'Ruby' |
do...end.
{ puts "Hello" } # this is a block
do #
club.enroll(person) # and so is this
person.socialize #
end #
|
yield. El siguiente
ejemplo muestra esto en acción. Definimos un método que llama a yield
dos veces. Entonces lo llamamos, poniendo un bloque en la misma línea,
después de la llamada (y después de cualquier argumento al método).
[Alguna gente le gusta pensar en la asociación de un bloque
con un método como el paso de algún tipo de parámetro. Esto función
en un nivel, pero no es realmente toda la historia. Podrías pensar
mejor en el bloque y el método como corrutinas, que se transfieren el
control entre si.]
def callBlock
yield
yield
end
callBlock { puts "In the block" }
|
In the block In the block |
puts "In the block") es ejecutado
dos veces, una por cada llamada a yield.
Puedes proporcionar parámetros a la llamada a yield:
estos parámetros serán pasados al bloque. Dentro del bloque, tu listas
los nombres de los argumentos para recibir esos parámetros entre barras
verticales (``|'').
def callBlock
yield ,
end
callBlock { |, | ... }
|
a = %w( ant bee cat dog elk ) # create an array
a.each { |animal| puts animal } # iterate over the contents
|
ant bee cat dog elk |
each de la clase
Array
que hemos utilizado en el ejemplo previo. El iterador each recorre cada elemento en el array,
llamando a yield para cada uno. En pseudocódigo, esto podría ser como:
# within class Array... def each for each element yield(element) end end |
each y proporcionando un bloque. El bloque sería llamado por
cada elemento.
[ 'cat', 'dog', 'horse' ].each do |animal| print animal, " -- " end |
cat -- dog -- horse -- |
5.times { print "*" }
3.upto(6) {|i| print i }
('a'..'e').each {|char| print char }
|
*****3456abcde |
each.
puts escribe cada uno de sus argumentos, añadiendo
una carácter de nueva línea después de cada uno. print también
escribe sus argumentos, pero sin nueva línea. Ambos pueden ser utilizados
para escribir a cualquier objeto E/S, pero suelen escribir a la consola.
Otro método de salida que utilizamos mucho es printf, el
cual imprime sus argumentos bajo el control de una cadena de formato (como
printf en C o Perl).
printf "Number: %5.2f, String: %s", 1.23, "hello" |
Number: 1.23, String: hello |
"Number: %5.2f, String: %s"
le dice al método printf que sustituya un número en coma flotante
(permitiendo cinco caracteres en total, con dos después del punto decimal) y una
cadena.
Hay muchas maneras de leer la entrada en tu programa. Probablemente la más
tradicional es utilizando la rutina gets, que devuelve la
siguiente línea desde el flujo de entra estándar de tu programa.
line = gets print line |
gets tiene un efecto secundario: así como devuelve
la línea recién leida, también la almacena den la variable global
$_. Esta variable es especial, en el aspecto de que es usada
como argumento por defecto en algunas circunstancias. Si llamas a print
sin argumentos, imprime el contenido de $_. Si escribes una condición if
o sencencia while con justamente una expresión regular como condición,
esa expresión es validada contra $_. Mientras que esto es visto
por algunos purista como barbaridad, estas abreviaturas pueden
ayudarte a escribir algunos programas concisos. Por ejemplo, el siguiente
programa imprime todas las lineas del flujo de entrada que contienen la palabra
``Ruby.''
while gets # assigns line to $_ if /Ruby/ # matches against $_ print # prints $_ end end |
ARGF.each { |line| print line if line =~ /Ruby/ }
|
ARGF, que representa el
flujo de entrada que puede ser leido por un programa.