Dan Rubio Dan Rubio - 27 days ago 10
Ruby Question

Why is my case statement failing despite the condition being true?

I'm working on a kata that tallies scores based on the role of five six sided die. Here is my code so far:

def score( dice )
points = []
score = {}
dice.each do |n|
if score.has_key?(n.to_s.to_sym)
score[n.to_s.to_sym] += 1
else
score[n.to_s.to_sym] = 1
end
end

score.each do |k,v|
key_int = k.to_s.to_i

case key_int
when key_int == 1 && (v == 3)
points << 1000
when key_int == 6 && (v == 3)
points << 600
when key_int == 5 && (v == 3)
points << 500
when key_int == 4 && (v == 3)
points << 400
when key_int == 3 && (v == 2)
points << 300
when key_int == 2 && (v == 3)
puts "did I get here"
points << 200
when key_int == 1 && (v < 3)
points << key_int * v
when key_int == 5 && (v < 3)
points << key_int * v
else
puts "Default"
end
end
points
end

puts score([2, 2, 2, 3, 3]) ==> 200


So at a basic level for this example, what's happening is when my each loop hits the hash I get this condition of:

key_int == 2 && (v == 3)


and insert it into the code before the case statement, I get a value of
true
but I never reach the condition of
points << 200
. For simplification I whittled down the code to this for the case logic.

score.each do |k,v|
key_int = k.to_s.to_i
case key_int
when key_int == 2
puts "I reached the condition"
else
puts "default"
end
end


I still get the default and I never reach the
when
condition. This is confusing me. What am I possibly doing wrong?

Answer

If you specify an object right after case, it will be compared against each when pattern via pattern === object.

In this example:

case key_int
when key_int == 2
  # ...
end

it will compare key_int against key_int == 2 like this:

(key_int == 2) === key_int

Assuming that key_int is 2, the above becomes:

true === 2

which evaluates to false.

To use a case expression like an if-elsif expression, you have to omit the initial object:

case
when key_int == 2
  # ...
end

See Ruby's documentation on the case Expression for another example.