separate features: sequences, conditions, and intervals.
The first and perhaps most natural use of ranges is to express a
sequence.
Sequences have a start point, an end point, and a way to
produce successive values in the sequence. In Ruby, these sequences
are created using the ``..'' and ``...'' range operators. The
two-dot form creates an inclusive range, while the three-dot form
creates a range that excludes the specified high value.
1..10
'a'..'z'
0...anArray.length
|
In Ruby, unlike in some earlier versions of Perl, ranges are not
represented internally as lists: the sequence 1..100000 is held as a
Range
object containing references to two
Fixnum
objects. If
you need to, you can convert a range to a list using the
to_a
method.
(1..10).to_a
|
� |
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
('bar'..'bat').to_a
|
� |
["bar", "bas", "bat"]
|
Ranges implement methods that let you iterate over them and test their
contents in a variety of ways.
digits = 0..9
|
digits.include?(5)
|
� |
true
|
digits.min
|
� |
0
|
digits.max
|
� |
9
|
digits.reject {|i| i < 5 }
|
� |
[5, 6, 7, 8, 9]
|
digits.each do |digit|
|
dial(digit)
|
end
|
So far we've shown ranges of numbers and strings. However, as you'd
expect from an object-oriented language, Ruby can create ranges based
on objects that you define. The only constraints are that the objects
must respond to
succ
by returning the next object in sequence
and the objects must be comparable using
<=>
,
the general comparison operator.
Sometimes called the
spaceship operator,
<=>
compares two values, returning -1, 0, or +1
depending on whether the first is less than, equal to, or greater than
the second.
Here's a simple class that represents rows of ``#'' signs. We might
use it as a text-based stub when testing the jukebox volume control.
class VU
include Comparable
attr :volume
def initialize(volume) # 0..9
@volume = volume
end
def inspect
'#' * @volume
end
# Support for ranges
def <=>(other)
self.volume <=> other.volume
end
def succ
raise(IndexError, "Volume too big") if @volume >= 9
VU.new(@volume.succ)
end
end
|
We can test it by creating a range of
VU
objects.
medium = VU.new(4)..VU.new(7)
|
medium.to_a
|
� |
[####, #####, ######, #######]
|
medium.include?(VU.new(3))
|
� |
false
|