¿Cómo escribir una sentencia switch en Ruby?


¿Cómo escribo una instrucción switch en Ruby?

Author: Dmitry Grigoryev, 2009-06-04

21 answers

Ruby utiliza el case expression en 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 when sofisticadas como se ha visto anteriormente. Rangos, clases y todo tipo de cosas se pueden probar en lugar de solo la igualdad.

A diferencia de switch declaraciones en muchos otros idiomas, Ruby case no tiene fall-through, por lo que no hay necesidad de terminar cada when con un break. También puede especificar varias coincidencias en una sola cláusula when como when "foo", "bar".

 2346
Author: Chuck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-04 09:03:49

case...when se comporta un poco inesperadamente al manejar clases. Esto se debe al hecho de que utiliza el operador ===.

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

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

Esto significa que si desea 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

Imprimirá "No es una cadena".

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

Fixnum === 1 # => true

En resumen, el código anterior se puede arreglar eliminando el .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 encontré este problema mientras buscaba una respuesta, y esta fue la primera página que apareció, así que pensé que sería útil para otros en mi misma situación.

 400
Author: kikito,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-11 19:04:00

Se hace por case en Ruby. También ver 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

Alrededor de la página 123 (estoy usando Kindle) de El Lanugage de Programación Ruby (1ª Edición, O'Reilly), dice que la palabra clave then después de las cláusulas when se puede reemplazar con una nueva línea o punto y coma (al igual que en la sintaxis if then else). (Ruby 1.8 también permite dos puntos en lugar de then... Pero esta sintaxis ya no está permitida en Ruby 1.9.)

 190
Author: 太極者無極而生,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-08 02:40:33

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 kikito advierte.

 88
Author: mmdemirbas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:26:34

Muchos lenguajes de programació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 similares a C, fallthrough normalmente 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 cayendo a través de 'b' o 'c', pero en su mayor parte lo encuentro lo suficientemente similar como para ser útil de la misma manera.

 65
Author: Robert Kajic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-06 01:59:39

En Ruby 2.0, también puede usar lambdas en las 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 usando una estructura con un ===

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 puede usar procs con sentencias case 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 Una Sentencia Ruby Case Y Qué Se Puede Hacer Con Ella".)

 64
Author: James Lim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:55:11

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

Ruby case utilizará el operando de igualdad === para esto (gracias @JimDeville). Hay información adicional disponible en"Operadores de Ruby". 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.

 48
Author: Haris Krajina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-17 03:47:49

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

Así, en una sentencia case, a , es el equivalente de || en una sentencia if.

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

Muchas otras cosas que puedes hacer con una sentencia Ruby case

 30
Author: Manish Shrivastava,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-08 02:46:05

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

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

Ahora para un poco de diversión:

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 arbitraria if/else (es decir, incluso si las pruebas no involucran una variable común) con case omitiendo el parámetro inicial case y simplemente escribiendo expresiones donde la primera coincidencia es lo que desea.

case
  when x.nil?
    ...
  when (x.match /'^fn'/)
    ...
  when (x.include? 'substring')
    ...
  when x.gsub('o', 'z') == 'fnzrq'
    ...
  when Time.now.tuesday?
    ...
end
 25
Author: DigitalRoss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-30 22:48:00

Dependiendo de su caso, podría preferir usar 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 desde el 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])
 20
Author: Alexander,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-08 02:47:41

Dado que switch case siempre devuelve un único objeto, podemos imprimir directamente su resultado:

puts case a
     when 0
        "It's zero"
     when 1
        "It's one"
     end
 19
Author: Sonu Oommen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-08 02:42:17

Multi-valor cuando y caso sin valor:

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 expresión regular solución 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
 19
Author: 123,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-08 02:45:03

Ruby usa case para escribir sentencias switch.

Según los Documentos de Ruby :

Las sentencias Case consisten en una condición opcional, que posición de un argumento a case, y cero o más when cláusulas. La primera cláusula when para que coincida con la condición (o para evaluar a Verdad booleana, si la condición es nula) "gana", y su estrofa de código es ejecutado. El valor de la sentencia case es el valor de la la cláusula when exitosa, o nil si no existe tal cláusula.

Una sentencia case puede terminar con una cláusula else. Cada when a la instrucción 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 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 utilizar con Regex :

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

## => "they can match regular expressions!"

Puede utilizarse con Procs y Lambdas :

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

## => "lambdas"

También, se puede utilizar con sus propias clases de partido:

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
 17
Author: Lahiru,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-22 09:27:32

Puede escribir expresiones de mayúsculas y minúsculas de dos maneras diferentes en ruby.

  1. Similar a una serie de declaraciones "if"
  2. Especifique un destino junto al caso y cada cláusula "when" se compara con el destino.

1er camino

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
 11
Author: ysk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-16 17:45:44

Un montón de grandes respuestas, pero pensé que podría añadir un factoid.. Si está intentando comparar objetos (Clases) asegúrese de tener un método de nave espacial (no es una broma) o entender cómo se están comparando

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

 8
Author: jmansurf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-06 20:18:37

Puedes hacer esto de una manera más natural,

case expression
when condtion1
   function
when condition2
   function
else
   function
end
 8
Author: Navin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-26 09:15:12
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
 5
Author: Prabhakar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-03-12 06:33:17

Como se indica en muchas de las respuestas anteriores, el operador === se usa bajo el capó en las sentencias case/when.

Aquí hay algunas informaciones adicionales sobre ese operador.

Operador de igualdad de casos: = = =

Muchas de las clases integradas de Ruby, como String, Range y Regexp, proporcionan sus propias implementaciones del operador===, también conocido como case-equality, triple equals o threequals. Debido a que se implementa de manera diferente en cada clase, se comportará de manera diferente dependiendo sobre el tipo de objeto al que fue llamado. Generalmente, devuelve true si el objeto de la derecha "pertenece a" 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 rango objeto, devuelve true 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 izquierdo. So (1..4) = = = 3 es equivalente a (1..4).=== 3. En otras palabras, la clase del operando izquierdo definirá qué implementación del método === se llamará, por lo que las posiciones del operando no son intercambiables.

Regexp Implementación de = = =

Devuelve true si la cadena de la derecha coincide con la expresión regular de la izquierda. / zen / = = = "practice zazen today" # Output: = > true # es similar a "practice zazen today" = ~/zen /

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

 4
Author: BrunoFacca,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-06 16:07:17
$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

 2
Author: Navneet,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-13 09:28:06

He empezado a usar:

a = "secondcase"

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

puts var_name
>> "bar"

Ayuda a compactar el código en algunos casos.

 1
Author: deepfritz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-08 02:46:39

No hay soporte para expresiones regulares en su entorno? E. g. Shopify Editor de scripts (abril, 2018):

[Error]: constante no inicializada RegExp

Una solución alternativa siguiendo una combinación de métodos ya cubiertos previamente en 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

Usé ors en la instrucción class method ya que || tiene mayor precedencia que .include?. Si usted es un ruby-nazi, por favor imagina que usé esto (item.include? 'A') || ... en su lugar. repl.it prueba.

 0
Author: CPHPython,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-18 11:29:29