Ограничить целое число до диапазона в Ruby?

У меня есть переменная экземпляра @limit, которая должна быть больше 0 и не больше 20. В настоящее время у меня есть такой код:

@limit = (params[:limit] || 10).to_i
@limit = 20 if @limit > 20
@limit = 0 if @limit < 0

Это выглядит уродливо. Есть ли лучший способ ограничить целое число до диапазона значений?

Спасибо!

Ответ 2

Как насчет использования Enumerable#min, Enumerable#max?

Например, чтобы ограничить значение в диапазоне 0..10:

x = 100
[[10, x].min, 0].max
# => 10

x = -2
[[10, x].min, 0].max
# => 0

x = 5
[[10, x].min, 0].max
# => 5

Альтернатива, используя Enumerable#sort:

x = 100
[x, 0, 10].sort[1]
# => 10

x = -2
[x, 0, 10].sort[1]
# => 0

x = 5
[x, 0, 10].sort[1]
# => 5

Ответ 3

Вот быстрый тест, чтобы показать, какой метод мы должны использовать. Потому что кто-то неизбежно скажет "Использовать sort_by, потому что он быстрее, чем sort", я добавил его. sort_by работает только быстрее, чем sort при работе со сложными объектами. Основные объекты, такие как целые числа и строки, должны обрабатываться sort.

require 'fruity'

class Numeric
  def clamp(min, max)
    self < min ? min : self > max ? max : self
  end
end

compare do
  min_max { [[10, 100].min, 0].max }
  sort { [100, 0, 10].sort[1] }
  sort_by { [100, 0, 10].sort_by{ |v| v }[1] }
  clamp_test { 10.clamp(0, 100) }
  original {
    limit = 10
    limit = 100 if limit > 100
    limit = 0 if limit < 0
    limit
  }
end

С результатами:

Running each test 65536 times. Test will take about 8 seconds.
original is faster than clamp_test by 2x ± 1.0
clamp_test is faster than sort by 6x ± 1.0
sort is faster than min_max by 2x ± 0.1
min_max is faster than sort_by by 2x ± 0.1

Иногда уродство лучше.

Ответ 4

Если вы чувствуете, что обезьяна исправляет метод, вы можете сделать что-то вроде этого:

class Numeric
  def clamp(min, max)
    self < min ? min : self > max ? max : self
  end
end

# usage
@limit = (params[:limit] || 10).clamp(0, 20)

Ответ 5

Для удобства здесь находится обезьяна-патч для "уродливого и лучшего" решения, которое выигрывает тест Tin Man в другом месте на этой странице. (Это должно быть немного быстрее, если вы вернетесь немедленно, если граница превысила.)

class Numeric
  def clamp(min, max)
    return min if self < min
    return max if self > max
    self
  end
end

Ответ 6

(1..19).cover? @limit

Подробнее см. docs.