This section documents Ruby’s simple looping statements:
while
, until
, and for
. Ruby also includes the ability to define
custom looping constructs known as iterators.
Iterators (see Iterators and Enumerable Objects) are probably more commonly
used than Ruby’s built-in looping statements; they are documented later
in this chapter.
Ruby’s basic looping statements are while
and until
. They execute a chunk of code
while a certain condition is true, or
until the condition becomes true. For
example:
x = 10 # Initialize a loop counter variable while x >= 0 do # Loop while x is greater than or equal to 0 puts x # Print out the value of x x = x - 1 # Subtract 1 from x end # The loop ends here # Count back up to 10 using an until loop x = 0 # Start at 0 (instead of -1) until x > 10 do # Loop until x is greater than 10 puts x x = x + 1 end # Loop ends here
The loop condition is the Boolean expression that appears
between the while
or until
and do
keywords. The
loop body is the Ruby code that appears between the do
and the end
keyword
. The while
loop evaluates its condition. If the
value is anything other than false
or nil
, it executes its body, and
then loops to evaluate its condition again. In this way, the body is
executed repeatedly, zero or more times, while the condition remains true (or, more
strictly, non-false
and
non-nil
).
The until
loop is the
reverse. The condition is tested and the body is executed if the
condition evaluates to false
or
nil
. This means that the body is
executed zero or more times while the condition is false
or nil
. Note that any until
loop can be converted to a while
simply by negating the condition. Most
programmers are familiar with while
loops, but many have not used until
loops before. For this reason, you may want to use while
loops except when until
truly improves the clarity of your
code.
The do
keyword in a while
or until
loop is like the then
keyword in an if
statement: it may be omitted altogether
as long as a newline (or semicolon) appears between the loop condition
and the loop body.[*]
If the body of a loop is a single Ruby expression, you can express
that loop in a particularly compact form by using while
or until
as a modifier after the expression.
For example:
x = 0 # Initialize loop variable puts x = x + 1 while x < 10 # Output and increment in a single expression
This modifier syntax uses the while
keyword itself to separate the loop
body from the loop condition, and avoids the need for the do
(or newline) and end
keywords. Contrast this code with the
more traditional while
loop written
on a single line:
x = 0 while x < 10 do puts x = x + 1 end
until
can be used as a
modifier just as while
can
be:
a = [1,2,3] # Initialize an array puts a.pop until a.empty? # Pop elements from array until empty
Note that when while
and
until
are used as modifiers, they
must appear on the same line as the loop body that they modify. If
there is a newline between the loop body and the while
or until
keyword, the Ruby interpreter will
treat the loop body as an unmodified expression and the while
or until
as the beginning of a regular
loop.
When while
and until
are used as modifiers for a single
Ruby expression, the loop condition is tested first, even though it is
written after the loop body. The loop body is executed zero or more
times, just as if it were formatted as a regular while
or until
loop.
There is a special-case exception to this rule. When the
expression being evaluated is a compound expression delimited by
begin
and end
keywords, then the body is executed
first before the condition is tested:
x = 10 # Initialize loop variable begin # Start a compound expression: executed at least once puts x # output x x = x - 1 # decrement x end until x == 0 # End compound expression and modify it with a loop
This results in a construct much like the do/while
loop of C, C++, and Java. Despite
its similarity to the do/while
loop
of other languages, this special-case behavior of loop modifiers with
the begin
statement is
counterintuitive and its use is discouraged. Future releases of Ruby may forbid the
use of while
and until
modifiers with begin/end
.
Note that if you group multiple statements with parentheses and apply an until modifier to that grouped expression, you do not get this special case behavior:
x = 0 # Initialize loop variable ( # Start a compound expression: may be executed 0 times puts x # output x x = x - 1 # decrement x ) until x == 0 # End compound expression and modify it with a loop
The for
loop, or for/in
loop,
iterates through the elements of an enumerable object (such as an
array). On each iteration, it assigns an element to a specified loop
variable and then executes the body of the loop. A for
loop looks like this:
forvar
incollection
dobody
end
var
is a variable or a
comma-separated list of variables.
collection
is any object that has an each
iterator method. Arrays and hashes
define the each
method, and many
other Ruby objects do, too. The for/in
loop calls the each
method of the specified object. As that
iterator yields values, the for
loop assigns each value (or each set of values) to the specified
variable (or variables) and then executes the code in
body
. As with the while
and until
loops, the do
keyword is optional and may be replaced
with a newline or semicolon.
Here are some sample for
loops:
# Print the elements in an array array = [1,2,3,4,5] for element in array puts element end # Print the keys and values in a hash hash = {:a=>1, :b=>2, :c=>3} for key,value in hash puts "#{key} => #{value}" end
The loop variable or variables of a for
loop are not local to the loop; they
remain defined even after the loop exits. Similarly, new variables
defined within the body of the loop continue to exist after the loop
exits.
The fact that the for
loop
depends on the each
iterator method
implies that for
loops are much
like iterators. For example, the for
loop shown above for enumerating the
keys and values of a hash could also be written with an explicit use
of the each
iterator:
hash = {:a=>1, :b=>2, :c=>3} hash.each do |key,value| puts "#{key} => #{value}" end
The only difference between the for
version of the loop and the each
version is that the block of code that
follows an iterator does define a new variable scope. Details are in
the discussion of iterators later in this chapter.
[*] In Ruby 1.8, a colon may be used in place of the do
keyword. This is no longer allowed in
Ruby 1.9.
18.220.160.43