Métodos

Eventualmente vas tener algunas líneas de código que necesitan ser ejecutadas varias veces y desde diferentes partes de tu programa. En vez de repetir el mismo código una y otra vez puedes crear un método (también se les conoce como procedimientos o funciones en otros lenguajes de programación) e invocarlo cada vez que necesites ejecutar ese trozo de código.

Crea un archivo llamado methods.rb y escribe lo siguiente:

def hello
  puts "Hola mundo"
end

Para definir un método usamos la palabra reservada def y le damos un nombre (en este caso hello). Al final debemos cerrar el método con end.

$ ruby methods.rb

Si lo ejecutas no debería salir nada. Una característica de los métodos es que no son ejecutados hasta que no los invoquemos. Modifiquemos nuestro programa para invocarlo:

def hello
  puts "Hola mundo"
end

hello() # acá lo invocamos, los paréntesis son opcionales

En la última línea lo estamos invocando. Si lo ejecutas ahora si debería aparecer "Hola mundo":

$ ruby methods.rb
Hola mundo

Parámetros

Los métodos pueden recibir cero o más parámetros (o argumentos). Modifiquemos nuestro programa para que salude a cualquier persona:

def hello(name)
  puts "Hola #{name}"
end

hello("Germán")
hello("David")

Si lo ejecutamos deberías ver lo siguiente:

$ ruby methods.rb
Hola Germán
Hola David

Retornando un valor

En Ruby todas las expresiones retornan un valor. Incluso puts "Hola mundo" retorna un valor, solo que el valor es nil (una forma de decir "nada").

Por defecto, todos los métodos retornan el resultado de la última línea que se ejecute en el método. Vamos a modificar nuestro ejemplo para que en vez de imprimir el saludo, lo retorne:

def hello(name)
  "Hola #{name}"
end

puts hello("Germán")
puts hello "David"  # los paréntesis son opcionales

Fíjate que ya no hacemos el puts dentro de la función, así que nos toca hacerlo al invocar el método. Pero es mejor práctica así. El problema es que cuando el puts está dentro de la función, esa función solo nos serviría en aplicaciones de consola. Si la queremos usar en una aplicación Web no serviría (el puts es únicamente para imprimir en la consola).

$ ruby methods.rb
Hola Germán
Hola David

También es posible retornar el valor explícitamente con la palabra reservada return:

def hello(name)
  return "Hola #{name}"
end

puts hello("Germán")
puts hello "David"

El resultado cuando lo ejecutes debe seguir siendo el mismo.

En general, los programadores de Ruby tienden a omitir el return a menos de que sea completamente necesario.

Un ejemplo

Hagamos un programa que nos diga de qué generación somos dependiendo de nuestro año de nacimiento. Las generaciones son las siguientes:

Nacidos <= 1945 - la gran generación
Nacidos entre 1946 y 1964 - baby boomers
Nacidos entre 1965 y 1982 - generación x
Nacidos entre 1983 y 2004 - milenials
Nacidos >= 2005 - centenials

Vamos ahora a hacer un método que nos diga la generación y lo invocamos con lo que ingrese el usuario. Crea un archivo llamado generation_method.rb y escribe lo siguiente:

def generation(year_of_birth)
  if year_of_birth >= 1996
    puts "Eres un centenial"
  elsif year_of_birth >= 1977
    puts "Eres un millenial"
  elsif year_of_birth >= 1965
    puts "Eres generación X"
  elsif year_of_birth >= 1946
    puts "Eres baby boomer"
  else
    puts "Eres tradicionalista"
  end
end

print "¿Cuál es tu año de nacimiento? "
year_of_birth = gets.chomp.to_i
generation(year_of_birth)

Si la ejecutas debería decirte la generación dependiendo de tu año de nacimiento:

$ ruby generation_method.rb
¿Cuál es tu año de nacimiento? 1982
Eres un millenial

Sin embargo, sería mucho mejor evitar el puts en el método. Modifiquémoslo para mejorarlo:

def generation(year_of_birth)
  if year_of_birth >= 1996
    "Eres un centenial"
  elsif year_of_birth >= 1977
    "Eres un millenial"
  elsif year_of_birth >= 1965
    "Eres generación X"
  elsif year_of_birth >= 1946
    "Eres baby boomer"
  else
    "Eres tradicionalista"
  end
end

print "¿Cuál es tu año de nacimiento? "
year_of_birth = gets.chomp.to_i

puts generation(year_of_birth)

Mucho mejor. Sin embargo hay algo que no me gusta de este método. Está retornando los strings en Español. Si quisiéramos comparar ese valor para realizar alguna acción dependiendo de la generación, nos tocaría comparar el string exacto. Además, si queremos tener una aplicación que soporte varios idiomas esta implementación no va a funcionar. Podemos mejorarla:

def generation(year_of_birth)
  if year_of_birth >= 1996
    :centenial
  elsif year_of_birth >= 1977
    :millenial
  elsif year_of_birth >= 1965
    :generation_x
  elsif year_of_birth >= 1946
    :baby_boomer
  else
    :traditionalist
  end
end

translations = { centenial: "centenial", millenial: "millenial", generation_x: "X",
  baby_boomer: "baby boomer", traditionalist: "tradicionalista" }

print "¿Cuál es tu año de nacimiento? "
year_of_birth = gets.chomp.to_i

generation_code = generation(year_of_birth)
puts "Eres de la generación #{translations[generation_code]}"

El programa es más largo pero la función generation es ahora mucho más reutilizable. Si queremos tomar una desición dependiendo de la generación lo podemos hacer fácilmente (comparar símbolos es mucho menos propenso a errores que comparar cadenas de texto).

Evalúate

  1. Escribe un método llamado square_perimeter que reciba un argumento side y calcule el perímetro de un cuadrado (recuerda que el perímetro de un cuadrado es la suma de los lados). Por ejemplo:

     square_perimeter(2) # Debería retornar 8
     square_perimeter(5) # Debería retornar 20
  2. Escribe un método llamado square_area que reciba un argumento side y retorne el área de de un cuadrado. Por ejemplo:

     square_area(2) # Debería retornar 4
     square_area(5) # Debería retornar 25
  3. Escribe un método llamado sum que reciba un arreglo y retorne la suma de los elementos. Por ejemplo:

     sum([]) # debería retornar 0
     sum([1]) # debería retornar 1
     sum([1, 2, 3]) # debería retornar 6
  4. Escribe un método llamado average que reciba un arreglo y retorne el promedio de los elementos. Por ejemplo:

     average([]) # debería retornar 0
     average([1]) # debería retornar 1
     average([1, 2, 3]) # debería retornar 2

Last updated