10

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?

3
  • 3
    Just for fun, you could also say { -1 => :low, 0 => :correct, 1 => :high }[guess <=> @answer]. Commented Dec 19, 2013 at 1:08
  • 1
    That looks like madness. I'll try it soon. Thanks.
    – dwilbank
    Commented Dec 19, 2013 at 1:21
  • Yes it is, I don't recommend you do it in real life, that's why I didn't include it in my answer. Commented Dec 19, 2013 at 1:27

4 Answers 4

17

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.

0
6

This works:

return case
  when guess > @answer ; :high
  when guess < @answer ; :low
  else ; :correct
  end
3
  • indeed it does. Wasn't exactly the trick I saw before, but it's just as nice! Thanks.
    – dwilbank
    Commented Dec 19, 2013 at 0:44
  • You need not to put a semicolon after else. Just a nitpick. Commented Dec 19, 2013 at 8:43
  • The op only needed to remove the word guess from 'case guess'. The case form demonstrated in this answer, a list of boolean conditions, would normally have 'then' instead of ';'. see mu's answer.
    – notapatch
    Commented Oct 2, 2015 at 10:54
6

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
2
  • Um, case x when y ... is perfectly valid in Ruby. The problem is that there are two forms of case and the OP is confused about which one they're using. Commented Dec 19, 2013 at 0:53
  • Yes, I meant that you can't use it like case x when x > 2, I'm guilty of not giving a proper explanation Commented Dec 19, 2013 at 0:54
0

Picking up on @mu's first comment on the question (an approach that looks fine to me), you could of course also write that as:

return case (guess <=> @answer)
       when -1 then :low
       when  0 then :correct
       when  1 then :high
       end

or

       ...
       else
         :high
       end

Not the answer you're looking for? Browse other questions tagged or ask your own question.