⚙️ Módulo 5-6: Funciones y Métodos

Duración: Semanas 5 y 6

Objetivos del Módulo

  • Entender qué son los métodos y por qué son importantes
  • Aprender a definir métodos con y sin parámetros
  • Dominar el concepto de scope (alcance) de variables
  • Trabajar con blocks, procs y lambdas
  • Crear código reutilizable y modular

Contenido Teórico

1. ¿Qué son los Métodos?

Los métodos son bloques de código reutilizable que realizan una tarea específica. Nos permiten:

  • Evitar repetir código
  • Organizar mejor nuestros programas
  • Hacer el código más legible y mantenible

2. Definición Básica de Métodos

# Método sin parámetros
def greet
  puts "¡Hola!"
end

# Llamar al método
greet  # Output: ¡Hola!

# Método con parámetros
def greet_person(name)
  puts "¡Hola #{name}!"
end

greet_person("Ana")  # Output: ¡Hola Ana!

3. Métodos con Valores de Retorno

# Ruby devuelve automáticamente la última expresión
def add(a, b)
  a + b
end

result = add(5, 3)
puts result  # Output: 8

# Return explícito
def is_even(number)
  return true if number % 2 == 0
  false
end

puts is_even(4)  # Output: true
puts is_even(5)  # Output: false

4. Parámetros y Argumentos

Parámetros Obligatorios

def introduce(name, age)
  "Me llamo #{name} y tengo #{age} años"
end

puts introduce("Luis", 25)

Parámetros Opcionales (con valores por defecto)

def greet(name, greeting = "Hola")
  "#{greeting}, #{name}!"
end

puts greet("María")                    # "Hola, María!"
puts greet("María", "Buenos días")     # "Buenos días, María!"

Parámetros con Nombre (keyword arguments)

def create_user(name:, age:, city: "No especificada")
  "Usuario: #{name}, #{age} años, vive en #{city}"
end

puts create_user(name: "Ana", age: 30)
puts create_user(name: "Luis", age: 25, city: "Madrid")

Número Variable de Parámetros (splat operator)

def add_all(*numbers)
  numbers.sum
end

puts add_all(1, 2, 3)        # 6
puts add_all(1, 2, 3, 4, 5)  # 15

# Con argumentos con nombre
def process_data(action, **options)
  puts "Acción: #{action}"
  options.each { |key, value| puts "#{key}: #{value}" }
end

process_data("guardar", formato: "json", compresion: true)

5. Scope (Alcance) de Variables

Variables Locales

def example_method
  local_variable = "Solo existe aquí"
  puts local_variable
end

example_method
# puts local_variable  # Error: variable no definida

Variables de Instancia

@instance_variable = "Disponible en toda la instancia"

def show_variable
  puts @instance_variable
end

show_variable  # Output: Disponible en toda la instancia

Variables Globales

$global_variable = "Disponible en todo el programa"

def show_global
  puts $global_variable
end

show_global  # Output: Disponible en todo el programa

6. Blocks (Bloques)

Los blocks son fragmentos de código que se pueden pasar a métodos:

# Block con each
[1, 2, 3].each { |number| puts number * 2 }

# Block multilinea
[1, 2, 3].each do |number|
  square = number ** 2
  puts "#{number} al cuadrado es #{square}"
end

# Métodos que reciben blocks
def execute_three_times
  yield if block_given?
  yield if block_given?
  yield if block_given?
end

execute_three_times { puts "¡Hola!" }

Métodos que usan blocks

def process_numbers(numbers)
  result = []
  numbers.each do |number|
    result << yield(number) if block_given?
  end
  result
end

numbers = [1, 2, 3, 4, 5]
squares = process_numbers(numbers) { |n| n ** 2 }
puts squares  # [1, 4, 9, 16, 25]

7. Procs y Lambdas

Procs

# Crear un proc
my_proc = Proc.new { |x| x * 2 }

# Usar el proc
puts my_proc.call(5)  # 10

# Pasar proc a un método
numbers = [1, 2, 3, 4, 5]
result = numbers.map(&my_proc)
puts result  # [2, 4, 6, 8, 10]

Lambdas

# Crear un lambda
my_lambda = lambda { |x| x * 3 }
# o usando la sintaxis corta
my_lambda = ->(x) { x * 3 }

puts my_lambda.call(4)  # 12

# Los lambdas son más estrictos con argumentos
add = ->(a, b) { a + b }
puts add.call(2, 3)  # 5

Diferencias entre Procs y Lambdas

# Lambdas verifican el número de argumentos
my_lambda = ->(x, y) { x + y }
# my_lambda.call(1)  # Error: argumentos incorrectos

# Procs son más flexibles
my_proc = Proc.new { |x, y| (x || 0) + (y || 0) }
puts my_proc.call(1)  # 1 (y es nil, se convierte a 0)

8. Métodos Útiles de Ruby

Métodos de Enumerable

numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

# select - filtrar elementos
even_numbers = numbers.select { |n| n.even? }
puts even_numbers  # [2, 4, 6, 8, 10]

# map - transformar elementos
squares = numbers.map { |n| n ** 2 }
puts squares  # [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

# reduce - combinar elementos
sum = numbers.reduce(0) { |accumulated, n| accumulated + n }
puts sum  # 55

# find - encontrar primer elemento que cumple condición
first_greater_than_5 = numbers.find { |n| n > 5 }
puts first_greater_than_5  # 6

9. Métodos Predicate (Predicado)

Por convención, los métodos que devuelven true/false terminan en ?:

def positive?(number)
  number > 0
end

def empty?(array)
  array.empty?
end

puts positive?(5)     # true
puts positive?(-3)    # false
puts empty?([])       # true
puts empty?([1, 2])   # false

10. Métodos de Bang (!)

Los métodos que terminan en ! suelen modificar el objeto original:

def uppercase!(text)
  text.upcase!
end

name = "juan"
uppercase!(name)
puts name  # "JUAN" (modificado)

# Comparar con versión sin !
def uppercase(text)
  text.upcase
end

name2 = "ana"
result = uppercase(name2)
puts name2    # "ana" (sin cambios)
puts result  # "ANA" (nuevo string)

Ejercicios Prácticos

Ve al archivo ejercicios.rb para practicar los conceptos aprendidos.

Proyecto del Módulo

Ve al archivo proyecto_sistema_inventario.rb para completar el proyecto de este módulo.