How to find the "effective" end of a Range?

range, ruby

Solution

Use the `Range#max` method:

r = 1...10
r.end
# => 10
r.max
# => 9

`max` won't work for exclusive ranges if any of the endpoints is `Float` (see `range_max` in `range.c` for details):

(1.0...10.0).max
# TypeError: cannot exclude non Integer end value

(1.0..10.0).max
# => 10.0

As an exception, if `begin > end`, no error is raised and `nil` is returned:

(2.0...1.0).max
# => nil

Update: `max` works in costant time for any inclusive range and exclusive ranges of integers, it returns the same value as `end` and `end-1`, respectively. It is also O(1) if for the range holds that `begin > end`, in this case `nil` is returned. For exlusive ranges of non integer objects (`String`, `Date`, ...) or when a block is passed, it calls `Enumerable#max` so it have to travel all the elements in the range!

Problem

The `.end` of a Ruby range is the number used to specify the end of the range, whether or not the range is "exclusive of" the end. I don't understand the rationale for this design decision, but never the less, I was wondering what the most idiomatic mechanism is for determining the "effective end" of the range (i.e. greatest integer `n` such that `range.include?(n)` is `true`. The only mechanism I know of is `last(1)[0]`, which seems pretty klunky.

Original source