Shortcut to make case/switch return a value

I'm pretty sure I saw someone do a shortcut technique like the code below (which doesn't work)

return case guess
  when guess > @answer then :high
  when guess < @answer then :low
  else :correct
end

Does anyone know the trick I'm referring to?


A case statement does return a value, you just have to use the right form of it to get the value you're expecting.

There are two forms of case in Ruby. The first one looks like this:

case expr
when expr1 then ...
when expr2 then ...
else ...
end

This will compare expr with each when expression using === (that's a triple BTW) and it will execute the first then where === gives a true value. For example:

case obj
when Array then do_array_things_to(obj)
when Hash  then do_hash_things_to(obj)
else raise 'nonsense!'
end

is the same as:

if(Array === obj)
  do_array_things_to(obj)
elsif(Hash === obj)
  do_hash_things_to(obj)
else
  raise 'nonsense!'
end

The other form of case is just a bunch of boolean conditions:

case
when expr1 then ...
when expr2 then ...
else ...
end

For example:

case
when guess > @answer then :high
when guess < @answer then :low
else :correct
end

is the same as:

if(guess > @answer)
  :high
elsif(guess < @answer)
  :low
else
  :correct
end

You're using the first form when you think you're using the second form so you end up doing strange (but syntactically valid) things like:

(guess > @answer) === guess
(guess < @answer) === guess

In either case, case is an expression and returns whatever the matched branch returns.


You need to remove the guess from the case, because it's not valid ruby syntax.

For example:

def test value
  case 
  when value > 3
    :more_than_3
  when value < 0
    :negative
  else
    :other
  end
end

Then

test 2   #=> :other 
test 22  #=> :more_than_3 
test -2  #=> :negative 

The return is implicit.

Edit: you can use then if you like too, the same example would look like this:

def test value
  case 
    when value > 3 then :more_than_3
    when value < 0 then :negative
    else :other
  end
end

This works:

return case
  when guess > @answer ; :high
  when guess < @answer ; :low
  else ; :correct
  end