The case statement and ranges - Mehdi Farsi

By Mehdi Farsi

The case statement and ranges in Ruby

Mehdi Farsi

In this article, we’re going to explore the following topics:

  • The .. operator
  • The operator
  • An edge case using floating values

Feel free to read the Case statement behind the scene article if you’re not familiar with the case statement and the when clause.

The when clause with range

In a case statement the when clauses can take a range as parameter

Here, the case statement takes an integer as parameter.

As the when clause takes a range as parameter then instead of making a comparison using the === operator, the when clause checks if the integer is included in the range.

The .. operator in our range ensures the left and the right operands are included in the range.

The second when clause takes a range using the operator.

This means that the right operand isn’t included in the range.

Now that we’re more familiar with the when clause and ranges, let’s break down an edge case that I encountered using floats and ranges.

Range of floating values and the when clause

As we’ve seen in the above example, the operator excludes the right operand of the range. But, what if I want to exclude the left operand?

Here we can see that we exclude the left value by omitting it in the range — starting by 91 instead of 90 in order to exclude the 90 value.

This works fine for a range of integers.

But what if we have to deal with a range of floats?

Here surface doesn’t match any when clause — as its value is inferior to 130.01.

So, we cannot exclude the left operand by omitting it in the range.

Indeed, the next value is hard to determine because of the potential level of precision of the floating part — 130.01 to 130+1e–N.

So , a quick solution is to handle this comparison by using the Float#next_float

In the above example, we use the 130.0.next_float (which returns the next floating value with a precision of 1e-14) to exclude the 130.0 value.

Also, notice that we use endless ranges (available from Ruby 2.6.0).

This allows us to avoid to explicitly call the Float::INFINITY to end our range.

So here, the value of surface matches against this comparison and the case statement returns :third_value.

Voilà!