Reading nested if statements making you sad? Case statements can be the answer. Refactoring your if statements can clear up complicated code and make spotting bugs much easier.

Nested if statements often lead to complex and hard-to-read code. They can grow over time as new conditions are added, making it difficult to maintain and debug. The reason most people don’t notice is that usually the if statements grow over time and never get refactored even though doing so is simple.

Refactoring these into case statements can significantly clarify the code.

One place where case statements shine is in scenarios like evaluating number ranges. They offer a cleaner, more readable syntax compared to multiple if/else blocks. For instance, grading systems benefit from case statements due to their straightforward range-based conditions, as demonstrated below in this Ruby code example.

An if/else structure that is ok:

if grade >= 90 
  "A" 
elsif grade >= 80 
  "B" 
elsif grade >= 70 
  "C" 
elsif grade >= 60 
  "D" 
else 
  "F" 
end

Using a case statements it becomes much more clear about what the grades really are. Case statements are great for number ranges where you can simply set them up like:

case grade 
  when (90..100) then "A" 
  when (80..89)  then "B"
  when (70..79)  then "C"
  when (60..69)  then "D"
  when (0..59)   then "F" 
  else "error"
end

Or is it? the if/else code lets us get a correct value for a grade of 89.5. Though both bits of code would return very wrong letter grades for a number grade of 105 (“error” for the case statement and “F” for the if/else ). So make sure you test your edge cases and be aware of how different results can come from these simple examples.

It is crucial to consider the nuances of each approach. While case statements offer clarity. Both approaches require careful consideration of edge cases.

Here is another examples of a refactoring an if/else statement into a case statement in Ruby:

age = 25

if age < 18
  "Minor"
elsif age >= 18 && age < 60
  "Adult"
elsif age >= 60 && age < 100
  "Senior"
else
  "Centenarian"
end

Now, let’s refactor this into a case statement.

# Refactored into a case statement
age = 17.9 # Minor

case age
  when (0...18)   then "Minor"
  when (18...60)  then "Adult"
  when (60...100) then "Senior"
  else "Centenarian"
end

This looks good and is easy to read if you understand that ranges defined with 3 periods exclude the last number. That is to say that (0...18) in the code above will return "Minor" for age = 17.9 but will return "Adult" for age = 18 which is how it is defined around here anyway.

We can see this by putting the case statement in a method and calling it with different ages:

def age_to_text(age)
  case age
    when (0...18)   then "Minor"
    when (18...60)  then "Adult"
    when (60...100) then "Senior"
    else "Centenarian"
  end
end

age_to_text(1) # "Minor"
age_to_text(10) # "Minor"
age_to_text(17.9) # "Minor"
age_to_text(18) # "Adult"
age_to_text(18.1) # "Adult"
age_to_text(25) # "Adult"
age_to_text(55) # "Adult"
age_to_text(59.999) # "Adult"
age_to_text(60) # "Senior"
age_to_text(99.9) # "Senior"
age_to_text(100) # "Centenarian"
age_to_text(111) # "Centenarian"

So, while refactoring with case statements can simplify and declutter code, it’s essential to understand their behavior thoroughly, especially in edge cases. Both case statements and if/else structures have their place in Ruby programming, and the choice between them should be guided by the specific requirements of the task at hand.