05. Más Sobre Métodos
Hasta ahora hemos visto un montón de métodos diferentes, puts y gets entre otros (Prueba Sorpresa: ¡Lista todos los métodos que hemos visto hasta ahora! Había diez de ellos; la respuesta está más abajo.), pero realmente no hemos hablado de qué son los métodos. Sabemos lo que hacen, pero no sabemos lo que son.
Pero en realidad, eso es lo que son: cosas que hacen cosas. Si los objetos (como strings, enteros y floats) son los sustantivos en el lenguaje Ruby, entonces los métodos son como los verbos. Y, a diferencia del español (donde hay sujetos tácitos y otras construcciones esotéricas), no puedes tener un verbo sin un sustantivo para realizar el verbo. Pero incluso el español trata la ausencia de un sustantivo como una excepción: por ejemplo, marcar el tiempo no es algo que simplemente sucede; un reloj (o un cronómetro, o algo similar) tiene que hacerlo. En español diríamos: "El reloj marca el tiempo". En Ruby decimos reloj.marcar (asumiendo que reloj es un objeto Ruby, claro). Los programadores podrían decir que estamos "llamando al método marcar en reloj," o que "llamamos a marcar en reloj."
Entonces, ¿hiciste la prueba? Bien. Bueno, estoy seguro de que recordaste los métodos puts, gets y chomp que acabamos de ver. También probablemente recordaste los métodos de conversión, to_i, to_f y to_s. Sin embargo, ¿conseguiste los otros cuatro? ¡Pues no eran otros que nuestros viejos amigos de la aritmética, +, -, * y /!
Como decía, cada método necesita un objeto. Por lo general, es fácil decir qué objeto está ejecutando el método: es lo que viene justo antes del punto, como en nuestro ejemplo de reloj.marcar, o en 101.to_s. A veces, sin embargo, no es tan obvio; como con los métodos aritméticos. De hecho, 5 + 5 es realmente solo un atajo para escribir 5.+ 5. Por ejemplo:
puts 'hola '.+ 'mundo'
puts (10.* 9).+ 9
hola mundo
99
No es muy bonito, así que nunca lo escribiremos así; sin embargo, es importante entender lo que realmente está sucediendo. (En mi máquina, esto también me da una advertencia: warning: parenthesize argument(s) for future version. El código aún se ejecutó bien, pero me dice que tiene problemas para averiguar lo que quise decir, y me pide que use más paréntesis en el futuro). Esto también nos da una comprensión más profunda de por qué podemos hacer 'cerdo'*5 pero no 5*'cerdo': 'cerdo'*5 le está diciendo a 'cerdo' que haga la multiplicación, pero 5*'cerdo' le está pidiendo a 5 que haga la multiplicación. 'cerdo' sabe cómo hacer 5 copias de sí mismo y sumarlas; sin embargo, 5 tendrá mucho más dificultades para hacer 'cerdo' copias de sí mismo y sumarlas.
Y, por supuesto, todavía tenemos puts y gets para explicar. ¿Dónde están sus objetos? En español, a veces puedes omitir el sustantivo; por ejemplo, si un villano grita "¡Muere!", el sustantivo implícito es la persona a la que le está gritando. En Ruby, si digo puts 'ser o no ser', lo que realmente estoy diciendo es self.puts 'ser o no ser'. Entonces, ¿qué es self? Es una variable especial que apunta al objeto en el que te encuentras actualmente. Ni siquiera sabemos cómo estar en un objeto todavía, pero hasta que lo averigüemos, siempre estamos en un gran objeto que es... ¡todo el programa! Y por suerte, el programa tiene algunos métodos propios, como puts y gets. Mira esto:
noPuedoCreerQueHiceUnNombreDeVariableTanLargoSoloParaGuardarUn3 = 3
puts noPuedoCreerQueHiceUnNombreDeVariableTanLargoSoloParaGuardarUn3
self.puts noPuedoCreerQueHiceUnNombreDeVariableTanLargoSoloParaGuardarUn3
3
3
Si no seguiste todo eso, está bien. Lo importante que debes sacar de esto es que cada método está siendo realizado por algún objeto, incluso si no está justo frente a ti. Si entiendes eso, entonces estás listo.
Métodos Elegantes de String
Vamos a aprender algunos métodos divertidos de string. No tienes que memorizarlos todos; simplemente puedes mirar esta página de nuevo si los olvidas. Solo quiero mostrarte una pequeña parte de lo que las strings pueden hacer. De hecho, yo mismo no recuerdo ni la mitad de los métodos de string, pero eso está bien, porque hay excelentes referencias en internet con todos los métodos de string listados y explicados. (Te mostraré dónde encontrarlos al final de este tutorial.) Para ser honesto, ni siquiera quiero saber todos los métodos de string; es como saber cada palabra en el diccionario. Puedo hablar español perfectamente bien sin saber cada palabra en el diccionario... ¿y no es ese el punto? ¿Que no tienes que saber todo lo que hay en él?
Entonces, nuestro primer método de string es reverse, que nos da una versión al revés de la string:
var1 = 'parar'
var2 = 'radar'
var3 = '¿Puedes pronunciar esta frase al reves?'
puts var1.reverse
puts var2.reverse
puts var3.reverse
puts var1
puts var2
puts var3
rarap
radar
?sever la esarf atse raicnunorp sedeuP¿
parar
radar
¿Puedes pronunciar esta frase al reves?
Como puedes ver, reverse no invierte la string original; simplemente hace una nueva versión al revés de ella. Es por eso que var1 sigue siendo 'parar' incluso después de llamar a reverse en var1.
Otro método de string es length, que nos dice el número de caracteres (incluyendo espacios) en la string:
puts '¿Cuál es tu nombre completo?'
nombre = gets.chomp
puts '¿Sabías que hay ' + nombre.length + ' caracteres en tu nombre, ' + nombre + '?'
¿Cuál es tu nombre completo?
Christopher David Pine
#<TypeError: can't convert Fixnum into String>
¡Uh-oh! Algo salió mal, y parece que sucedió después de la línea nombre = gets.chomp... ¿Ves el problema? Mira si puedes averiguarlo.
El problema es con length: te da un número, pero queremos una string. Bastante fácil, vamos a poner un to_s (y cruzar los dedos):
puts '¿Cuál es tu nombre completo?'
nombre = gets.chomp
puts '¿Sabías que hay ' + nombre.length.to_s + ' caracteres en tu nombre, ' + nombre + '?'
¿Cuál es tu nombre completo?
Christopher David Pine
¿Sabías que hay 22 caracteres en tu nombre, Christopher David Pine?
No, no lo sabía. Nota: este es el número de caracteres en mi nombre, no el número de letras (cuéntalas). Supongo que podríamos escribir un programa que pregunte por tu nombre, segundo nombre y apellido individualmente, y luego sume esas longitudes... Oye, ¿por qué no haces eso? Adelante, esperaré.
¿Listo? ¡Bien! Es un buen programa, ¿no? Después de unos capítulos más, sin embargo, te sorprenderás de lo que puedes hacer.
También hay una serie de métodos de string que cambian el caso (mayúsculas y minúsculas) de tu string. upcase cambia cada letra minúscula a mayúscula, y downcase cambia cada letra mayúscula a minúscula. swapcase cambia el caso de cada letra en la string, y finalmente, capitalize es igual que downcase, excepto que cambia el primer carácter a mayúscula (si es una letra).
letras = 'aAbBcCdDeE'
puts letras.upcase
puts letras.downcase
puts letras.swapcase
puts letras.capitalize
puts ' a'.capitalize
puts letras
AABBCCDDEE
aabbccddee
AaBbCcDdEe
Aabbccddee
a
aAbBcCdDeE
Cosas bastante estándar. Como puedes ver en la línea puts ' a'.capitalize, el método capitalize solo pone en mayúscula el primer carácter, no la primera letra. Además, como hemos visto antes, a lo largo de todas estas llamadas a métodos, letras permanece sin cambios. No quiero insistir en el punto, pero es importante entenderlo. Hay algunos métodos que sí cambian el objeto asociado, pero aún no hemos visto ninguno, y no lo haremos por algún tiempo.
El último de los métodos elegantes de string que veremos es para el formato visual. El primero, center, agrega espacios al principio y al final de la string para centrarla. Sin embargo, al igual que tienes que decirle a puts lo que quieres que imprima, y a + lo que quieres que sume, tienes que decirle a center qué tan ancha quieres que sea tu string centrada. Así que si quisiera centrar las líneas de un poema, lo haría así:
anchoDeLinea = 50
puts( 'Old Mother Hubbard'.center(anchoDeLinea))
puts( 'Sat in her cupboard'.center(anchoDeLinea))
puts( 'Eating her curds an whey,'.center(anchoDeLinea))
puts( 'When along came a spider'.center(anchoDeLinea))
puts( 'Which sat down beside her'.center(anchoDeLinea))
puts('And scared her poor shoe dog away.'.center(anchoDeLinea))
Old Mother Hubbard
Sat in her cupboard
Eating her curds an whey,
When along came a spider
Which sat down beside her
And scared her poor shoe dog away.
Hmm... No creo que así sea la rima infantil, pero soy demasiado perezoso para buscarla. (Además, quería alinear la parte de .center anchoDeLinea, así que puse esos espacios extra antes de las strings. Esto es solo porque creo que se ve más bonito. Los programadores a menudo tienen opiniones fuertes sobre lo que es bonito en un programa, y a menudo no están de acuerdo al respecto. Cuanto más programes, más desarrollarás tu propio estilo). Hablando de ser perezoso, la pereza no siempre es algo malo en la programación. Por ejemplo, ¿viste cómo guardé el ancho del poema en la variable anchoDeLinea? Lo hice para que si quiero hacer el poema más ancho más tarde, solo tenga que cambiar la línea superior del programa, en lugar de cada línea que hace el centrado. Con un poema muy largo, esto podría ahorrarme mucho tiempo. Ese tipo de pereza es realmente una virtud en la programación.
Entonces, sobre ese centrado... habrás notado que no es tan hermoso como lo habría hecho un procesador de textos. Si realmente quieres un centrado perfecto (y tal vez una fuente más bonita), ¡entonces deberías usar un procesador de textos! Ruby es una herramienta maravillosa, pero ninguna herramienta es la herramienta adecuada para cada trabajo.
Los otros dos métodos de formato de string son ljust y rjust, que significan justificar a la izquierda y justificar a la derecha. Son similares a center, excepto que rellenan la string con espacios a la derecha y a la izquierda, respectivamente. Veamos los tres en acción:
anchoDeLinea = 40
str = '--> texto <--'
puts str.ljust anchoDeLinea
puts str.center anchoDeLinea
puts str.rjust anchoDeLinea
puts str.ljust (anchoDeLinea/2) + str.rjust (anchoDeLinea/2)
--> texto <--
--> texto <--
--> texto <--
--> texto <-- --> texto <--
Algunas Cositas Para Probar
- Escribe un programa del Jefe Enojado. Debe preguntar groseramente qué quieres. Sea lo que sea que respondas, el Jefe Enojado debe gritarte de vuelta y luego despedirte. Por ejemplo, si escribes
Quiero un aumento., debe gritarte¿QUÉ QUIERES DECIR CON "QUIERO UN AUMENTO."?!? ¡¡ESTÁS DESPEDIDO!! - Aquí hay algo para que hagas para jugar más con
center,ljustyrjust: Escribe un programa que muestre una Tabla de Contenidos para que se vea así:
Tabla de Contenidos
Capítulo 1: Números página 1
Capítulo 2: Letras página 72
Capítulo 3: Variables página 118
Matemáticas Superiores
(Esta sección es completamente opcional. Asume cierto nivel de conocimiento matemático. Si no estás interesado, puedes ir directamente al Control de Flujo sin ningún problema. Sin embargo, un vistazo rápido a la sección de Números Aleatorios podría ser útil.)
No hay tantos métodos numéricos como métodos de string (aunque todavía no los he memorizado todos). Aquí, veremos el resto de los métodos aritméticos, un generador de números aleatorios y el objeto Math, con sus métodos trigonométricos y trascendentales.
Más Aritmética
Los otros dos métodos aritméticos son ** (exponenciación) y % (módulo). Así que si quisieras decir "cinco al cuadrado" en Ruby, escribirías 5**2. También puedes usar floats para tu exponente, así que si quieres la raíz cuadrada de 5, puedes escribir 5**0.5. El método módulo te da el resto después de la división por un número. Así que, por ejemplo, si divido 7 por 3, obtengo 2 con un resto de 1. Veámoslos en acción en un programa:
puts 5**2
puts 5**0.5
puts 7/3
puts 7%3
puts 365%7
25
2.23606797749979
2
1
1
De esa última línea, aprendemos que un año (no bisiesto) tiene un cierto número de semanas, más un día. Así que si tu cumpleaños fue un martes este año, será un miércoles el próximo año. También puedes usar floats con el método módulo. Básicamente funciona de la única manera razonable que puede... pero dejaré que juegues con eso.
Hay un último método para mencionar antes de ver el generador de números aleatorios: abs. Simplemente toma el valor absoluto del número:
puts((5-2).abs)
puts((2-5).abs)
3
3
Números Aleatorios
Ruby viene con un generador de números aleatorios bastante bueno. El método para obtener un número elegido al azar es rand. Si llamas a rand simplemente así, obtienes un float mayor o igual a 0.0 y menor que 1.0. Si le das a rand un entero (5 por ejemplo), te dará un entero mayor o igual a 0 y menor que 5 (así que cinco números posibles, de 0 a 4).
Veamos rand en acción. (Si recargas esta página, estos números cambiarán cada vez. Sabías que en realidad estaba ejecutando estos programas, ¿verdad?)
puts rand
puts rand
puts rand
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(1))
puts(rand(1))
puts(rand(1))
puts(rand(99999999999999999999999999999999999999999999999999999999999))
puts('El meteorólogo dijo que hay un '+rand(101).to_s+'% de probabilidad de lluvia,')
puts('pero nunca puedes confiar en un meteorólogo.')
0.533099438199271
0.692927743758217
0.940976910494312
35
25
43
0
0
0
43268570703742641064840128301077341089498686011220522458380
El meteorólogo dijo que hay un 42% de probabilidad de lluvia,
pero nunca puedes confiar en un meteorólogo.
Observa que usé rand(101) para obtener números del 0 al 100, y que rand(1) siempre devuelve 0. No entender el rango de posibles valores devueltos es el mayor error que veo que comete la gente con rand; incluso programadores profesionales; incluso en productos terminados que puedes comprar en la tienda. Una vez tuve un reproductor de CD que, si se configuraba en "Reproducción Aleatoria", reproducía todas las canciones menos la última... (Me pregunto qué pasaría si pusieras un CD con solo una canción en él).
A veces es posible que desees que rand devuelva los mismos números aleatorios en la misma secuencia en dos ejecuciones diferentes de tu programa. (Por ejemplo, una vez estaba usando números aleatorios para generar un mundo generado aleatoriamente en un juego de computadora. Si encontraba un mundo que realmente me gustaba, tal vez querría jugarlo de nuevo, o enviárselo a un amigo). Para hacer esto, necesitas establecer la semilla (seed), lo cual puedes hacer con srand. Así:
srand 1776
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts ''
srand 1776
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
puts(rand(100))
24
35
36
58
70
24
35
36
58
70
Hará lo mismo cada vez que lo siembres con el mismo número. Si quieres obtener números diferentes de nuevo (como sucede si nunca usas srand), entonces simplemente llama a srand 0. Esto lo siembra con un número realmente extraño, usando (entre otras cosas) la hora actual en tu computadora, hasta el milisegundo.
El Objeto Math
Finalmente, veamos el objeto Math. Vamos a saltar directamente:
puts(Math::PI)
puts(Math::E)
puts(Math.cos(Math::PI/3))
puts(Math.tan(Math::PI/4))
puts(Math.log(Math::E**2))
puts((1 + Math.sqrt(5))/2)
3.14159265358979
2.71828182845905
0.5
1.0
2.0
1.61803398874989
Lo primero que notaste fue probablemente la notación ::. Explicar el operador de ámbito (que es lo que es) está un poco más allá del, eh... alcance de este tutorial. Sin juego de palabras. Lo juro. Baste decir que puedes usar Math::PI tal como esperas.
Como puedes ver, Math tiene todas las cosas que esperarías que tuviera una calculadora científica decente. Y como siempre, los floats están realmente cerca de ser las respuestas correctas.
¡Así que entremos en el flujo!