¿Cómo escribir una statement de cambio en Ruby?

¿Cómo escribo una statement de cambio en Ruby?

Ruby usa la expresión de case su lugar.

 case x when 1..5 "It's between 1 and 5" when 6 "It's 6" when "foo", "bar" "It's either foo or bar" when String "You passed a string" else "You gave me #{x} -- I have no idea what to do with that." end 

Ruby compara el objeto en la cláusula when con el objeto en la cláusula case usando el operador === . Por ejemplo, 1..5 === x , y no x === 1..5 .

Esto permite cláusulas sofisticadas when ven arriba. Los rangos, las clases y todo tipo de cosas se pueden probar en lugar de solo la igualdad.

A diferencia de los enunciados de switch en muchos otros idiomas, el case de Ruby no tiene fallas, por lo que no es necesario finalizar cada uno when se produce un break . También puede especificar múltiples coincidencias en una sola cláusula como when "foo", "bar" .

case...when comporta de forma inesperada al manejar clases. Esto se debe al hecho de que usa el operador === .

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

 1 === 1 # => true Fixnum === Fixnum # => false 

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

 obj = 'hello' case obj.class when String print('It is a string') when Fixnum print('It is a number') else print('It is not a string') end 

Se imprimirá “No es una cadena”.

Afortunadamente, esto se resuelve fácilmente. El operador === se ha definido de modo que devuelve true si lo usa con una clase y proporciona una instancia de esa clase como el segundo operando:

 Fixnum === 1 # => true 

En resumen, el código anterior puede solucionarse eliminando .class :

 obj = 'hello' case obj # was case obj.class when String print('It is a string') when Fixnum print('It is a number') else print('It is not a string') end 

Hoy llegué a este problema mientras buscaba una respuesta, y esta era la primera página que aparecía, así que pensé que sería útil para otros en mi misma situación.

Se hace por caso en Ruby. También vea este artículo en Wikipedia .

Citado:

 case n when 0 puts 'You typed zero' when 1, 9 puts 'n is a perfect square' when 2 puts 'n is a prime number' puts 'n is an even number' when 3, 5, 7 puts 'n is a prime number' when 4, 6, 8 puts 'n is an even number' else puts 'Only single-digit numbers are allowed' end 

Otro ejemplo:

 score = 70 result = case score when 0..40 then "Fail" when 41..60 then "Pass" when 61..70 then "Pass with Merit" when 71..100 then "Pass with Distinction" else "Invalid Score" end puts result 

En la página 123 (Estoy usando Kindle) de The Ruby Programming Lanugage (1ra Edición, O’Reilly), dice que la palabra clave then sigue a las cláusulas when se puede reemplazar por una nueva línea o punto y coma (como en la syntax if then else ) (Ruby 1.8 también permite dos puntos en lugar de then … Pero esta syntax ya no está permitida en Ruby 1.9.)

caso … cuando

Para agregar más ejemplos a la respuesta de Chuck :

Con el parámetro:

 case a when 1 puts "Single value" when 2, 3 puts "One of comma-separated values" when 4..6 puts "One of 4, 5, 6" when 7...9 puts "One of 7, 8, but not 9" else puts "Any other thing" end 

Sin parámetro:

 case when b < 3 puts "Little than 3" when b == 3 puts "Equal to 3" when (1..10) === b puts "Something in closed range of [1..10]" end 

Por favor, tenga en cuenta el problema que el kikito advierte.

En Ruby 2.0, también puede usar lambdas en sentencias case , de la siguiente manera:

 is_even = ->(x) { x % 2 == 0 } case number when 0 then puts 'zero' when is_even then puts 'even' else puts 'odd' end 

También puede crear sus propios comparadores fácilmente utilizando un Struct con una función personalizada ===

 Moddable = Struct.new(:n) do def ===(numeric) numeric % n == 0 end end mod4 = Moddable.new(4) mod3 = Moddable.new(3) case number when mod4 then puts 'multiple of 4' when mod3 then puts 'multiple of 3' end 

(Ejemplo tomado de ” ¿Se pueden usar los procesos con las declaraciones de casos en Ruby 2.0? “).

O, con una clase completa:

 class Vehicle def ===(another_vehicle) self.number_of_wheels == another_vehicle.number_of_wheels end end four_wheeler = Vehicle.new 4 two_wheeler = Vehicle.new 2 case vehicle when two_wheeler puts 'two wheeler' when four_wheeler puts 'four wheeler' end 

(Ejemplo tomado de ” Cómo funciona un enunciado de caso Ruby y qué puede hacer con él “).

Muchos lenguajes de progtwigción, especialmente los derivados de C, tienen soporte para el llamado Switch Fallthrough . Estaba buscando la mejor manera de hacer lo mismo en Ruby y pensé que podría ser útil para otros:

En lenguajes tipo C, Fallthrough generalmente se ve así:

 switch (expression) { case 'a': case 'b': case 'c': // Do something for a, b or c break; case 'd': case 'e': // Do something else for d or e break; } 

En Ruby, lo mismo se puede lograr de la siguiente manera:

 case expression when 'a', 'b', 'c' # Do something for a, b or c when 'd', 'e' # Do something else for d or e end 

Esto no es estrictamente equivalente, porque no es posible dejar que 'a' ejecute un bloque de código antes de pasar a 'b' o 'c' , pero en general me parece lo suficientemente similar como para ser útil de la misma manera.

Puede usar expresiones regulares, como encontrar un tipo de cadena:

 case foo when /^(true|false)$/ puts "Given string is boolean" when /^[0-9]+$/ puts "Given string is integer" when /^[0-9\.]+$/ puts "Given string is float" else puts "Given string is probably string" end 

El case de Ruby usará el operando de igualdad === para esto (gracias @JimDeville). Información adicional está disponible en ” Ruby Operators “. Esto también se puede hacer usando el ejemplo @mmdemirbas (sin parámetro), solo que este enfoque es más limpio para este tipo de casos.

Si está ansioso por saber cómo usar una condición O en un caso de interruptor de Ruby:

Entonces, en una statement de case , a , es el equivalente de || en una statement if .

 case car when 'Maruti', 'Hyundai' # Code here end 

Muchas otras cosas que puede hacer con una statement de caso de Ruby

Se llama case y funciona como era de esperar, además de muchas más cosas divertidas cortesía de === que implementa las pruebas.

 case 5 when 5 puts 'yes' else puts 'else' end 

Ahora para divertirse:

 case 5 # every selector below would fire (if first) when 3..7 # OK, this is nice when 3,4,5,6 # also nice when Fixnum # or when Integer # or when Numeric # or when Comparable # (?!) or when Object # (duhh) or when Kernel # (?!) or when BasicObject # (enough already) ... end 

Y resulta que también puede reemplazar una cadena if / else arbitraria (es decir, incluso si las pruebas no involucran una variable común) con case y case dejando fuera el parámetro inicial del case y simplemente escribiendo expresiones donde la primera coincidencia es lo que querer.

 case when x.nil? ... when (x.match /'^fn'/) ... when (x.include? 'substring') ... when x.gsub('o', 'z') == 'fnzrq' ... when Time.now.tuesday? ... end 

Como la switch case siempre devuelve un solo objeto, podemos imprimir directamente su resultado:

 puts case a when 0 "It's zero" when 1 "It's one" end 

Valor múltiple cuando y sin valor de mayúsculas y minúsculas:

 print "Enter your grade: " grade = gets.chomp case grade when "A", "B" puts 'You pretty smart!' when "C", "D" puts 'You pretty dumb!!' else puts "You can't even use a computer!" end 

Y una solución de expresión regular aquí:

 print "Enter a string: " some_string = gets.chomp case when some_string.match(/\d/) puts 'String has numbers' when some_string.match(/[a-zA-Z]/) puts 'String has letters' else puts 'String has no numbers or letters' end 

Dependiendo de su caso, podría preferir utilizar un hash de métodos.

Si hay una larga lista de cuándo y cada uno de ellos tiene un valor concreto para comparar (no un intervalo), será más efectivo declarar un hash de métodos y luego llamar al método relevante del hash de esa manera.

 # Define the hash menu = {a: :menu1, b: :menu2, c: :menu2, d: :menu3} # Define the methods def menu1 puts 'menu 1' end def menu2 puts 'menu 2' end def menu3 puts 'menu3' end # Let's say we case by selected_menu = :a selected_menu = :a # Then just call the relevant method from the hash send(menu[selected_menu]) 

Ruby usa el case para escribir declaraciones de cambio.

Según los Ruby Docs :

Las declaraciones de casos consisten en una condición opcional, que está en la posición de un argumento para el case , y cero o más when cláusulas. La primera cláusula when para hacer coincidir la condición (o para evaluar la verdad booleana, si la condición es nula) “gana”, y se ejecuta su estrofa de código. El valor de la statement case es el valor de la cláusula when exitosa, o nil si no existe dicha cláusula.

Una statement de caso puede terminar con una cláusula else . Cada uno when una statement puede tener múltiples valores candidatos, separados por comas.

Ejemplo:

 case x when 1,2,3 puts "1, 2, or 3" when 10 puts "10" else puts "Some other number" end 

Versión más corta:

 case x when 1,2,3 then puts "1, 2, or 3" when 10 then puts "10" else puts "Some other number" end 

Y como este blog de Honeybadger describe a Ruby Case;

Se puede usar con rangos :

 case 5 when (1..10) puts "case statements match inclusion in a range" end ## => "case statements match inclusion in a range" 

Se puede usar con Regex :

 case "FOOBAR" when /BAR$/ puts "they can match regular expressions!" end ## => "they can match regular expressions!" 

Se puede usar con Procs y Lambdas :

 case 40 when -> (n) { n.to_s == "40" } puts "lambdas!" end ## => "lambdas" 

Además, se puede usar con sus propias clases de coincidencia:

 class Success def self.===(item) item.status >= 200 && item.status < 300 end end class Empty def self.===(item) item.response_size == 0 end end case http_response when Empty puts "response was empty" when Success puts "response was a success" end 

Puede escribir expresiones de casos de dos maneras diferentes en ruby.

  1. Similar a una serie de declaraciones “si”
  2. Especifique un objective al lado del caso y cada cláusula “cuándo” se compara con el objective.

1ra manera

 age = 20 case when age >= 21 puts "display something" when 1 == 0 puts "omg" else puts "default condition" end 

2da manera

  case params[:unknown] when /Something/ then 'Nothing' when /Something else/ then 'I dont know' end 

Muchas respuestas excelentes, pero pensé que agregaría un factor. Si está intentando comparar objetos (Clases), asegúrese de tener un método de nave espacial (no es una broma) o entienda cómo se comparan.

Aquí hay una buena discusión sobre el tema http://www.skorks.com/2009/09/ruby-equality-and-object-comparison/

Puedes hacer esto de forma más natural,

 case expression when condtion1 function when condition2 function else function end 
 puts "Recommend me a language to learn?" input = gets.chomp.downcase.to_s case input when 'ruby' puts "Learn Ruby" when 'python' puts "Learn Python" when 'java' puts "Learn Java" when 'php' puts "Learn PHP" else "Go to Sleep!" end 

Como se indica en muchas de las respuestas anteriores, el operador === se usa debajo del capó en las declaraciones caso / cuando.

Aquí hay algunos datos adicionales sobre ese operador.

Operador de igualdad de caso: ===

Muchas de las clases incorporadas de Ruby, como String, Range y Regexp, proporcionan sus propias implementaciones del operador ===, también conocido como igualdad de casos, triple equals o threequals. Debido a que se implementa de manera diferente en cada clase, se comportará de manera diferente según el tipo de objeto al que se invocó. En general, devuelve verdadero si el objeto de la derecha “pertenece” o “es un miembro de” el objeto de la izquierda. Por ejemplo, se puede usar para probar si un objeto es una instancia de una clase (o una de sus subclases).

 String === "zen" # Output: => true Range === (1..2) # Output: => true Array === [1,2,3] # Output: => true Integer === 2 # Output: => true 

El mismo resultado se puede lograr con otros métodos que probablemente sean los más adecuados para el trabajo, como is_a? y instance_of ?.

Implementación de rango de ===

Cuando se llama al operador === en un objeto de rango, devuelve verdadero si el valor de la derecha cae dentro del rango de la izquierda.

 (1..4) === 3 # Output: => true (1..4) === 2.345 # Output: => true (1..4) === 6 # Output: => false ("a".."d") === "c" # Output: => true ("a".."d") === "e" # Output: => false 

Recuerde que el operador === invoca el método === del objeto de la izquierda. Entonces (1..4) === 3 es equivalente a (1..4). === 3. En otras palabras, la clase del operando de la izquierda definirá qué implementación del método === será llamado, por lo que las posiciones del operando no son intercambiables.

Implementación Regexp de ===

Devuelve verdadero si la cadena de la derecha coincide con la expresión regular de la izquierda. / zen / === “practica zazen hoy” # Salida: => true # es similar a “practica zazen hoy” = ~ / zen /

La única diferencia relevante entre los dos ejemplos anteriores es que, cuando hay una coincidencia, === devuelve verdadero y = ~ devuelve un entero, que es un valor de verdad en Ruby. Volveremos a esto pronto.

 $age = 5 case $age when 0 .. 2 puts "baby" when 3 .. 6 puts "little child" when 7 .. 12 puts "child" when 13 .. 18 puts "youth" else puts "adult" end 

referencia => https://www.tutorialspoint.com/ruby/ruby_if_else.htm

Empecé a usar:

 a = "secondcase" var_name = case a when "firstcase" then "foo" when "secondcase" then "bar" end puts var_name >> "bar" 

Ayuda código compacto en algunos casos.

¿No hay soporte para expresiones regulares en su entorno? Ej. Shopify Script Editor (abril, 2018):

[Error]: constante no reinicializada RegExp

Una solución alternativa que sigue una combinación de métodos que ya hemos tratado anteriormente aquí y aquí :

 code = '!ADD-SUPER-BONUS!' class StrContains def self.===(item) item.include? 'SUPER' or item.include? 'MEGA' or\ item.include? 'MINI' or item.include? 'UBER' end end case code.upcase when '12345PROMO', 'CODE-007', StrContains puts "Code #{code} is a discount code!" when '!ADD-BONUS!' puts 'This is a bonus code!' else puts 'Sorry, we can\'t do anything with the code you added...' end 

Utilicé or s en la statement de método de clase desde || tiene mayor precedencia que .include? . Si eres un nazi Ruby , imagina que usé esto (item.include? 'A') || ... (item.include? 'A') || ... cambio. prueba de repl.it