The most common control structure, in any programming language, is
the conditional. This is a way
of telling the computer to conditionally execute some code: to execute
it only if some condition is satisfied. The condition is an
expression—if it evaluates to any value other than false
or nil
, then the condition is satisfied.
Ruby has a rich vocabulary for expressing conditionals. The syntax choices are described in the subsections that follow. When writing Ruby code, you can choose the one that seems most elegant for the task at hand.
The most straightforward of the conditionals is if
. In its simplest form, it looks like
this:
ifexpression
code
end
The code
between if
and end
is executed if (and only if) the
expression
evaluates to something other
than false
or nil
. The code
must be separated from the expression
with
a newline or semicolon or the keyword then
.[5] Here are two ways to write the same simple
conditional:
# If x is less than 10, increment it if x < 10 # newline separator x += 1 end if x < 10 then x += 1 end # then separator
You can also use then
as the
separator token, and follow it with a newline. Doing so makes your
code robust; it will work even if the newline is subsequently
removed:
if x < 10 then x += 1 end
Programmers who are used to C, or languages whose syntax is
derived from C, should note two important things about Ruby’s if
statement:
Parentheses are not required (and typically not used) around the
conditional expression. The
newline, semicolon, or then
keyword serves to delimit the expression instead.
The end
keyword is
required, even when the code to be conditionally executed consists
of a single statement. The modifier form of if
, described
below, provides a way to write simple conditionals without the
end
keyword.
An if
statement may include an else
clause to specify code to be executed
if the condition is not
true:
ifexpression
code
elsecode
end
The code
between the if
and else
is executed if
expression
evaluates to anything other
than false
or nil
. Otherwise (if
expression
is false
or nil
), the code
between the else
and end
is executed. As in the simple form of
if
, the
expression
must be separated from the
code
that follows it by a newline, a
semicolon, or the keyword then
.
The else
and end
keywords fully delimit the second
chunk of code
, and no newlines or additional delimiters are
required.
Here is an example of a conditional that includes an else
clause:
if data # If the array exists data << x # then append a value to it. else # Otherwise... data = [x] # create a new array that holds the value. end # This is the end of the conditional.
If you want to test more than one condition within a conditional,
you can add one or more elsif
clauses between an if
and an
else
. elsif
is a shortened form of “else if.”
Note that there is only one e in elsif
. A conditional using elsif
looks like this:
ifexpression1
code1
elsifexpression2
code2
. . . elsifexpressionN
codeN
elsecode
end
If expression1
evaluates to
anything other than false
or
nil
, then
code1
is executed. Otherwise,
expression2
is evaluated. If it is
anything other than false
or
nil
, then
code2
is executed. This process continues
until an expression evaluates to something other than false
or nil
, or until all elsif
clauses have been tested. If the
expression associated with the last elsif
clause is false
or nil
, and the elsif
clause is followed by an else
clause, then the code between
else
and end
is executed. If no else
clause is present, then no code is
executed at all.
elsif
is like if
: the expression must be separated from
the code by a newline, a semicolon, or a then
keyword. Here is an example of a
multiway conditional using elsif
:
if x == 1 name = "one" elsif x == 2 name = "two" elsif x == 3 then name = "three" elsif x == 4; name = "four" else name = "many" end
In most languages, the if
conditional
is a statement. In Ruby, however, everything is an expression, even
the control structures that are commonly called statements. The
return value of an if
“statement”
(i.e., the value that results from evaluating an if
expression) is the value of the last
expression in the code that was executed, or nil
if no block of code was
executed.
The fact that if
statements
return a value means that, for example, the multiway conditional shown previously can be
elegantly rewritten as follows:
name = if x == 1 then "one" elsif x == 2 then "two" elsif x == 3 then "three" elsif x == 4 then "four" else "many" end
When if
is used in its
normal statement form, Ruby’s grammar requires that it be terminated
with the end
keyword. For simple,
single-line conditionals, this is somewhat awkward. This is just a
parsing problem, and the solution is to use the if
keyword itself as the delimiter that
separates the code to be executed from the conditional expression. Instead of writing:
ifexpression
thencode
end
we can simply write:
code
ifexpression
When used in this form, if
is
known as a statement (or expression) modifier. If
you’re a Perl programmer, you may be accustomed to this syntax. If
not, please note that the code to execute comes first, and the
expression follows. For example:
puts message if message # Output message, if it is defined
This syntax places more emphasis on the code to be executed, and less emphasis on the condition under which it will be executed. Using this syntax can make your code more readable when the condition is a trivial one or when the condition is almost always true.
Even though the condition is written last, it is evaluated
first. If it evaluates to anything other than false
or nil
, then the code is evaluated, and its
value is used as the return value of the modified expression.
Otherwise, the code is not executed, and the return value of the
modified expression is nil
.
Obviously, this syntax does not allow any kind of else
clause.
To use if
as a modifier, it
must follow the modified statement or expression immediately, with no
intervening line break. Inserting a newline into the previous example
turns it into an unmodified method invocation followed by an
incomplete if
statement:
puts message # Unconditional if message # Incomplete!
The if
modifier has very low
precedence and binds more loosely than the assignment operator. Be
sure you know just what expression you are modifying when you use it.
For example, the following two lines of code are different:
y = x.invert if x.respond_to? :invert y = (x.invert if x.respond_to? :invert)
In the first line, the modifier applies to the assignment
expression. If x
does not have a
method named invert
, then nothing
happens at all, and the value of y
is not modified. In the second line, the if
modifier applies only to the method call.
If x
does not have an invert
method, then the modified expression
evaluates to nil
, and this is the
value that is assigned to y
.
An if
modifier binds to the
single nearest expression. If you want to modify more than one
expression, you can use parentheses or a begin
statement for grouping. But this
approach is problematic because readers don’t know that the code is
part of a conditional until they reach the bottom. Also, using an
if
modifier in this way gives up
the conciseness that is the primary benefit of this syntax. When more
than one line of code is involved, you should typically use a
traditional if
statement rather
than an if
modifier. Compare the
following three side-by-side alternatives:
if expression begin ( line1 line1 line1 line2 line2 line2 end end if expression ) end if expression
Note that an expression modified with an if
clause is itself an expression that can
be modified. It is therefore possible to attach multiple if
modifiers to an expression:
# Output message if message exists and the output method is defined puts message if message if defined? puts
Repeating an if
modifier like
this is hard to read, however, and it makes more sense to combine the
two conditions into a single expression:
puts message if message and defined? puts
unless
, as a statement or a modifier, is the opposite of if
: it executes code only if an associated
expression evaluates to false
or
nil
. Its syntax is just like
if
, except that elsif
clauses are not allowed:
# single-way unless statement unlesscondition
code
end # two-way unless statement unlesscondition
code
elsecode
end # unless modifiercode
unlesscondition
The unless
statement, like
the if
statement, requires that the
condition and the code are separated by a newline, a semicolon, or the
then
keyword. Also like if
, unless
statements are expressions and return
the value of the code they execute, or nil
if they execute nothing:
# Call the to_s method on object o, unless o is nil s = unless o.nil? # newline separator o.to_s end s = unless o.nil? then o.to_s end # then separator
For single-line conditionals like this, the modifier form of
unless
is usually clearer:
s = o.to_s unless o.nil?
Ruby has no equivalent of the elsif
clause for an unless
conditional. You can still write a
multiway unless
statement, however,
if you’re willing to be a little more verbose:
unless x == 0 puts "x is not 0" else unless y == 0 puts "y is not 0" else unless z == 0 puts "z is not 0" else puts "all are 0" end end end
The case
statement is a multiway conditional. There are two forms of this
statement. The simple (and infrequently used) form is nothing more
than an alternative syntax for if/elsif/else
. These two side-by-side
expressions are equivalent:
name = case name = if x == 1 then "one" when x == 1 then "one" elsif x == 2 then "two" when x == 2 then "two" elsif x == 3 then "three" when x == 3 then "three" elsif x == 4 then "four" when x == 4 then "four" else "many" else "many" end end
As you can see from this code, the case
statement returns a value, just as the
if
statement does. As with the
if
statement, the then
keyword following the when
clauses can be replaced with a newline
or semicolon:[*]
case when x == 1 "one" when x == 2 "two" when x == 3 "three" end
The case
statement tests each
of its when
expressions in the
order they are written until it finds one that evaluates to true
. If it finds one, it evaluates the
statements that come between that when
and the following when
, else
, or end
. The last expression evaluated becomes
the return value of the case
statement. Once a when
clause that
evaluates to true
has been found,
no other when
clauses are
considered.
The else
clause of a case
statement
is optional, but if it appears, it must come at the end of the
statement, after all when
clauses.
If no when
clause is true
, and there is an else
clause, then the code between else
and end
is executed. The value of the last
expression evaluated in this code becomes the value of the case
statement. If no when
clause is true
and there is no else
clause, then no code is executed and
the value of the case
statement is
nil
.
A when
clause within a
case
statement may have more than one (comma-separated) expression
associated with it. If any one of these expressions evaluates to
true
, then the code associated with
that when
is executed. In this
simple form of the case
statement,
the commas aren’t particularly useful and act just like the ||
operator:
case when x == 1, y == 0 then "x is one or y is zero" # Obscure syntax when x == 2 || y == 1 then "x is two or y is one" # Easier to understand end
All the case
examples we’ve
seen so far demonstrate the simpler, less common form of the
statement. case
is really more
powerful than this. Notice that in most of the examples, the left side
of each when
clause expression is
the same. In the common form of case
, we factor this repeated lefthand
expression of the when
clause and
associate it with the case
itself:
name = case x when 1 # Just the value to compare to x "one" when 2 then "two" # Then keyword instead of newline when 3; "three" # Semicolon instead of newline else "many" # Optional else clause at end end
In this form of the case
statement, the expression associated with the case
is evaluated once, and then it’s
compared to the values obtained by evaluating the when
expression. The comparisons are
performed in the order in which the when
clauses are written, and the code
associated with the first matching when
is executed. If no match is found, the
code associated with the else
clause (if there is one) is executed. The return value of this form of
the case
statement is the same as
the return value of the simpler form: the value of the last expression
evaluated, or nil
if no when
or else
matches.
The important thing to understand about the case
statement is how the values of the
when
clauses are compared to the
expression that follows the case
keyword. This comparison is done using the ===
operator.
This operator is invoked on the value of the when
expression and is passed the value of
the case
expression. Therefore, the
case
statement above is equivalent
to the following (except that x
is
only evaluated once in the code above):
name = case when 1 === x then "one" when 2 === x then "two" when 3 === x then "three" else "many" end
===
is the case
equality operator. For many classes, such as the Fixnum
class used earlier, the ===
operator behaves just the same as
==
. But certain classes define this
operator in interesting ways. The Class
class defines ===
so that it tests whether the righthand
operand is an instance of the class named by the lefthand operand.
Range
defines this operator to test
whether the value on the right falls within the range on the left.
Regexp
defines it so that it tests
whether the text on the right matches the pattern on the left. In Ruby
1.9,Symbol
defines
===
so that it tests for symbol or
string equality. With these definitions of case equality, we are able
to write interesting case
statements like the following:
# Take different actions depending on the class of x puts case x when String then "string" when Numeric then "number" when TrueClass, FalseClass then "boolean" else "other" end # Compute 2006 U.S. income tax using case and Range objects tax = case income when 0..7550 income * 0.1 when 7550..30650 755 + (income-7550)*0.15 when 30650..74200 4220 + (income-30655)*0.25 when 74200..154800 15107.5 + (income-74201)*0.28 when 154800..336550 37675.5 + (income-154800)*0.33 else 97653 + (income-336550)*0.35 end # Get user's input and process it, ignoring comments and exiting # when the user enters the word "quit" while line=gets.chomp do # Loop, asking the user for input each time case line when /^s*#/ # If input looks like a comment... next # skip to the next line. when /^quit$/i # If input is "quit" (case insensitive)... break # exit the loop. else # Otherwise... puts line.reverse # reverse the user's input and print it. end end
A when
clause can have more
than one expression associated with it. Multiple expressions are
separated by commas, and the ===
operator is invoked on each one. That is, it is possible to trigger
the same block of code with more than one value:
def hasValue?(x) # Define a method named hasValue? case x # Multiway conditional based on value of x when nil, [], "", 0 # if nil===x || []===x || ""===x || 0===x then false # method return value is false else # Otherwise true # method return value is true end end
The conditional operator ?:
, described earlier in Conditional: ?:, behaves much like an if
statement, with ?
replacing then
and :
replacing else
. It provides a succinct way to express
conditionals:
def how_many_messages(n) # Handle singular/plural "You have " + n.to_s + (n==1 ? " message." : " messages.") end
3.17.154.139