class Range - Documentation for Ruby 3.2

# class Range

A Range object represents a collection of values that are between given begin and end values.

You can create an Range object explicitly with:

- A range literal:

      # Ranges that use '..' to include the given end value.
      (1..4).to_a      # => [1, 2, 3, 4]
      ('a'..'d').to_a  # => ["a", "b", "c", "d"]
      # Ranges that use '...' to exclude the given end value.
      (1...4).to_a     # => [1, 2, 3]
      ('a'...'d').to_a # => ["a", "b", "c"]

A range may be created using method `Range.new`:

    # Ranges that by default include the given end value.
    Range.new(1, 4).to_a     # => [1, 2, 3, 4]
    Range.new('a', 'd').to_a # => ["a", "b", "c", "d"]
    # Ranges that use third argument +exclude_end+ to exclude the given end value.
    Range.new(1, 4, true).to_a     # => [1, 2, 3]
    Range.new('a', 'd', true).to_a # => ["a", "b", "c"]

## Beginless Ranges¶ ↑

A beginless range has a definite end value, but a `nil` begin value. Such a range includes all values up to the end value.

    r = (..4)               # => nil..4
    r.begin                 # => nil
    r.include?(-50)         # => true
    r.include?(4)           # => true

    r = (...4)              # => nil...4
    r.include?(4)           # => false

    Range.new(nil, 4)       # => nil..4
    Range.new(nil, 4, true) # => nil...4

A beginless range may be used to slice an array:

    a = [1, 2, 3, 4]
    r = (..2) # => nil...2
    a[r]      # => [1, 2]

Method `each` for a beginless range raises an exception.

## Endless Ranges¶ ↑

An endless range has a definite begin value, but a `nil` end value. Such a range includes all values from the begin value.

    r = (1..)         # => 1..
    r.end             # => nil
    r.include?(50)    # => true

    Range.new(1, nil) # => 1..

The literal for an endless range may be written with either two dots or three. The range has the same elements, either way. But note that the two are not equal:

    r0 = (1..)           # => 1..
    r1 = (1...)          # => 1...
    r0.begin == r1.begin # => true
    r0.end == r1.end     # => true
    r0 == r1             # => false

An endless range may be used to slice an array:

    a = [1, 2, 3, 4]
    r = (2..) # => 2..
    a[r]      # => [3, 4]

Method `each` for an endless range calls the given block indefinitely:

    a = []
    r = (1..)
    r.each do |i|
      a.push(i) if i.even?
      break if i > 10
    end
    a # => [2, 4, 6, 8, 10]

A range can be both beginless and endless. For literal beginless, endless ranges, at least the beginning or end of the range must be given as an explicit nil value. It is recommended to use an explicit nil beginning and implicit nil end, since that is what Ruby uses for `Range#inspect`:

    (nil..)    # => (nil..)
    (..nil)    # => (nil..)
    (nil..nil) # => (nil..)

## Ranges and Other Classes¶ ↑

An object may be put into a range if its class implements instance method `<=>`. Ruby core classes that do so include `Array`, `Complex`, `File::Stat`, `Float`, `Integer`, `Kernel`, `Module`, `Numeric`, `Rational`, `String`, `Symbol`, and `Time`.

Example:

    t0 = Time.now         # => 2021-09-19 09:22:48.4854986 -0500
    t1 = Time.now         # => 2021-09-19 09:22:56.0365079 -0500
    t2 = Time.now         # => 2021-09-19 09:23:08.5263283 -0500
    (t0..t2).include?(t1) # => true
    (t0..t1).include?(t2) # => false

A range can be iterated over only if its elements implement instance method `succ`. Ruby core classes that do so include `Integer`, `String`, and `Symbol` (but not the other classes mentioned above).

Iterator methods include:

- In Range itself: `each`, `step`, and `%`

- Included from module Enumerable: `each_entry`, `each_with_index`, `each_with_object`, `each_slice`, `each_cons`, and `reverse_each`.

Example:

    a = []
    (1..4).each {|i| a.push(i) }
    a # => [1, 2, 3, 4]

## Ranges and User-Defined Classes¶ ↑

A user-defined class that is to be used in a range must implement instance `<=>`; see `Integer#<=>`. To make iteration available, it must also implement instance method `succ`; see `Integer#succ`.

The class below implements both `<=>` and `succ`, and so can be used both to construct ranges and to iterate over them. Note that the `Comparable` module is included so the `==` method is defined in terms of `<=>`.

    # Represent a string of 'X' characters.
    class Xs
      include Comparable
      attr_accessor :length
      def initialize(n)
        @length = n
      end
      def succ
        Xs.new(@length + 1)
      end
      def <=>(other)
        @length <=> other.length
      end
      def to_s
        sprintf "%2d #{inspect}", @length
      end
      def inspect
        'X' * @length
      end
    end

    r = Xs.new(3)..Xs.new(6) #=> XXX..XXXXXX
    r.to_a                   #=> [XXX, XXXX, XXXXX, XXXXXX]
    r.include?(Xs.new(5))    #=> true
    r.include?(Xs.new(7))    #=> false

## What’s Here¶ ↑

First, what’s elsewhere. Class Range:

- Inherits from class Object.

- Includes module Enumerable, which provides dozens of additional methods.

Here, class Range provides methods that are useful for:

- Creating a Range

- Querying

- Comparing

- Iterating

- Converting

### Methods for Creating a Range¶ ↑

- `::new`: Returns a new range.

### Methods for Querying¶ ↑

- `begin`: Returns the begin value given for `self`.

- `bsearch`: Returns an element from `self` selected by a binary search.

- `count`: Returns a count of elements in `self`.

- `end`: Returns the end value given for `self`.

- `exclude_end?`: Returns whether the end object is excluded.

- `first`: Returns the first elements of `self`.

- `hash`: Returns the integer hash code.

- `last`: Returns the last elements of `self`.

- `max`: Returns the maximum values in `self`.

- `min`: Returns the minimum values in `self`.

- `minmax`: Returns the minimum and maximum values in `self`.

- `size`: Returns the count of elements in `self`.

### Methods for Comparing¶ ↑

- `==`: Returns whether a given object is equal to `self` (uses `==`).

- `===`: Returns whether the given object is between the begin and end values.

- `cover?`: Returns whether a given object is within `self`.

- `eql?`: Returns whether a given object is equal to `self` (uses `eql?`).

- `include?` (aliased as `member?`): Returns whether a given object is an element of `self`.

### Methods for Iterating¶ ↑

- `%`: Requires argument `n`; calls the block with each `n`-th element of `self`.

- `each`: Calls the block with each element of `self`.

- `step`: Takes optional argument `n` (defaults to 1); calls the block with each `n`-th element of `self`.

### Methods for Converting¶ ↑

- `inspect`: Returns a string representation of `self` (uses `inspect`).

- `to_a` (aliased as `entries`): Returns elements of `self` in an array.

- `to_s`: Returns a string representation of `self` (uses `to_s`).

### Public Class Methods

json_create(object) click to toggle source

Deserializes `JSON` string by constructing new `Range` object with arguments `a` serialized by `to_json`.

    # File ext/json/lib/json/add/range.rb, line 10
    def self.json_create(object)
      new(*object['a'])
    end

new(begin, end, exclude_end = false) → new_range click to toggle source

Returns a new range based on the given objects `begin` and `end`. Optional argument `exclude_end` determines whether object `end` is included as the last object in the range:

    Range.new(2, 5).to_a            # => [2, 3, 4, 5]
    Range.new(2, 5, true).to_a      # => [2, 3, 4]
    Range.new('a', 'd').to_a        # => ["a", "b", "c", "d"]
    Range.new('a', 'd', true).to_a  # => ["a", "b", "c"]

    static VALUE
    range_initialize(int argc, VALUE *argv, VALUE range)
    {
        VALUE beg, end, flags;

        rb_scan_args(argc, argv, "21", &beg, &end, &flags);
        range_modify(range);
        range_init(range, beg, end, RBOOL(RTEST(flags)));
        return Qnil;
    }

### Public Instance Methods

%(n) {|element| ... } → self click to toggle source
%(n) → enumerator

Iterates over the elements of `self`.

With a block given, calls the block with selected elements of the range; returns `self`:

    a = []
    (1..5).%(2) {|element| a.push(element) } # => 1..5
    a # => [1, 3, 5]
    a = []
    ('a'..'e').%(2) {|element| a.push(element) } # => "a".."e"
    a # => ["a", "c", "e"]

With no block given, returns an enumerator, which will be of class `Enumerator::ArithmeticSequence` if `self` is numeric; otherwise of class Enumerator:

    e = (1..5) % 2 # => ((1..5).%(2))
    e.class        # => Enumerator::ArithmeticSequence
    ('a'..'e') % 2 # =>  #<Enumerator: ...>

Related: `Range#step`.

    static VALUE
    range_percent_step(VALUE range, VALUE step)
    {
        return range_step(1, &step, range);
    }

self == other → true or false click to toggle source

Returns `true` if and only if:

- `other` is a range.

- `other.begin == self.begin`.

- `other.end == self.end`.

- `other.exclude_end? == self.exclude_end?`.

Otherwise returns `false`.

    r = (1..5)
    r == (1..5)                # => true
    r = Range.new(1, 5)
    r == 'foo'                 # => false
    r == (2..5)                # => false
    r == (1..4)                # => false
    r == (1...5)               # => false
    r == Range.new(1, 5, true) # => false

Note that even with the same argument, the return values of `==` and `eql?` can differ:

    (1..2) == (1..2.0)   # => true
    (1..2).eql? (1..2.0) # => false

Related: `Range#eql?`.

    static VALUE
    range_eq(VALUE range, VALUE obj)
    {
        if (range == obj)
            return Qtrue;
        if (!rb_obj_is_kind_of(obj, rb_cRange))
            return Qfalse;

        return rb_exec_recursive_paired(recursive_equal, range, obj, obj);
    }

self === object → true or false click to toggle source

Returns `true` if `object` is between `self.begin` and `self.end`. `false` otherwise:

    (1..4) === 2       # => true
    (1..4) === 5       # => false
    (1..4) === 'a'     # => false
    (1..4) === 4       # => true
    (1...4) === 4      # => false
    ('a'..'d') === 'c' # => true
    ('a'..'d') === 'e' # => false

A case statement uses method `===`, and so:

    case 79
    when (1..50)
      "low"
    when (51..75)
      "medium"
    when (76..100)
      "high"
    end # => "high"

    case "2.6.5"
    when ..."2.4"
      "EOL"
    when "2.4"..."2.5"
      "maintenance"
    when "2.5"..."3.0"
      "stable"
    when "3.1"..
      "upcoming"
    end # => "stable"

    static VALUE
    range_eqq(VALUE range, VALUE val)
    {
        VALUE ret = range_string_cover_internal(range, val);
        if (!UNDEF_P(ret)) return ret;
        return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val);
    }

as_json(*) click to toggle source

Returns a hash, that will be turned into a `JSON` object and represent this object.

    # File ext/json/lib/json/add/range.rb, line 16
    def as_json(*)
      {
        JSON.create_id  => self.class.name,
        'a'             => [ first, last, exclude_end? ]
      }
    end

begin → object click to toggle source

Returns the object that defines the beginning of `self`.

    (1..4).begin # => 1
    (..2).begin  # => nil

Related: `Range#first`, `Range#end`.

    static VALUE
    range_begin(VALUE range)
    {
        return RANGE_BEG(range);
    }

bsearch {|obj| block } → value click to toggle source

Returns an element from `self` selected by a binary search.

See Binary Searching.

    static VALUE
    range_bsearch(VALUE range)
    {
        VALUE beg, end, satisfied = Qnil;
        int smaller;

        /* Implementation notes:
         * Floats are handled by mapping them to 64 bits integers.
         * Apart from sign issues, floats and their 64 bits integer have the
         * same order, assuming they are represented as exponent followed
         * by the mantissa. This is true with or without implicit bit.
         *
         * Finding the average of two ints needs to be careful about
         * potential overflow (since float to long can use 64 bits)
         * as well as the fact that -1/2 can be 0 or -1 in C89.
         *
         * Note that -0.0 is mapped to the same int as 0.0 as we don't want
         * (-1...0.0).bsearch to yield -0.0.
         */

    #define BSEARCH(conv) \
        do { \
            RETURN_ENUMERATOR(range, 0, 0); \
            if (EXCL(range)) high--; \
            org_high = high; \
            while (low < high) { \
                mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
                    : (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \
                BSEARCH_CHECK(conv(mid)); \
                if (smaller) { \
                    high = mid; \
                } \
                else { \
                    low = mid + 1; \
                } \
            } \
            if (low == org_high) { \
                BSEARCH_CHECK(conv(low)); \
                if (!smaller) return Qnil; \
            } \
            return satisfied; \
        } while (0)

        beg = RANGE_BEG(range);
        end = RANGE_END(range);

        if (FIXNUM_P(beg) && FIXNUM_P(end)) {
            long low = FIX2LONG(beg);
            long high = FIX2LONG(end);
            long mid, org_high;
            BSEARCH(INT2FIX);
        }
    #if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
        else if (RB_FLOAT_TYPE_P(beg) || RB_FLOAT_TYPE_P(end)) {
            int64_t low  = double_as_int64(NIL_P(beg) ? -HUGE_VAL : RFLOAT_VALUE(rb_Float(beg)));
            int64_t high = double_as_int64(NIL_P(end) ?  HUGE_VAL : RFLOAT_VALUE(rb_Float(end)));
            int64_t mid, org_high;
            BSEARCH(int64_as_double_to_num);
        }
    #endif
        else if (is_integer_p(beg) && is_integer_p(end)) {
            RETURN_ENUMERATOR(range, 0, 0);
            return bsearch_integer_range(beg, end, EXCL(range));
        }
        else if (is_integer_p(beg) && NIL_P(end)) {
            VALUE diff = LONG2FIX(1);
            RETURN_ENUMERATOR(range, 0, 0);
            while (1) {
                VALUE mid = rb_funcall(beg, '+', 1, diff);
                BSEARCH_CHECK(mid);
                if (smaller) {
                    return bsearch_integer_range(beg, mid, 0);
                }
                diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
            }
        }
        else if (NIL_P(beg) && is_integer_p(end)) {
            VALUE diff = LONG2FIX(-1);
            RETURN_ENUMERATOR(range, 0, 0);
            while (1) {
                VALUE mid = rb_funcall(end, '+', 1, diff);
                BSEARCH_CHECK(mid);
                if (!smaller) {
                    return bsearch_integer_range(mid, end, 0);
                }
                diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
            }
        }
        else {
            rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg));
        }
        return range;
    }

count → integer click to toggle source
count(object) → integer
count {|element| ... } → integer

Returns the count of elements, based on an argument or block criterion, if given.

With no argument and no block given, returns the number of elements:

    (1..4).count      # => 4
    (1...4).count     # => 3
    ('a'..'d').count  # => 4
    ('a'...'d').count # => 3
    (1..).count       # => Infinity
    (..4).count       # => Infinity

With argument `object`, returns the number of `object` found in `self`, which will usually be zero or one:

    (1..4).count(2)   # => 1
    (1..4).count(5)   # => 0
    (1..4).count('a')  # => 0

With a block given, calls the block with each element; returns the number of elements for which the block returns a truthy value:

    (1..4).count {|element| element < 3 } # => 2

Related: `Range#size`.

    static VALUE
    range_count(int argc, VALUE *argv, VALUE range)
    {
        if (argc != 0) {
            /* It is odd for instance (1...).count(0) to return Infinity. Just let
             * it loop. */
            return rb_call_super(argc, argv);
        }
        else if (rb_block_given_p()) {
            /* Likewise it is odd for instance (1...).count {|x| x == 0 } to return
             * Infinity. Just let it loop. */
            return rb_call_super(argc, argv);
        }
        else if (NIL_P(RANGE_END(range))) {
            /* We are confident that the answer is Infinity. */
            return DBL2NUM(HUGE_VAL);
        }
        else if (NIL_P(RANGE_BEG(range))) {
            /* We are confident that the answer is Infinity. */
            return DBL2NUM(HUGE_VAL);
        }
        else {
            return rb_call_super(argc, argv);
        }
    }

cover?(object) → true or false click to toggle source
cover?(range) → true or false

Returns `true` if the given argument is within `self`, `false` otherwise.

With non-range argument `object`, evaluates with `<=` and `<`.

For range `self` with included end value (`#exclude_end? == false`), evaluates thus:

    self.begin <= object <= self.end

Examples:

    r = (1..4)
    r.cover?(1)     # => true
    r.cover?(4)     # => true
    r.cover?(0)     # => false
    r.cover?(5)     # => false
    r.cover?('foo') # => false

    r = ('a'..'d')
    r.cover?('a')     # => true
    r.cover?('d')     # => true
    r.cover?(' ')     # => false
    r.cover?('e')     # => false
    r.cover?(0)       # => false

For range `r` with excluded end value (`#exclude_end? == true`), evaluates thus:

    r.begin <= object < r.end

Examples:

    r = (1...4)
    r.cover?(1)     # => true
    r.cover?(3)     # => true
    r.cover?(0)     # => false
    r.cover?(4)     # => false
    r.cover?('foo') # => false

    r = ('a'...'d')
    r.cover?('a')     # => true
    r.cover?('c')     # => true
    r.cover?(' ')     # => false
    r.cover?('d')     # => false
    r.cover?(0)       # => false

With range argument `range`, compares the first and last elements of `self` and `range`:

    r = (1..4)
    r.cover?(1..4)     # => true
    r.cover?(0..4)     # => false
    r.cover?(1..5)     # => false
    r.cover?('a'..'d') # => false

    r = (1...4)
    r.cover?(1..3)     # => true
    r.cover?(1..4)     # => false

If begin and end are numeric, `cover?` behaves like `include?`

    (1..3).cover?(1.5) # => true
    (1..3).include?(1.5) # => true

But when not numeric, the two methods may differ:

    ('a'..'d').cover?('cc')   # => true
    ('a'..'d').include?('cc') # => false

Returns `false` if either:

- The begin value of `self` is larger than its end value.

- An internal call to `<=>` returns `nil`; that is, the operands are not comparable.

Beginless ranges cover all values of the same type before the end, excluding the end for exclusive ranges. Beginless ranges cover ranges that end before the end of the beginless range, or at the end of the beginless range for inclusive ranges.

    (..2).cover?(1)     # => true
    (..2).cover?(2)     # => true
    (..2).cover?(3)     # => false
    (...2).cover?(2)    # => false
    (..2).cover?("2")   # => false
    (..2).cover?(..2)   # => true
    (..2).cover?(...2)  # => true
    (..2).cover?(.."2") # => false
    (...2).cover?(..2)  # => false

Endless ranges cover all values of the same type after the beginning. Endless exclusive ranges do not cover endless inclusive ranges.

    (2..).cover?(1)     # => false
    (2..).cover?(3)     # => true
    (2...).cover?(3)    # => true
    (2..).cover?(2)     # => true
    (2..).cover?("2")   # => false
    (2..).cover?(2..)   # => true
    (2..).cover?(2...)  # => true
    (2..).cover?("2"..) # => false
    (2...).cover?(2..)  # => false
    (2...).cover?(3...) # => true
    (2...).cover?(3..)  # => false
    (3..).cover?(2..)   # => false

Ranges that are both beginless and endless cover all values and ranges, and return true for all arguments, with the exception that beginless and endless exclusive ranges do not cover endless inclusive ranges.

    (nil...).cover?(Object.new) # => true
    (nil...).cover?(nil...)     # => true
    (nil..).cover?(nil...)      # => true
    (nil...).cover?(nil..)      # => false
    (nil...).cover?(1..)        # => false

Related: `Range#include?`.

    static VALUE
    range_cover(VALUE range, VALUE val)
    {
        VALUE beg, end;

        beg = RANGE_BEG(range);
        end = RANGE_END(range);

        if (rb_obj_is_kind_of(val, rb_cRange)) {
            return RBOOL(r_cover_range_p(range, beg, end, val));
        }
        return r_cover_p(range, beg, end, val);
    }

each {|element| ... } → self click to toggle source
each → an_enumerator

With a block given, passes each element of `self` to the block:

    a = []
    (1..4).each {|element| a.push(element) } # => 1..4
    a # => [1, 2, 3, 4]

Raises an exception unless `self.first.respond_to?(:succ)`.

With no block given, returns an enumerator.

    static VALUE
    range_each(VALUE range)
    {
        VALUE beg, end;
        long i;

        RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);

        beg = RANGE_BEG(range);
        end = RANGE_END(range);

        if (FIXNUM_P(beg) && NIL_P(end)) {
            range_each_fixnum_endless(beg);
        }
        else if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */
            return range_each_fixnum_loop(beg, end, range);
        }
        else if (RB_INTEGER_TYPE_P(beg) && (NIL_P(end) || RB_INTEGER_TYPE_P(end))) {
            if (SPECIAL_CONST_P(end) || RBIGNUM_POSITIVE_P(end)) { /* end >= FIXNUM_MIN */
                if (!FIXNUM_P(beg)) {
                    if (RBIGNUM_NEGATIVE_P(beg)) {
                        do {
                            rb_yield(beg);
                        } while (!FIXNUM_P(beg = rb_big_plus(beg, INT2FIX(1))));
                        if (NIL_P(end)) range_each_fixnum_endless(beg);
                        if (FIXNUM_P(end)) return range_each_fixnum_loop(beg, end, range);
                    }
                    else {
                        if (NIL_P(end)) range_each_bignum_endless(beg);
                        if (FIXNUM_P(end)) return range;
                    }
                }
                if (FIXNUM_P(beg)) {
                    i = FIX2LONG(beg);
                    do {
                        rb_yield(LONG2FIX(i));
                    } while (POSFIXABLE(++i));
                    beg = LONG2NUM(i);
                }
                ASSUME(!FIXNUM_P(beg));
                ASSUME(!SPECIAL_CONST_P(end));
            }
            if (!FIXNUM_P(beg) && RBIGNUM_SIGN(beg) == RBIGNUM_SIGN(end)) {
                if (EXCL(range)) {
                    while (rb_big_cmp(beg, end) == INT2FIX(-1)) {
                        rb_yield(beg);
                        beg = rb_big_plus(beg, INT2FIX(1));
                    }
                }
                else {
                    VALUE c;
                    while ((c = rb_big_cmp(beg, end)) != INT2FIX(1)) {
                        rb_yield(beg);
                        if (c == INT2FIX(0)) break;
                        beg = rb_big_plus(beg, INT2FIX(1));
                    }
                }
            }
        }
        else if (SYMBOL_P(beg) && (NIL_P(end) || SYMBOL_P(end))) { /* symbols are special */
            beg = rb_sym2str(beg);
            if (NIL_P(end)) {
                rb_str_upto_endless_each(beg, sym_each_i, 0);
            }
            else {
                rb_str_upto_each(beg, rb_sym2str(end), EXCL(range), sym_each_i, 0);
            }
        }
        else {
            VALUE tmp = rb_check_string_type(beg);

            if (!NIL_P(tmp)) {
                if (!NIL_P(end)) {
                    rb_str_upto_each(tmp, end, EXCL(range), each_i, 0);
                }
                else {
                    rb_str_upto_endless_each(tmp, each_i, 0);
                }
            }
            else {
                if (!discrete_object_p(beg)) {
                    rb_raise(rb_eTypeError, "can't iterate from %s",
                             rb_obj_classname(beg));
                }
                if (!NIL_P(end))
                    range_each_func(range, each_i, 0);
                else
                    for (;; beg = rb_funcallv(beg, id_succ, 0, 0))
                        rb_yield(beg);
            }
        }
        return range;
    }

end → object click to toggle source

Returns the object that defines the end of `self`.

    (1..4).end  # => 4
    (1...4).end # => 4
    (1..).end   # => nil

Related: `Range#begin`, `Range#last`.

    static VALUE
    range_end(VALUE range)
    {
        return RANGE_END(range);
    }

entries()

Returns an array containing the elements in `self`, if a finite collection; raises an exception otherwise.

    (1..4).to_a     # => [1, 2, 3, 4]
    (1...4).to_a    # => [1, 2, 3]
    ('a'..'d').to_a # => ["a", "b", "c", "d"]

`Range#entries` is an alias for `Range#to_a`.

Alias for: to_a
eql?(other) → true or false click to toggle source

Returns `true` if and only if:

- `other` is a range.

- `other.begin eql? self.begin`.

- `other.end eql? self.end`.

- `other.exclude_end? == self.exclude_end?`.

Otherwise returns `false`.

    r = (1..5)
    r.eql?(1..5)                  # => true
    r = Range.new(1, 5)
    r.eql?('foo')                 # => false
    r.eql?(2..5)                  # => false
    r.eql?(1..4)                  # => false
    r.eql?(1...5)                 # => false
    r.eql?(Range.new(1, 5, true)) # => false

Note that even with the same argument, the return values of `==` and `eql?` can differ:

    (1..2) == (1..2.0)   # => true
    (1..2).eql? (1..2.0) # => false

Related: `Range#==`.

    static VALUE
    range_eql(VALUE range, VALUE obj)
    {
        if (range == obj)
            return Qtrue;
        if (!rb_obj_is_kind_of(obj, rb_cRange))
            return Qfalse;
        return rb_exec_recursive_paired(recursive_eql, range, obj, obj);
    }

exclude_end? → true or false click to toggle source

Returns `true` if `self` excludes its end value; `false` otherwise:

    Range.new(2, 5).exclude_end?       # => false
    Range.new(2, 5, true).exclude_end? # => true
    (2..5).exclude_end?                # => false
    (2...5).exclude_end?               # => true

    static VALUE
    range_exclude_end_p(VALUE range)
    {
        return RBOOL(EXCL(range));
    }

first → object click to toggle source
first(n) → array

With no argument, returns the first element of `self`, if it exists:

    (1..4).first     # => 1
    ('a'..'d').first # => "a"

With non-negative integer argument `n` given, returns the first `n` elements in an array:

    (1..10).first(3) # => [1, 2, 3]
    (1..10).first(0) # => []
    (1..4).first(50) # => [1, 2, 3, 4]

Raises an exception if there is no first element:

    (..4).first # Raises RangeError

    static VALUE
    range_first(int argc, VALUE *argv, VALUE range)
    {
        VALUE n, ary[2];

        if (NIL_P(RANGE_BEG(range))) {
            rb_raise(rb_eRangeError, "cannot get the first element of beginless range");
        }
        if (argc == 0) return RANGE_BEG(range);

        rb_scan_args(argc, argv, "1", &n);
        ary[0] = n;
        ary[1] = rb_ary_new2(NUM2LONG(n));
        rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);

        return ary[1];
    }

hash → integer click to toggle source

Returns the integer hash value for `self`. Two range objects `r0` and `r1` have the same hash value if and only if `r0.eql?(r1)`.

Related: `Range#eql?`, `Object#hash`.

    static VALUE
    range_hash(VALUE range)
    {
        st_index_t hash = EXCL(range);
        VALUE v;

        hash = rb_hash_start(hash);
        v = rb_hash(RANGE_BEG(range));
        hash = rb_hash_uint(hash, NUM2LONG(v));
        v = rb_hash(RANGE_END(range));
        hash = rb_hash_uint(hash, NUM2LONG(v));
        hash = rb_hash_uint(hash, EXCL(range) << 24);
        hash = rb_hash_end(hash);

        return ST2FIX(hash);
    }

include?(object) → true or false

Returns `true` if `object` is an element of `self`, `false` otherwise:

    (1..4).include?(2)        # => true
    (1..4).include?(5)        # => false
    (1..4).include?(4)        # => true
    (1...4).include?(4)       # => false
    ('a'..'d').include?('b')  # => true
    ('a'..'d').include?('e')  # => false
    ('a'..'d').include?('B')  # => false
    ('a'..'d').include?('d')  # => true
    ('a'...'d').include?('d') # => false

If begin and end are numeric, `include?` behaves like `cover?`

    (1..3).include?(1.5) # => true
    (1..3).cover?(1.5) # => true

But when not numeric, the two methods may differ:

    ('a'..'d').include?('cc') # => false
    ('a'..'d').cover?('cc')   # => true

Related: `Range#cover?`.

`Range#member?` is an alias for `Range#include?`.

Alias for: member?
inspect → string click to toggle source

Returns a string representation of `self`, including `begin.inspect` and `end.inspect`:

    (1..4).inspect  # => "1..4"
    (1...4).inspect # => "1...4"
    (1..).inspect   # => "1.."
    (..4).inspect   # => "..4"

Note that returns from `to_s` and `inspect` may differ:

    ('a'..'d').to_s    # => "a..d"
    ('a'..'d').inspect # => "\"a\"..\"d\""

Related: `Range#to_s`.

    static VALUE
    range_inspect(VALUE range)
    {
        return rb_exec_recursive(inspect_range, range, 0);
    }

last → object click to toggle source
last(n) → array

With no argument, returns the last element of `self`, if it exists:

    (1..4).last     # => 4
    ('a'..'d').last # => "d"

Note that `last` with no argument returns the end element of `self` even if `exclude_end?` is `true`:

    (1...4).last     # => 4
    ('a'...'d').last # => "d"

With non-negative integer argument `n` given, returns the last `n` elements in an array:

    (1..10).last(3) # => [8, 9, 10]
    (1..10).last(0) # => []
    (1..4).last(50) # => [1, 2, 3, 4]

Note that `last` with argument does not return the end element of `self` if `exclude_end?` it `true`:

    (1...4).last(3)     # => [1, 2, 3]
    ('a'...'d').last(3) # => ["a", "b", "c"]

Raises an exception if there is no last element:

    (1..).last # Raises RangeError

    static VALUE
    range_last(int argc, VALUE *argv, VALUE range)
    {
        VALUE b, e;

        if (NIL_P(RANGE_END(range))) {
            rb_raise(rb_eRangeError, "cannot get the last element of endless range");
        }
        if (argc == 0) return RANGE_END(range);

        b = RANGE_BEG(range);
        e = RANGE_END(range);
        if (RB_INTEGER_TYPE_P(b) && RB_INTEGER_TYPE_P(e) &&
            RB_LIKELY(rb_method_basic_definition_p(rb_cRange, idEach))) {
            return rb_int_range_last(argc, argv, range);
        }
        return rb_ary_last(argc, argv, rb_Array(range));
    }

max → object click to toggle source
max(n) → array
max {|a, b| ... } → object
max(n) {|a, b| ... } → array

Returns the maximum value in `self`, using method `<=>` or a given block for comparison.

With no argument and no block given, returns the maximum-valued element of `self`.

    (1..4).max     # => 4
    ('a'..'d').max # => "d"
    (-4..-1).max   # => -1

With non-negative integer argument `n` given, and no block given, returns the `n` maximum-valued elements of `self` in an array:

    (1..4).max(2)     # => [4, 3]
    ('a'..'d').max(2) # => ["d", "c"]
    (-4..-1).max(2)   # => [-1, -2]
    (1..4).max(50)    # => [4, 3, 2, 1]

If a block is given, it is called:

- First, with the first two element of `self`.

- Then, sequentially, with the so-far maximum value and the next element of `self`.

To illustrate:

    (1..4).max {|a, b| p [a, b]; a <=> b } # => 4

Output:

    [2, 1]
    [3, 2]
    [4, 3]

With no argument and a block given, returns the return value of the last call to the block:

    (1..4).max {|a, b| -(a <=> b) } # => 1

With non-negative integer argument `n` given, and a block given, returns the return values of the last `n` calls to the block in an array:

    (1..4).max(2) {|a, b| -(a <=> b) }  # => [1, 2]
    (1..4).max(50) {|a, b| -(a <=> b) } # => [1, 2, 3, 4]

Returns an empty array if `n` is zero:

    (1..4).max(0)                      # => []
    (1..4).max(0) {|a, b| -(a <=> b) } # => []

Returns `nil` or an empty array if:

- The begin value of the range is larger than the end value:

      (4..1).max                         # => nil
      (4..1).max(2)                      # => []
      (4..1).max {|a, b| -(a <=> b) }    # => nil
      (4..1).max(2) {|a, b| -(a <=> b) } # => []

- The begin value of an exclusive range is equal to the end value:

      (1...1).max                          # => nil
      (1...1).max(2)                       # => []
      (1...1).max  {|a, b| -(a <=> b) }    # => nil
      (1...1).max(2)  {|a, b| -(a <=> b) } # => []

Raises an exception if either:

- `self` is a endless range: `(1..)`.

- A block is given and `self` is a beginless range.

Related: `Range#min`, `Range#minmax`.

    static VALUE
    range_max(int argc, VALUE *argv, VALUE range)
    {
        VALUE e = RANGE_END(range);
        int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric);

        if (NIL_P(RANGE_END(range))) {
            rb_raise(rb_eRangeError, "cannot get the maximum of endless range");
        }

        VALUE b = RANGE_BEG(range);

        if (rb_block_given_p() || (EXCL(range) && !nm) || argc) {
            if (NIL_P(b)) {
                rb_raise(rb_eRangeError, "cannot get the maximum of beginless range with custom comparison method");
            }
            return rb_call_super(argc, argv);
        }
        else {
            int c = NIL_P(b) ? -1 : OPTIMIZED_CMP(b, e);

            if (c > 0)
                return Qnil;
            if (EXCL(range)) {
                if (!RB_INTEGER_TYPE_P(e)) {
                    rb_raise(rb_eTypeError, "cannot exclude non Integer end value");
                }
                if (c == 0) return Qnil;
                if (!RB_INTEGER_TYPE_P(b)) {
                    rb_raise(rb_eTypeError, "cannot exclude end value with non Integer begin value");
                }
                if (FIXNUM_P(e)) {
                    return LONG2NUM(FIX2LONG(e) - 1);
                }
                return rb_funcall(e, '-', 1, INT2FIX(1));
            }
            return e;
        }
    }

member?(object) -> true or false click to toggle source

Returns `true` if `object` is an element of `self`, `false` otherwise:

    (1..4).include?(2)        # => true
    (1..4).include?(5)        # => false
    (1..4).include?(4)        # => true
    (1...4).include?(4)       # => false
    ('a'..'d').include?('b')  # => true
    ('a'..'d').include?('e')  # => false
    ('a'..'d').include?('B')  # => false
    ('a'..'d').include?('d')  # => true
    ('a'...'d').include?('d') # => false

If begin and end are numeric, `include?` behaves like `cover?`

    (1..3).include?(1.5) # => true
    (1..3).cover?(1.5) # => true

But when not numeric, the two methods may differ:

    ('a'..'d').include?('cc') # => false
    ('a'..'d').cover?('cc')   # => true

Related: `Range#cover?`.

`Range#member?` is an alias for `Range#include?`.

    static VALUE
    range_include(VALUE range, VALUE val)
    {
        VALUE ret = range_include_internal(range, val);
        if (!UNDEF_P(ret)) return ret;
        return rb_call_super(1, &val);
    }

Also aliased as: include?
min → object click to toggle source
min(n) → array
min {|a, b| ... } → object
min(n) {|a, b| ... } → array

Returns the minimum value in `self`, using method `<=>` or a given block for comparison.

With no argument and no block given, returns the minimum-valued element of `self`.

    (1..4).min     # => 1
    ('a'..'d').min # => "a"
    (-4..-1).min   # => -4

With non-negative integer argument `n` given, and no block given, returns the `n` minimum-valued elements of `self` in an array:

    (1..4).min(2)     # => [1, 2]
    ('a'..'d').min(2) # => ["a", "b"]
    (-4..-1).min(2)   # => [-4, -3]
    (1..4).min(50)    # => [1, 2, 3, 4]

If a block is given, it is called:

- First, with the first two element of `self`.

- Then, sequentially, with the so-far minimum value and the next element of `self`.

To illustrate:

    (1..4).min {|a, b| p [a, b]; a <=> b } # => 1

Output:

    [2, 1]
    [3, 1]
    [4, 1]

With no argument and a block given, returns the return value of the last call to the block:

    (1..4).min {|a, b| -(a <=> b) } # => 4

With non-negative integer argument `n` given, and a block given, returns the return values of the last `n` calls to the block in an array:

    (1..4).min(2) {|a, b| -(a <=> b) }  # => [4, 3]
    (1..4).min(50) {|a, b| -(a <=> b) } # => [4, 3, 2, 1]

Returns an empty array if `n` is zero:

    (1..4).min(0)                      # => []
    (1..4).min(0) {|a, b| -(a <=> b) } # => []

Returns `nil` or an empty array if:

- The begin value of the range is larger than the end value:

      (4..1).min                         # => nil
      (4..1).min(2)                      # => []
      (4..1).min {|a, b| -(a <=> b) }    # => nil
      (4..1).min(2) {|a, b| -(a <=> b) } # => []

- The begin value of an exclusive range is equal to the end value:

      (1...1).min                          # => nil
      (1...1).min(2)                       # => []
      (1...1).min  {|a, b| -(a <=> b) }    # => nil
      (1...1).min(2)  {|a, b| -(a <=> b) } # => []

Raises an exception if either:

- `self` is a beginless range: `(..4)`.

- A block is given and `self` is an endless range.

Related: `Range#max`, `Range#minmax`.

    static VALUE
    range_min(int argc, VALUE *argv, VALUE range)
    {
        if (NIL_P(RANGE_BEG(range))) {
            rb_raise(rb_eRangeError, "cannot get the minimum of beginless range");
        }

        if (rb_block_given_p()) {
            if (NIL_P(RANGE_END(range))) {
                rb_raise(rb_eRangeError, "cannot get the minimum of endless range with custom comparison method");
            }
            return rb_call_super(argc, argv);
        }
        else if (argc != 0) {
            return range_first(argc, argv, range);
        }
        else {
            VALUE b = RANGE_BEG(range);
            VALUE e = RANGE_END(range);
            int c = NIL_P(e) ? -1 : OPTIMIZED_CMP(b, e);

            if (c > 0 || (c == 0 && EXCL(range)))
                return Qnil;
            return b;
        }
    }

minmax → [object, object] click to toggle source
minmax {|a, b| ... } → [object, object]

Returns a 2-element array containing the minimum and maximum value in `self`, either according to comparison method `<=>` or a given block.

With no block given, returns the minimum and maximum values, using `<=>` for comparison:

    (1..4).minmax     # => [1, 4]
    (1...4).minmax    # => [1, 3]
    ('a'..'d').minmax # => ["a", "d"]
    (-4..-1).minmax   # => [-4, -1]

With a block given, the block must return an integer:

- Negative if `a` is smaller than `b`.

- Zero if `a` and `b` are equal.

- Positive if `a` is larger than `b`.

The block is called `self.size` times to compare elements; returns a 2-element `Array` containing the minimum and maximum values from `self`, per the block:

    (1..4).minmax {|a, b| -(a <=> b) } # => [4, 1]

Returns `[nil, nil]` if:

- The begin value of the range is larger than the end value:

      (4..1).minmax                      # => [nil, nil]
      (4..1).minmax {|a, b| -(a <=> b) } # => [nil, nil]

- The begin value of an exclusive range is equal to the end value:

      (1...1).minmax                          # => [nil, nil]
      (1...1).minmax  {|a, b| -(a <=> b) }    # => [nil, nil]

Raises an exception if `self` is a beginless or an endless range.

Related: `Range#min`, `Range#max`.

    static VALUE
    range_minmax(VALUE range)
    {
        if (rb_block_given_p()) {
            return rb_call_super(0, NULL);
        }
        return rb_assoc_new(
            rb_funcall(range, id_min, 0),
            rb_funcall(range, id_max, 0)
        );
    }

size → non_negative_integer or Infinity or nil click to toggle source

Returns the count of elements in `self` if both begin and end values are numeric; otherwise, returns `nil`:

    (1..4).size      # => 4
    (1...4).size     # => 3
    (1..).size       # => Infinity
    ('a'..'z').size  #=> nil

Related: `Range#count`.

    static VALUE
    range_size(VALUE range)
    {
        VALUE b = RANGE_BEG(range), e = RANGE_END(range);
        if (rb_obj_is_kind_of(b, rb_cNumeric)) {
            if (rb_obj_is_kind_of(e, rb_cNumeric)) {
                return ruby_num_interval_step_size(b, e, INT2FIX(1), EXCL(range));
            }
            if (NIL_P(e)) {
                return DBL2NUM(HUGE_VAL);
            }
        }
        else if (NIL_P(b)) {
            if (rb_obj_is_kind_of(e, rb_cNumeric)) {
                return DBL2NUM(HUGE_VAL);
            }
        }

        return Qnil;
    }

step(n = 1) {|element| ... } → self click to toggle source
step(n = 1) → enumerator

Iterates over the elements of `self`.

With a block given and no argument, calls the block each element of the range; returns `self`:

    a = []
    (1..5).step {|element| a.push(element) } # => 1..5
    a # => [1, 2, 3, 4, 5]
    a = []
    ('a'..'e').step {|element| a.push(element) } # => "a".."e"
    a # => ["a", "b", "c", "d", "e"]

With a block given and a positive integer argument `n` given, calls the block with element `0`, element `n`, element `2n`, and so on:

    a = []
    (1..5).step(2) {|element| a.push(element) } # => 1..5
    a # => [1, 3, 5]
    a = []
    ('a'..'e').step(2) {|element| a.push(element) } # => "a".."e"
    a # => ["a", "c", "e"]

With no block given, returns an enumerator, which will be of class `Enumerator::ArithmeticSequence` if `self` is numeric; otherwise of class Enumerator:

    e = (1..5).step(2) # => ((1..5).step(2))
    e.class            # => Enumerator::ArithmeticSequence
    ('a'..'e').step # => #<Enumerator: ...>

Related: `Range#%`.

    static VALUE
    range_step(int argc, VALUE *argv, VALUE range)
    {
        VALUE b, e, step, tmp;

        b = RANGE_BEG(range);
        e = RANGE_END(range);
        step = (!rb_check_arity(argc, 0, 1) ? INT2FIX(1) : argv[0]);

        if (!rb_block_given_p()) {
            if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
                step = rb_to_int(step);
            }
            if (rb_equal(step, INT2FIX(0))) {
                rb_raise(rb_eArgError, "step can't be 0");
            }

            const VALUE b_num_p = rb_obj_is_kind_of(b, rb_cNumeric);
            const VALUE e_num_p = rb_obj_is_kind_of(e, rb_cNumeric);
            if ((b_num_p && (NIL_P(e) || e_num_p)) || (NIL_P(b) && e_num_p)) {
                return rb_arith_seq_new(range, ID2SYM(rb_frame_this_func()), argc, argv,
                        range_step_size, b, e, step, EXCL(range));
            }

            RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size);
        }

        step = check_step_domain(step);
        VALUE iter[2] = {INT2FIX(1), step};

        if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) {
            long i = FIX2LONG(b), unit = FIX2LONG(step);
            do {
                rb_yield(LONG2FIX(i));
                i += unit;          /* FIXABLE+FIXABLE never overflow */
            } while (FIXABLE(i));
            b = LONG2NUM(i);

            for (;; b = rb_big_plus(b, step))
                rb_yield(b);
        }
        else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
            long end = FIX2LONG(e);
            long i, unit = FIX2LONG(step);

            if (!EXCL(range))
                end += 1;
            i = FIX2LONG(b);
            while (i < end) {
                rb_yield(LONG2NUM(i));
                if (i + unit < i) break;
                i += unit;
            }

        }
        else if (SYMBOL_P(b) && (NIL_P(e) || SYMBOL_P(e))) { /* symbols are special */
            b = rb_sym2str(b);
            if (NIL_P(e)) {
                rb_str_upto_endless_each(b, sym_step_i, (VALUE)iter);
            }
            else {
                rb_str_upto_each(b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter);
            }
        }
        else if (ruby_float_step(b, e, step, EXCL(range), TRUE)) {
            /* done */
        }
        else if (rb_obj_is_kind_of(b, rb_cNumeric) ||
                 !NIL_P(rb_check_to_integer(b, "to_int")) ||
                 !NIL_P(rb_check_to_integer(e, "to_int"))) {
            ID op = EXCL(range) ? '<' : idLE;
            VALUE v = b;
            int i = 0;

            while (NIL_P(e) || RTEST(rb_funcall(v, op, 1, e))) {
                rb_yield(v);
                i++;
                v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step));
            }
        }
        else {
            tmp = rb_check_string_type(b);

            if (!NIL_P(tmp)) {
                b = tmp;
                if (NIL_P(e)) {
                    rb_str_upto_endless_each(b, step_i, (VALUE)iter);
                }
                else {
                    rb_str_upto_each(b, e, EXCL(range), step_i, (VALUE)iter);
                }
            }
            else {
                if (!discrete_object_p(b)) {
                    rb_raise(rb_eTypeError, "can't iterate from %s",
                             rb_obj_classname(b));
                }
                if (!NIL_P(e))
                    range_each_func(range, step_i, (VALUE)iter);
                else
                    for (;; b = rb_funcallv(b, id_succ, 0, 0))
                        step_i(b, (VALUE)iter);
            }
        }
        return range;
    }

to_a → array click to toggle source

Returns an array containing the elements in `self`, if a finite collection; raises an exception otherwise.

    (1..4).to_a     # => [1, 2, 3, 4]
    (1...4).to_a    # => [1, 2, 3]
    ('a'..'d').to_a # => ["a", "b", "c", "d"]

`Range#entries` is an alias for `Range#to_a`.

    static VALUE
    range_to_a(VALUE range)
    {
        if (NIL_P(RANGE_END(range))) {
            rb_raise(rb_eRangeError, "cannot convert endless range to an array");
        }
        return rb_call_super(0, 0);
    }

Also aliased as: entries
to_json(*args) click to toggle source

Stores class name (`Range`) with `JSON` array of arguments `a` which include `first` (integer), `last` (integer), and `exclude_end?` (boolean) as `JSON` string.

    # File ext/json/lib/json/add/range.rb, line 26
    def to_json(*args)
      as_json.to_json(*args)
    end

to_s → string click to toggle source

Returns a string representation of `self`, including `begin.to_s` and `end.to_s`:

    (1..4).to_s  # => "1..4"
    (1...4).to_s # => "1...4"
    (1..).to_s   # => "1.."
    (..4).to_s   # => "..4"

Note that returns from `to_s` and `inspect` may differ:

    ('a'..'d').to_s    # => "a..d"
    ('a'..'d').inspect # => "\"a\"..\"d\""

Related: `Range#inspect`.

    static VALUE
    range_to_s(VALUE range)
    {
        VALUE str, str2;

        str = rb_obj_as_string(RANGE_BEG(range));
        str2 = rb_obj_as_string(RANGE_END(range));
        str = rb_str_dup(str);
        rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
        rb_str_append(str, str2);

        return str;
    }