Class: Range
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:
-
# 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:
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 eachn
-th element ofself
. -
#each: Calls the block with each element of
self
. -
#step: Takes optional argument
n
(defaults to 1); calls the block with eachn
-th element ofself
.
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
-
#%(step) ⇒ Object
Iterates over the elements of
self
. -
#==(other) ⇒ Boolean
Returns
true
if and only if:. -
#===(object) ⇒ Boolean
Returns
true
ifobject
is betweenself.begin
andself.end
. -
#begin ⇒ Object
Returns the object that defines the beginning of
self
. -
#bsearch {|obj| ... } ⇒ Object
Returns an element from
self
selected by a binary search. -
#count(*args) ⇒ Object
Returns the count of elements, based on an argument or block criterion, if given.
-
#cover?(val) ⇒ Object
Returns
true
if the given argument is withinself
,false
otherwise. -
#each ⇒ Object
With a block given, passes each element of
self
to the block:. -
#end ⇒ Object
Returns the object that defines the end of
self
. -
#to_a ⇒ Array
Returns an array containing the elements in
self
, if a finite collection; raises an exception otherwise. -
#eql?(other) ⇒ Boolean
Returns
true
if and only if:. -
#exclude_end? ⇒ Boolean
Returns
true
ifself
excludes its end value;false
otherwise:. -
#first(*args) ⇒ Object
With no argument, returns the first element of
self
, if it exists:. -
#hash ⇒ Integer
Returns the integer hash value for
self
. -
#include?(object) ⇒ Boolean
Returns
true
ifobject
is an element ofself
,false
otherwise:. -
#new ⇒ Object
constructor
Returns a new range based on the given objects
begin
andend
. -
#initialize_copy(orig) ⇒ Object
:nodoc:.
-
#inspect ⇒ String
Returns a string representation of
self
, includingbegin.inspect
andend.inspect
:. -
#last(*args) ⇒ Object
With no argument, returns the last element of
self
, if it exists:. -
#max(*args) ⇒ Object
Returns the maximum value in
self
, using method<=>
or a given block for comparison. -
#include?(object) ⇒ Boolean
Returns
true
ifobject
is an element ofself
,false
otherwise:. -
#min(*args) ⇒ Object
Returns the minimum value in
self
, using method<=>
or a given block for comparison. -
#minmax ⇒ Object
Returns a 2-element array containing the minimum and maximum value in
self
, either according to comparison method<=>
or a given block. -
#overlap?(range) ⇒ Boolean
Returns
true
ifrange
overlaps withself
,false
otherwise:. -
#reverse_each ⇒ Object
With a block given, passes each element of
self
to the block in reverse order:. -
#size ⇒ Infinity?
Returns the count of elements in
self
if both begin and end values are numeric; otherwise, returnsnil
:. -
#step(*args) ⇒ Object
Iterates over the elements of
self
. -
#to_a ⇒ Array
Returns an array containing the elements in
self
, if a finite collection; raises an exception otherwise. -
#to_s ⇒ String
Returns a string representation of
self
, includingbegin.to_s
andend.to_s
:.
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
#new ⇒ Object
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"]
100 101 102 103 104 105 106 107 108 109 |
# File 'range.c', line 100
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
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.
572 573 574 575 576 |
# File 'range.c', line 572
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?.
182 183 184 185 186 187 188 189 190 191 |
# File 'range.c', line 182
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"
1888 1889 1890 1891 1892 |
# File 'range.c', line 1888
static VALUE
range_eqq(VALUE range, VALUE val)
{
return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val);
}
|
#begin ⇒ Object
Returns the object that defines the beginning of self
.
(1..4).begin # => 1
(..2).begin # => nil
Related: Range#first, Range#end.
1177 1178 1179 1180 1181 |
# File 'range.c', line 1177
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.
693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 |
# File 'range.c', line 693
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;
}
|
#count ⇒ Integer #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.
2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 2275 2276 |
# File 'range.c', line 2247
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
<=>
returnsnil
; 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?.
2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 |
# File 'range.c', line 2106
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 #each ⇒ Object
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.
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 |
# File 'range.c', line 933
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
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.
1198 1199 1200 1201 1202 |
# File 'range.c', line 1198
static VALUE
range_end(VALUE range)
{
return RANGE_END(range);
}
|
#to_a ⇒ Array
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"]
869 870 871 872 873 874 875 876 |
# File 'range.c', line 869
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#==.
250 251 252 253 254 255 256 257 258 |
# File 'range.c', line 250
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
132 133 134 135 136 |
# File 'range.c', line 132
static VALUE
range_exclude_end_p(VALUE range)
{
return RBOOL(EXCL(range));
}
|
#first ⇒ Object #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
1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 |
# File 'range.c', line 1242
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
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.
271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 |
# File 'range.c', line 271
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?.
1924 1925 1926 1927 1928 1929 1930 |
# File 'range.c', line 1924
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:
112 113 114 115 116 117 118 |
# File 'range.c', line 112
static VALUE
range_initialize_copy(VALUE range, VALUE orig)
{
range_modify(range);
rb_struct_init_copy(range, orig);
return range;
}
|
#inspect ⇒ String
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.
1840 1841 1842 1843 1844 |
# File 'range.c', line 1840
static VALUE
range_inspect(VALUE range)
{
return rb_exec_recursive(inspect_range, range, 0);
}
|
#last ⇒ Object #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
1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 |
# File 'range.c', line 1348
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 #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.
1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 |
# File 'range.c', line 1557
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?.
1924 1925 1926 1927 1928 1929 1930 |
# File 'range.c', line 1924
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);
}
|
#min ⇒ Object #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.
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 |
# File 'range.c', line 1449
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 ⇒ Array #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 thanb
. -
Zero if
a
andb
are equal. -
Positive if
a
is larger thanb
.
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.
1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 |
# File 'range.c', line 1643
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?.
2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 |
# File 'range.c', line 2358
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(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_each ⇒ Object
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.
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 |
# File 'range.c', line 1127
static VALUE
range_reverse_each(VALUE range)
{
RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_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;
}
|
#size ⇒ Infinity?
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.
835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 |
# File 'range.c', line 835
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 #step(n = 1) ⇒ Object
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#%.
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 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 |
# File 'range.c', line 438
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
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"]
869 870 871 872 873 874 875 876 |
# File 'range.c', line 869
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_s ⇒ String
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.
1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 |
# File 'range.c', line 1781
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;
}
|