Articles

Cómo escribir una expresión de caso en Ruby

Posted on

Imagina que necesitas una forma de comprobar el valor de un objeto, y realizar una acción diferente en función de ello. La manera de la Programación Orientada a Objetos es usar el polimorfismo, y veremos cómo hacerlo en un segundo.

Pero primero, veamos cómo funciona la expresión case, y cómo puedes usarla para lograr el objetivo mencionado anteriormente.

¿Cómo funciona el caso?

Hay dos partes principales en la expresión case. La cláusula case y la cláusula when.

La cláusula when es la expresión que define el receptor del operador (por defecto ===), y la cláusula case define el argumento que se le pasa.

Veamos un ejemplo.

case awhen String #..end

Así que puedes pensar en el ejemplo anterior como String === a, o String.===(a).

Por último, también hay una cláusula else que puedes utilizar para cuando no hay ninguna coincidencia.

case my_objectwhen String "This is a string"else "I have no idea what this is"end

El operador triple igual (===)

Por defecto, case utiliza el operador triple igual (===) para hacer la comparación.

Lo que ocurre con === es que no tiene nada que ver con la igualdad. Por defecto, está aliasado al operador doble de igualdad (==) que normalmente comprueba si dos objetos tienen un valor equivalente, pero se puede definir para que signifique cualquier cosa.

Por ejemplo, un rango lo define como un alias para includes?, un regex lo define como un alias para match, una clase para is_a?, un proc para call. Ya te haces una idea.

Ese operador funciona como se espera con los literales, pero no con las clases:

1 === 1 # => trueNumeric === Numeric # => false

Eso es porque el === es un alias de kind_of?. Y aquí están los docs para kind_of?.

kind_of?(class) → true o false

Devuelve true si class es la clase de obj, o si class es una de las superclases de obj o de los módulos incluidos en obj.

Esto significa que si quieres hacer un case ... when sobre la clase de un objeto, esto no funcionará:

obj = 'Hi'case obj.classwhen String "It's a string"end

Esto es porque, se traduce en String === String. Y eso devuelve false.

El operador por defecto

La expresión case tiene un operador por defecto. Y eso significa que no tienes que especificarlo. Eso está muy bien, porque puedes simplemente escribir when String y por defecto aparece el operador ===.

Pero, hay veces que quieres usar un operador diferente. Y Ruby te permite hacerlo. Aquí te decimos cómo.

casewhen a < 3 "Smaller than 3"end

Case es una expresión

Tal como dice el nombre, todo es una expresión. Es decir, se evalúa a un valor. Así que puedes asignar el resultado de toda la expresión case a una variable, así.

value = case when a < 3 "Smaller than 3" end

No hay caída

Si vienes de otros lenguajes, probablemente hayas usado una sentencia switch o algo similar, y habrás notado que case no utiliza palabras clave como break para romper el flujo.

Esto se debe a que no hay caída con case. Sólo devuelve el valor de la expresión con la que se ha encontrado una coincidencia y ya está.

Múltiples coincidencias

Hasta ahora, sólo has utilizado un valor para la cláusula when. Pero puedes utilizar múltiples valores.

case awhen 1..3 "Small number"end

Combinación de expresiones regulares

Puedes utilizar expresiones case para que coincida cualquier cosa. Pero por si acaso no es obvio, también puedes hacer coincidir regexes, o lambdas. Aquí tienes un ejemplo.

even = ->(x) { x % 2 == 0 }case awhen even "It's even"when /^+$/ "It's an integer"end

Define los tuyos

Uno de los hechos menos conocidos es que puedes definir tus propios comparadores.

Text = Struct.new(:min_length) do def ===(string) string.size > min_length && string.is_a?(String) endendcase awhen Text.new(100) "It's text"end

En el ejemplo anterior, si a es una cadena de más de 100 caracteres, entonces la expresión case devolverá It's text.

Usa el polimorfismo en su lugar

No voy a entrar aquí en las ventajas de la POO, puedes leer más sobre eso en el artículo Programación Orientada a Objetos con Ruby, pero sí voy a mostrarte cómo puedes usar el polimorfismo para sustituir una expresión case.

La versión case

class Person attr_reader :country def initialize(country) @country = country end def nationality case country when "USA" "This guy is an American" when "Romania" "This guy is a Romanian" end endendjohn = Person.new("USA")puts john.nationality # => This guy is an American

La versión OOP

class Person attr_reader :country def initialize(country) @country = country end def nationality country.nationality endendclass America def nationality "This guy is an American" endendclass Romania def nationality "This guy is a Romanian" endendjohn = Person.new(America.new)puts john.nationality # => This guy is an American

Es una buena idea eliminar todo el código de control de flujo (i.e. ifs, y case expresiones) como sea posible. Mejora la adhesión al principio de responsabilidad única y hace que el programa sea más legible en general.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *