Menu
CoddyTech

case y clases

Parte de la sección Programación orientada a objetos del Journey de Ruby de Coddy. Lección 35 de 57.

case puede ramificarse según la clase de un valor. when Integer coincide con todos los enteros, porque case compara con ===, y Integer === 5 pregunta si 5 es un Integer (is_a?):

def describe(value)
  case value
  when Integer then "integer #{value}"
  when Float then format("float %.2f", value)
  when String then "text of #{value.size} chars"
  when nil then "nothing"
  else "other: #{value.class}"
  end
end

[5, 2.5, "hi", nil, [1, 2]].each { |v| puts describe(v) }

Salida:

integer 5
float 2.50
text of 2 chars
nothing
other: Array

Como === en una clase sigue a is_a?, un when con una superclase también coincide con sus subclases. Ordena las ramas desde la clase más específica hasta la más general:

class Animal
end

class Dog < Animal
end

def kind(x)
  case x
  when Dog then "a dog"
  when Animal then "some animal"
  else "not an animal"
  end
end

puts kind(Dog.new)
puts kind(Animal.new)
puts kind("Rex")
puts Animal === Dog.new

Salida:

a dog
some animal
not an animal
true

Un when puede enumerar varias clases, y las ramas pueden realizar tareas útiles con el valor, como sumar una estructura anidada de tipos mixtos:

def total(value)
  case value
  when Integer, Float then value
  when String then value.to_f
  when Array then value.sum { |v| total(v) }
  when Hash then total(value.values)
  else 0
  end
end

puts total([1, "2.5", { a: 3, b: [4, nil] }])

Salida:

10.5

Ramificar según las clases es adecuado para valores a cuyas clases no puedes añadir métodos nuevos, como números, cadenas y arreglos, o datos externos. Para tus propias clases, prefiere el polimorfismo: una clase nueva necesita entonces un método nuevo, no una rama nueva en cada case:

# tus propias clases: deja que cada una responda
shape.area

# valores integrados externos: elige según la clase
case value
when Integer then ...
when String then ...
end
challenge icon

Desafío

Fácil

Completa la función auxiliar describe(value) en functions.rb con un case sobre la clase del valor. Devuelve integer 5 (odd) o integer 4 (even), float 2.50 con dos decimales, text "hi" (2 chars), list of 3: 1, a, 2.5 (los elementos unidos mediante to_s), nothing para nil y other Symbol para cualquier otra cosa. Los símbolos son el único otro tipo presente en las pruebas.

El código proporcionado convierte cada línea de entrada en un valor (números enteros, decimales, listas [a,b], nil, símbolos :name o texto) e imprime el resultado de describe para cada uno.

Tu código va en functions.rb. main.rb contiene el código de entrada y salida proporcionado y no se puede editar.

Pruébalo tú mismo

require_relative 'functions'

# Código de entrada/salida proporcionado: mantenlo tal como está
input = []
while (line = gets)
  input << line.chomp
end
def parse(text)
  return Integer(text) if text.match?(/\A-?\d+\z/)
  return Float(text) if text.match?(/\A-?\d+\.\d+\z/)
  return nil if text == "nil"
  return text[1..].to_sym if text.start_with?(":")
  return text[1...-1].split(",").map { |t| parse(t) } if text.start_with?("[")

  text
end

input.each { |line| puts describe(parse(line)) }
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Compilador de Ruby online