Skip to main content

Why `case/when` does NOT work with just result codes?

Sometimes it may feel idiomatic to check the result code in the following way:

# wrong
if result.not_success?
case result.code # `result.code` returns fancy object
when :full_queue
notify_devops
when :duplicated_job
notify_devs
else
# ...
end
end

Although this snippet looks very appealing, it won't work as expected.

A lot of Ruby folks often have an assumption that a value of case is compared with a value of when.

case value === when value

In other words, the case/when from example above can be transformed to if/else like so:

# wrong
if result.not_success?
if result.code === :full_queue
notify_devops
elsif result.code === :duplicated_job
notify_devs
else
# ...
end
end

But, that is NOT correct.

In reality, the value of when is always compared with the value of case.

when value === case value

Let's write the proper transformation:

# okish
if result.not_success?
if :full_queue === result.code
notify_devops
elsif :duplicated_job === result.code
notify_devs
else
# ...
end
end

Symbol#=== is just an alias to Symbol#==.

There is no way to hook into any behavior like with strings (String#=== calls to_str on its argument).

As a result, just case result.code is not enough.

But once you use case result.code.to_sym, the natural Ruby charm is back.

# ok
if result.not_success?
case result.code.to_sym
when :full_queue
notify_devops
when :duplicated_job
notify_devs
else
# ...
end
end