Ruby 2.7 adds supports for Comparable#clamp with a range


Clamp method was added to Comparable module in Ruby 2.4.

Comparable#clamp

The method is used to clamp an object within a specific range of values.

20.clamp(0, 5)
=> 5

20.clamp(0, 50)
=> 20

20.clamp(30, 50)
=> 30

Similarly, strings can also be clamped within a range.

"p".clamp("a", "z")
=> "p"
 
"p".clamp("s", "z")
=> "s"

"p".clamp("a", "g")
=> "g"

"king".clamp("kingdom", "kingship")
=> "kingdom"

One way to use clamping effectively is to define the minimum and maximum values for the globally used entities in configurations or constants and use them app-wide.

Example,

We have a constant to define range for the score

SCORE_RANGE = (1..10)

In order to clamp the input score value within score range we need to do,

input_score = 15
input_score.clamp(SCORE_RANGE.min, SCORE_RANGE.max)
=> 10

Comparable#clamp with a Range argument

Comparable#clamp accepts a Range argument with Ruby 2.7

The above score clamping can happen with,

input_score = 15
input_score.clamp(SCORE_RANGE)
=> 10

Both numbers and strings can be clamped with a Range argument,

20.clamp(0..5)
=> 5

20.clamp(0..50)
=> 20

20.clamp(30..50)
=> 30

"p".clamp("a".."z")
=> "p"

"p".clamp("s".."z")
=> "s"

"p".clamp("a".."g")
=> "g"
 
"king".clamp("kingdom".."kingship")
=> "kingdom"

Comparable#clamp with a beginless/endless ranges

clamp raises an exception ArgumentError (cannot clamp with an exclusive range) when beginless/endless range is used as an argument.

20.clamp(0..)
ArgumentError (cannot clamp with an exclusive range)

20.clamp(..100)
ArgumentError (cannot clamp with an exclusive range)

The above error message is misleading and should be raised only for the exclusive ranges.

This issue is being discussed on the feature ticket