Reputation: 1338
Is there a built-in way or a more elegant way of restricting a number num to upper/lower bounds in Ruby or in Rails?
e.g. something like:
def number_bounded (num, lower_bound, upper_bound)
return lower_bound if num < lower_bound
return upper_bound if num > upper_bound
num
end
Upvotes: 11
Views: 2810
Reputation: 7076
The method you're looking for is clamp: https://ruby-doc.org/core/Comparable.html#method-i-clamp
12.clamp(0, 100) #=> 12
523.clamp(0, 100) #=> 100
-3.123.clamp(0, 100) #=> 0
'd'.clamp('a', 'f') #=> 'd'
'z'.clamp('a', 'f') #=> 'f'
Upvotes: 1
Reputation: 2079
class Range
def clip(n)
if cover?(n)
n
elsif n < min
min
else
max
end
end
end
Upvotes: 1
Reputation: 54593
Since you're mentioning Rails, I'll mention how to do this with a validation.
validates_inclusion_of :the_column, :in => 5..10
That won't auto-adjust the number, of course.
Upvotes: 0
Reputation: 9818
Here's a clever way to do it:
[lower_bound, num, upper_bound].sort[1]
But that's not very readable. If you only need to do it once, I would just do
num < lower_bound ? lower_bound : (num > upper_bound ? upper_bound : num)
or if you need it multiple times, monkey-patch the Comparable module:
module Comparable
def bound(range)
return range.first if self < range.first
return range.last if self > range.last
self
end
end
so you can use it like
num.bound(lower_bound..upper_bound)
You could also just require ruby facets, which adds a method clip
that does just this.
Upvotes: 13
Reputation: 838116
You can use min and max to make the code more concise:
number_bounded = [lower_bound, [upper_bound, num].min].max
Upvotes: 12