Class: Range

Inherits:
Object show all
Includes:
Enumerable
Defined in:
range.c

Overview

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"]
    
  • 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]
# Include the third array element in the slice
r = (..2)  # => nil..2
a[r]       # => [1, 2, 3]
# Exclude the third array element from the slice
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 method #<=>; 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:

Here, class Range provides methods that are useful for:

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).

Methods for Working with JSON

  • ::json_create: Returns a new Range object constructed from the given object.

  • #as_json: Returns a 2-element hash representing self.

  • #to_json: Returns a JSON string representing self.

To make these methods available:

require 'json/add/range'

Instance Method Summary collapse

Methods included from Enumerable

#all?, #any?, #chain, #chunk, #chunk_while, #collect, #collect_concat, #compact, #cycle, #detect, #drop, #drop_while, #each_cons, #each_entry, #each_slice, #each_with_index, #each_with_object, #filter, #filter_map, #find, #find_all, #find_index, #flat_map, #grep, #grep_v, #group_by, #inject, #lazy, #map, #max_by, #min_by, #minmax_by, #none?, #one?, #partition, #reduce, #reject, #select, #slice_after, #slice_before, #slice_when, #sort, #sort_by, #sum, #take, #take_while, #tally, #to_h, #uniq, #zip

Constructor Details

#newObject

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"]


101
102
103
104
105
106
107
108
109
110
# File 'range.c', line 101

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;
}

Instance Method Details

#%(n) {|element| ... } ⇒ self #%(n) ⇒ Object

Same as #step (but doesn’t provide default value for n). The method is convenient for experssive producing of Enumerator::ArithmeticSequence.

array = [0, 1, 2, 3, 4, 5, 6]

# slice each second element:
seq = (0..) % 2 #=> ((0..).%(2))
array[seq] #=> [0, 2, 4, 6]
# or just
array[(0..) % 2] #=> [0, 2, 4, 6]

Note that due to operator precedence in Ruby, parentheses are mandatory around range in this case:

(0..7) % 2 #=> ((0..7).%(2)) -- as expected
0..7 % 2 #=> 0..1 -- parsed as 0..(7 % 2)

Overloads:

  • #%(n) {|element| ... } ⇒ self

    Yields:

    • (element)

    Returns:

    • (self)


669
670
671
672
673
# File 'range.c', line 669

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

#==(other) ⇒ Boolean

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?.

Returns:

  • (Boolean)


183
184
185
186
187
188
189
190
191
192
# File 'range.c', line 183

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);
}

#===(object) ⇒ Boolean

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"

Returns:

  • (Boolean)


2036
2037
2038
2039
2040
# File 'range.c', line 2036

static VALUE
range_eqq(VALUE range, VALUE val)
{
    return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val);
}

#beginObject

Returns the object that defines the beginning of self.

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

Related: Range#first, Range#end.

Returns:



1325
1326
1327
1328
1329
# File 'range.c', line 1325

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

#bsearch {|obj| ... } ⇒ Object

Returns an element from self selected by a binary search.

See Binary Searching.

Yields:

  • (obj)


790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
# File 'range.c', line 790

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).
     *
     * The half-open interval (low, high] indicates where the target is located.
     * The loop continues until low and high are adjacent.
     *
     * -1/2 can be either 0 or -1 in C89. However, when low and high are not adjacent,
     * the rounding direction of mid = (low + high) / 2 does not affect the result of
     * the binary search.
     *
     * 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, excl) \
    do { \
        RETURN_ENUMERATOR(range, 0, 0); \
        if (!(excl)) high++; \
        low--; \
        while (low + 1 < high) { \
            mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
                : (low + high) / 2; \
            BSEARCH_CHECK(conv(mid)); \
            if (smaller) { \
                high = mid; \
            } \
            else { \
                low = mid; \
            } \
        } \
        return satisfied; \
    } while (0)

#define BSEARCH_FIXNUM(beg, end, excl) \
    do { \
        long low = FIX2LONG(beg); \
        long high = FIX2LONG(end); \
        long mid; \
        BSEARCH(INT2FIX, (excl)); \
    } while (0)

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

    if (FIXNUM_P(beg) && FIXNUM_P(end)) {
        BSEARCH_FIXNUM(beg, end, EXCL(range));
    }
#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;
        BSEARCH(int64_as_double_to_num, EXCL(range));
    }
#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) {
                if (FIXNUM_P(beg) && FIXNUM_P(mid)) {
                    BSEARCH_FIXNUM(beg, mid, false);
                }
                else {
                    return bsearch_integer_range(beg, mid, false);
                }
            }
            diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
            beg = mid;
        }
    }
    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) {
                if (FIXNUM_P(mid) && FIXNUM_P(end)) {
                    BSEARCH_FIXNUM(mid, end, false);
                }
                else {
                    return bsearch_integer_range(mid, end, false);
                }
            }
            diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
            end = mid;
        }
    }
    else {
        rb_raise(rb_eTypeError, "can't do binary search for s", rb_obj_classname(beg));
    }
    return range;
}

#countInteger #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.

Overloads:



2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
# File 'range.c', line 2395

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);
    }

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

    if (NIL_P(beg) || NIL_P(end)) {
        /* We are confident that the answer is Infinity. */
        return DBL2NUM(HUGE_VAL);
    }

    if (is_integer_p(beg)) {
        VALUE size = range_size(range);
        if (!NIL_P(size)) {
            return size;
        }
    }

    return rb_call_super(argc, argv);
}

#cover?(object) ⇒ Boolean #cover?(range) ⇒ Boolean

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?.

Overloads:

  • #cover?(object) ⇒ Boolean

    Returns:

    • (Boolean)
  • #cover?(range) ⇒ Boolean

    Returns:

    • (Boolean)


2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
# File 'range.c', line 2254

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 #eachObject

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.

Overloads:

  • #each {|element| ... } ⇒ self

    Yields:

    • (element)

    Returns:

    • (self)


1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
# File 'range.c', line 1081

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;
}

#endObject

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.

Returns:



1346
1347
1348
1349
1350
# File 'range.c', line 1346

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

#to_aArray

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"]

Returns:



1011
1012
1013
1014
1015
1016
1017
1018
# File 'range.c', line 1011

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);
}

#eql?(other) ⇒ Boolean

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#==.

Returns:

  • (Boolean)


251
252
253
254
255
256
257
258
259
# File 'range.c', line 251

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?Boolean

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

Returns:

  • (Boolean)


133
134
135
136
137
# File 'range.c', line 133

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

#firstObject #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

Overloads:



1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
# File 'range.c', line 1390

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];
}

#hashInteger

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.

Returns:



272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
# File 'range.c', line 272

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) ⇒ Boolean

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?.

Returns:

  • (Boolean)


2072
2073
2074
2075
2076
2077
2078
# File 'range.c', line 2072

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);
}

#initialize_copy(orig) ⇒ Object

:nodoc:



113
114
115
116
117
118
119
# File 'range.c', line 113

static VALUE
range_initialize_copy(VALUE range, VALUE orig)
{
    range_modify(range);
    rb_struct_init_copy(range, orig);
    return range;
}

#inspectString

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.

Returns:



1988
1989
1990
1991
1992
# File 'range.c', line 1988

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

#lastObject #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

Overloads:



1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
# File 'range.c', line 1496

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));
}

#maxObject #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.

Overloads:



1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
# File 'range.c', line 1705

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;
    }
}

#include?(object) ⇒ Boolean

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?.

Returns:

  • (Boolean)


2072
2073
2074
2075
2076
2077
2078
# File 'range.c', line 2072

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);
}

#minObject #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.

Overloads:



1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
# File 'range.c', line 1597

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;
    }
}

#minmaxArray #minmax {|a, b| ... } ⇒ Array

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.

Overloads:

  • #minmaxArray

    Returns:

  • #minmax {|a, b| ... } ⇒ Array

    Yields:

    • (a, b)

    Returns:



1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
# File 'range.c', line 1791

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)
    );
}

#overlap?(range) ⇒ Boolean

Returns true if range overlaps with self, false otherwise:

(0..2).overlap?(1..3) #=> true
(0..2).overlap?(3..4) #=> false
(0..).overlap?(..0)   #=> true

With non-range argument, raises TypeError.

(1..3).overlap?(1)         # TypeError

Returns false if an internal call to #<=> returns nil; that is, the operands are not comparable.

(1..3).overlap?('a'..'d')  # => false

Returns false if self or range is empty. “Empty range” means that its begin value is larger than, or equal for an exclusive range, its end value.

(4..1).overlap?(2..3)      # => false
(4..1).overlap?(..3)       # => false
(4..1).overlap?(2..)       # => false
(2...2).overlap?(1..2)     # => false

(1..4).overlap?(3..2)      # => false
(..4).overlap?(3..2)       # => false
(1..).overlap?(3..2)       # => false
(1..2).overlap?(2...2)     # => false

Returns false if the begin value one of self and range is larger than, or equal if the other is an exclusive range, the end value of the other:

(4..5).overlap?(2..3)      # => false
(4..5).overlap?(2...4)     # => false

(1..2).overlap?(3..4)      # => false
(1...3).overlap?(3..4)     # => false

Returns false if the end value one of self and range is larger than, or equal for an exclusive range, the end value of the other:

(4..5).overlap?(2..3)      # => false
(4..5).overlap?(2...4)     # => false

(1..2).overlap?(3..4)      # => false
(1...3).overlap?(3..4)     # => false

Note that the method wouldn’t make any assumptions about the beginless range being actually empty, even if its upper bound is the minimum possible value of its type, so all this would return true:

(...-Float::INFINITY).overlap?(...-Float::INFINITY) # => true
(..."").overlap?(..."") # => true
(...[]).overlap?(...[]) # => true

Even if those ranges are effectively empty (no number can be smaller than -Float::INFINITY), they are still considered overlapping with themselves.

Related: Range#cover?.

Returns:

  • (Boolean)


2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
# File 'range.c', line 2506

static VALUE
range_overlap(VALUE range, VALUE other)
{
    if (!rb_obj_is_kind_of(other, rb_cRange)) {
        rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE" (expected Range)",
                 rb_class_name(rb_obj_class(other)));
    }

    VALUE self_beg = RANGE_BEG(range);
    VALUE self_end = RANGE_END(range);
    int self_excl = EXCL(range);
    VALUE other_beg = RANGE_BEG(other);
    VALUE other_end = RANGE_END(other);
    int other_excl = EXCL(other);

    if (empty_region_p(self_beg, other_end, other_excl)) return Qfalse;
    if (empty_region_p(other_beg, self_end, self_excl)) return Qfalse;

    if (!NIL_P(self_beg) && !NIL_P(other_beg)) {
        VALUE cmp = rb_funcall(self_beg, id_cmp, 1, other_beg);
        if (NIL_P(cmp)) return Qfalse;
        /* if both begin values are equal, no more comparisons needed */
        if (rb_cmpint(cmp, self_beg, other_beg) == 0) return Qtrue;
    }
    else if (NIL_P(self_beg) && !NIL_P(self_end) && NIL_P(other_beg)) {
        VALUE cmp = rb_funcall(self_end, id_cmp, 1, other_end);
        return RBOOL(!NIL_P(cmp));
    }

    if (empty_region_p(self_beg, self_end, self_excl)) return Qfalse;
    if (empty_region_p(other_beg, other_end, other_excl)) return Qfalse;

    return Qtrue;
}

#reverse_each {|element| ... } ⇒ self #reverse_eachObject

With a block given, passes each element of self to the block in reverse order:

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

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

With no block given, returns an enumerator.

Overloads:

  • #reverse_each {|element| ... } ⇒ self

    Yields:

    • (element)

    Returns:

    • (self)


1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
# File 'range.c', line 1275

static VALUE
range_reverse_each(VALUE range)
{
    RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_reverse_size);

    VALUE beg = RANGE_BEG(range);
    VALUE end = RANGE_END(range);
    int excl = EXCL(range);

    if (NIL_P(end)) {
        rb_raise(rb_eTypeError, "can't iterate from %s",
                 rb_obj_classname(end));
    }

    if (FIXNUM_P(beg) && FIXNUM_P(end)) {
        if (excl) {
            if (end == LONG2FIX(FIXNUM_MIN)) return range;

            end = rb_int_minus(end, INT2FIX(1));
        }

        range_reverse_each_fixnum_section(beg, end);
    }
    else if ((NIL_P(beg) || RB_INTEGER_TYPE_P(beg)) && RB_INTEGER_TYPE_P(end)) {
        if (excl) {
            end = rb_int_minus(end, INT2FIX(1));
        }
        range_reverse_each_positive_bignum_section(beg, end);
        range_reverse_each_fixnum_section(beg, end);
        range_reverse_each_negative_bignum_section(beg, end);
    }
    else {
        return rb_call_super(0, NULL);
    }

    return range;
}

#sizeInfinity?

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

If self is not iterable, raises an exception:

(0.5..2.5).size  # TypeError
(..1).size       # TypeError

Related: Range#count.

Returns:

  • (Infinity, nil)


941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
# File 'range.c', line 941

static VALUE
range_size(VALUE range)
{
    VALUE b = RANGE_BEG(range), e = RANGE_END(range);

    if (RB_INTEGER_TYPE_P(b)) {
        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);
        }
    }

    if (!discrete_object_p(b)) {
        CANT_ITERATE_FROM(b);
    }

    return Qnil;
}

#step(s = 1) {|element| ... } ⇒ self #step(s = 1) ⇒ Object

Iterates over the elements of range in steps of s. The iteration is performed by + operator:

(0..6).step(2) { puts _1 } #=> 1..5
# Prints: 0, 2, 4, 6

# Iterate between two dates in step of 1 day (24 hours)
(Time.utc(2022, 2, 24)..Time.utc(2022, 3, 1)).step(24*60*60) { puts _1 }
# Prints:
#   2022-02-24 00:00:00 UTC
#   2022-02-25 00:00:00 UTC
#   2022-02-26 00:00:00 UTC
#   2022-02-27 00:00:00 UTC
#   2022-02-28 00:00:00 UTC
#   2022-03-01 00:00:00 UTC

If + step decreases the value, iteration is still performed when step begin is higher than the end:

(0..6).step(-2) { puts _1 }
# Prints nothing

(6..0).step(-2) { puts _1 }
# Prints: 6, 4, 2, 0

(Time.utc(2022, 3, 1)..Time.utc(2022, 2, 24)).step(-24*60*60) { puts _1 }
# Prints:
#   2022-03-01 00:00:00 UTC
#   2022-02-28 00:00:00 UTC
#   2022-02-27 00:00:00 UTC
#   2022-02-26 00:00:00 UTC
#   2022-02-25 00:00:00 UTC
#   2022-02-24 00:00:00 UTC

When the block is not provided, and range boundaries and step are Numeric, the method returns Enumerator::ArithmeticSequence.

(1..5).step(2) # => ((1..5).step(2))
(1.0..).step(1.5) #=> ((1.0..).step(1.5))
(..3r).step(1/3r) #=> ((..3/1).step((1/3)))

Enumerator::ArithmeticSequence can be further used as a value object for iteration or slicing of collections (see Array#[]). There is a convenience method #% with behavior similar to step to produce arithmetic sequences more expressively:

# Same as (1..5).step(2)
(1..5) % 2 # => ((1..5).%(2))

In a generic case, when the block is not provided, Enumerator is returned:

('a'..).step('b')         #=> #<Enumerator: "a"..:step("b")>
('a'..).step('b').take(3) #=> ["a", "ab", "abb"]

If s is not provided, it is considered 1 for ranges with numeric begin:

(1..5).step { p _1 }
# Prints: 1, 2, 3, 4, 5

For non-Numeric ranges, step absence is an error:

(Time.utc(2022, 3, 1)..Time.utc(2022, 2, 24)).step { p _1 }
# raises: step is required for non-numeric ranges (ArgumentError)

For backward compatibility reasons, String ranges support the iteration both with string step and with integer step. In the latter case, the iteration is performed by calculating the next values with String#succ:

('a'..'e').step(2) { p _1 }
# Prints: a, c, e
('a'..'e').step { p _1 }
# Default step 1; prints: a, b, c, d, e

Overloads:

  • #step(s = 1) {|element| ... } ⇒ self

    Yields:

    • (element)

    Returns:

    • (self)


483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
# File 'range.c', line 483

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

    b = RANGE_BEG(range);
    e = RANGE_END(range);
    v = b;

    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);
    // For backward compatibility reasons (conforming to behavior before 3.4), String/Symbol
    // supports both old behavior ('a'..).step(1) and new behavior ('a'..).step('a')
    // Hence the additional conversion/additional checks.
    const VALUE str_b = rb_check_string_type(b);
    const VALUE sym_b = SYMBOL_P(b) ? rb_sym2str(b) : Qnil;

    if (rb_check_arity(argc, 0, 1))
        step = argv[0];
    else {
        if (b_num_p || !NIL_P(str_b) || !NIL_P(sym_b) || (NIL_P(b) && e_num_p))
            step = INT2FIX(1);
        else
            rb_raise(rb_eArgError, "step is required for non-numeric ranges");
    }

    const VALUE step_num_p = rb_obj_is_kind_of(step, rb_cNumeric);

    if (step_num_p && b_num_p && rb_equal(step, INT2FIX(0))) {
        rb_raise(rb_eArgError, "step can't be 0");
    }

    if (!rb_block_given_p()) {
        // This code is allowed to create even beginless ArithmeticSequence, which can be useful,
        // e.g., for array slicing:
        //   ary[(..-1) % 3]
        if (step_num_p && ((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));
        }

        // ...but generic Enumerator from beginless range is useless and probably an error.
        if (NIL_P(b)) {
            rb_raise(rb_eArgError, "#step for non-numeric beginless ranges is meaningless");
        }

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

    if (NIL_P(b)) {
        rb_raise(rb_eArgError, "#step iteration for beginless ranges is meaningless");
    }

    if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) {
        /* perform summation of numbers in C until their reach Fixnum limit */
        long i = FIX2LONG(b), unit = FIX2LONG(step);
        do {
            rb_yield(LONG2FIX(i));
            i += unit;          /* FIXABLE+FIXABLE never overflow */
        } while (FIXABLE(i));
        b = LONG2NUM(i);

        /* then switch to Bignum API */
        for (;; b = rb_big_plus(b, step))
            rb_yield(b);
    }
    else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) {
        /* fixnums are special: summation is performed in C for performance */
        long end = FIX2LONG(e);
        long i, unit = FIX2LONG(step);

        if (unit < 0) {
            if (!EXCL(range))
                end -= 1;
            i = FIX2LONG(b);
            while (i > end) {
                rb_yield(LONG2NUM(i));
                i += unit;
            }
        }
        else {
            if (!EXCL(range))
                end += 1;
            i = FIX2LONG(b);
            while (i < end) {
                rb_yield(LONG2NUM(i));
                i += unit;
            }
        }
    }
    else if (b_num_p && step_num_p && ruby_float_step(b, e, step, EXCL(range), TRUE)) {
        /* done */
    }
    else if (!NIL_P(str_b) && FIXNUM_P(step)) {
        // backwards compatibility behavior for String only, when no step/Integer step is passed
        // See discussion in https://bugs.ruby-lang.org/issues/18368

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

        if (NIL_P(e)) {
            rb_str_upto_endless_each(str_b, step_i, (VALUE)iter);
        }
        else {
            rb_str_upto_each(str_b, e, EXCL(range), step_i, (VALUE)iter);
        }
    }
    else if (!NIL_P(sym_b) && FIXNUM_P(step)) {
        // same as above: backward compatibility for symbols

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

        if (NIL_P(e)) {
            rb_str_upto_endless_each(sym_b, sym_step_i, (VALUE)iter);
        }
        else {
            rb_str_upto_each(sym_b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter);
        }
    }
    else if (NIL_P(e)) {
        // endless range
        for (;; v = rb_funcall(v, id_plus, 1, step))
            rb_yield(v);
    }
    else if (b_num_p && step_num_p && r_less(step, INT2FIX(0)) < 0) {
        // iterate backwards, for consistency with ArithmeticSequence
        if (EXCL(range)) {
            for (; r_less(e, v) < 0; v = rb_funcall(v, id_plus, 1, step))
                rb_yield(v);
        }
        else {
            for (; (c = r_less(e, v)) <= 0; v = rb_funcall(v, id_plus, 1, step)) {
                rb_yield(v);
                if (!c) break;
            }
        }

    }
    else if ((dir = r_less(b, e)) == 0) {
        if (!EXCL(range)) {
            rb_yield(v);
        }
    }
    else if (dir == r_less(b, rb_funcall(b, id_plus, 1, step))) {
        // Direction of the comparison. We use it as a comparison operator in cycle:
        // if begin < end, the cycle performs while value < end (iterating forward)
        // if begin > end, the cycle performs while value > end (iterating backward with
        // a negative step)
        // One preliminary addition to check the step moves iteration in the same direction as
        // from begin to end; otherwise, the iteration should be empty.
        if (EXCL(range)) {
            for (; r_less(v, e) == dir; v = rb_funcall(v, id_plus, 1, step))
                rb_yield(v);
        }
        else {
            for (; (c = r_less(v, e)) == dir || c == 0; v = rb_funcall(v, id_plus, 1, step)) {
                rb_yield(v);
                if (!c) break;
            }
        }
    }
    return range;
}

#to_aArray

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"]

Returns:



1011
1012
1013
1014
1015
1016
1017
1018
# File 'range.c', line 1011

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);
}

#to_sString

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.

Returns:



1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
# File 'range.c', line 1929

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;
}