Amy
Amy

Reputation: 1338

Restrict a number to upper/lower bounds?

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

Answers (5)

Ed McManus
Ed McManus

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

Bill Lipa
Bill Lipa

Reputation: 2079

class Range

  def clip(n)
    if cover?(n)
      n
    elsif n < min
      min
    else
      max
    end
  end

end

Upvotes: 1

August Lilleaas
August Lilleaas

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

mckeed
mckeed

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

Mark Byers
Mark Byers

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

Related Questions