U:RDoc::TopLevel[ i I"$syntax/control_expressions.rdoc:EFcRDoc::Parser::Simpleo:RDoc::Markup::Document:@parts[æS:RDoc::Markup::Heading:
leveli: textI"Control Expressions;To:RDoc::Markup::BlankLine o:RDoc::Markup::Paragraph;[I"URuby has a variety of ways to control execution. All the expressions described ;TI"here return a value.;T@
o;
;[I"TFor the tests in these control expressions, +nil+ and +false+ are false-values ;TI"Tand +true+ and any other object are true-values. In this document "true" will ;TI";mean "true-value" and "false" will mean "false-value".;T@
S; ;
i;I"+if+ Expression;T@
o;
;[I"RThe simplest +if+ expression has two parts, a "test" expression and a "then" ;TI"Oexpression. If the "test" expression evaluates to a true then the "then" ;TI"expression is evaluated.;T@
o;
;[I"#Here is a simple if statement:;T@
o:RDoc::Markup::Verbatim;[I"if true then
;TI"0 puts "the test resulted in a true-value"
;TI" end
;T:@format0o;
;[I"9This will print "the test resulted in a true-value".;T@
o;
;[I"The +then+ is optional:;T@
o;;[I"
if true
;TI"0 puts "the test resulted in a true-value"
;TI" end
;T;0o;
;[I"TThis document will omit the optional +then+ for all expressions as that is the ;TI"most common usage of +if+.;T@
o;
;[I"SYou may also add an +else+ expression. If the test does not evaluate to true ;TI",the +else+ expression will be executed:;T@
o;;[
I"if false
;TI"0 puts "the test resulted in a true-value"
;TI"
else
;TI"1 puts "the test resulted in a false-value"
;TI" end
;T;0o;
;[I":This will print "the test resulted in a false-value".;T@
o;
;[I"NYou may add an arbitrary number of extra tests to an if expression using ;TI"N+elsif+. An +elsif+ executes when all tests above the +elsif+ are false.;T@
o;;[I"a = 1
;TI"
;TI"if a == 0
;TI" puts "a is zero"
;TI"elsif a == 1
;TI" puts "a is one"
;TI"
else
;TI"$ puts "a is some other value"
;TI" end
;T;0o;
;[I"RThis will print "a is one" as 1
is not equal to 0
. ;TI"ISince +else+ is only executed when there are no matching conditions.;T@
o;
;[I"SOnce a condition matches, either the +if+ condition or any +elsif+ condition, ;TI"Lthe +if+ expression is complete and no further tests will be performed.;T@
o;
;[I"DLike an +if+, an +elsif+ condition may be followed by a +then+.;T@
o;
;[I"0In this example only "a is one" is printed:;T@
o;;[I"a = 1
;TI"
;TI"if a == 0
;TI" puts "a is zero"
;TI"elsif a == 1
;TI" puts "a is one"
;TI"elsif a >= 1
;TI"0 puts "a is greater than or equal to one"
;TI"
else
;TI"$ puts "a is some other value"
;TI" end
;T;0o;
;[I"SThe tests for +if+ and +elsif+ may have side-effects. The most common use of ;TI";side-effect is to cache a value into a local variable:;T@
o;;[I"if a = object.some_value
;TI" # do something to a
;TI" end
;T;0o;
;[I"NThe result value of an +if+ expression is the last value executed in the ;TI"expression.;T@
S; ;
i;I"Ternary if;T@
o;
;[I"KYou may also write a if-then-else expression using ?
and ;TI"&:
. This ternary if:;T@
o;;[I":input_type = gets =~ /hello/i ? "greeting" : "other"
;T;0o;
;[I")Is the same as this +if+ expression:;T@
o;;[I"input_type =
;TI" if gets =~ /hello/i
;TI" "greeting"
;TI" else
;TI" "other"
;TI" end
;T;0o;
;[ I"SWhile the ternary if is much shorter to write than the more verbose form, for ;TI"Oreadability it is recommended that the ternary if is only used for simple ;TI"Nconditionals. Also, avoid using multiple ternary conditions in the same ;TI")expression as this can be confusing.;T@
S; ;
i;I"+unless+ Expression;T@
o;
;[I"SThe +unless+ expression is the opposite of the +if+ expression. If the value ;TI"1is false, the "then" expression is executed:;T@
o;;[I"unless true
;TI") puts "the value is a false-value"
;TI" end
;T;0o;
;[I"6This prints nothing as true is not a false-value.;T@
o;
;[I"AYou may use an optional +then+ with +unless+ just like +if+.;T@
o;
;[I"a = ;TI"0.zero?.;T@
o;
;[I"QSince the test is true it executes the "then" expression, p a
. ;TI"QSince the +a+ in the body was recorded as a method which does not exist the ;TI"NameError is raised.;T@
o;
;[I"#The same is true for +unless+.;T@
S; ;
i;I"+case+ Expression;T@
o;
;[I"3The +case+ expression can be used in two ways.;T@
o;
;[ I"QThe most common way is to compare an object against multiple patterns. The ;TI"Mpatterns are matched using the +===+ method which is aliased to +==+ on ;TI"OObject. Other classes must override it to give meaningful behavior. See ;TI",Module#=== and Regexp#=== for examples.;T@
o;
;[I"NHere is an example of using +case+ to compare a String against a pattern:;T@
o;;[I"case "12345"
;TI"when /^1/
;TI") puts "the string starts with one"
;TI"
else
;TI"7 puts "I don't know what the string starts with"
;TI" end
;T;0o;
;[ I"PHere the string "12345"
is compared with /^1/
by ;TI"Pcalling /^1/ === "12345"
which returns +true+. Like the +if+ ;TI"Uexpression, the first +when+ that matches is executed and all other matches are ;TI"
ignored.;T@
o;
;[I"5If no matches are found, the +else+ is executed.;T@
o;
;[I"OThe +else+ and +then+ are optional, this +case+ expression gives the same ;TI"result as the one above:;T@
o;;[ I"case "12345"
;TI"when /^1/
;TI") puts "the string starts with one"
;TI" end
;T;0o;
;[I":You may place multiple conditions on the same +when+:;T@
o;;[ I"case "2"
;TI"when /^1/, "2"
;TI"3 puts "the string starts with one or is '2'"
;TI" end
;T;0o;
;[I"NRuby will try each condition in turn, so first /^1/ === "2"
;TI"Sreturns +false+, then "2" === "2"
returns +true+, so "the string ;TI"+starts with one or is '2'" is printed.;T@
o;
;[I"RYou may use +then+ after the +when+ condition. This is most frequently used ;TI"6to place the body of the +when+ on a single line.;T@
o;;[
I"case a
;TI"*when 1, 2 then puts "a is one or two
;TI"&when 3 then puts "a is three"
;TI"2else puts "I don't know what a is"
;TI" end
;T;0o;
;[I"MThe other way to use a +case+ expression is like an if-elsif expression:;T@
o;;[I"a = 2
;TI"
;TI"
case
;TI"when a == 1, a == 2
;TI" puts "a is one or two"
;TI"when a == 3
;TI" puts "a is three"
;TI"
else
;TI"% puts "I don't know what a is"
;TI" end
;T;0o;
;[I"/Again, the +then+ and +else+ are optional.;T@
o;
;[I"OThe result value of a +case+ expression is the last value executed in the ;TI"expression.;T@
S; ;
i;I"+while+ Loop;T@
o;
;[I"9The +while+ loop executes while a condition is true:;T@
o;;[
I"a = 0
;TI"
;TI"while a < 10 do
;TI" p a
;TI" a += 1
;TI" end
;TI"
;TI" p a
;T;0o;
;[I"TPrints the numbers 0 through 10. The condition a < 10
is checked ;TI"Obefore the loop is entered, then the body executes, then the condition is ;TI"Pchecked again. When the condition results in false the loop is terminated.;T@
o;
;[I"QThe +do+ keyword is optional. The following loop is equivalent to the loop ;TI"above:;T@
o;;[ I"while a < 10
;TI" p a
;TI" a += 1
;TI" end
;T;0o;
;[I"NThe result of a +while+ loop is +nil+ unless +break+ is used to supply a ;TI"value.;T@
S; ;
i;I"+until+ Loop;T@
o;
;[I":The +until+ loop executes while a condition is false:;T@
o;;[
I"a = 0
;TI"
;TI"until a > 10 do
;TI" p a
;TI" a += 1
;TI" end
;TI"
;TI" p a
;T;0o;
;[I"TThis prints the numbers 0 through 11. Like a while loop the condition a ;TI"O> 10
is checked when entering the loop and each time the loop body ;TI"Lexecutes. If the condition is false the loop will continue to execute.;T@
o;
;[I"/Like a +while+ loop, the +do+ is optional.;T@
o;
;[I"QLike a +while+ loop, the result of an +until+ loop is nil unless +break+ is ;TI"
used.;T@
S; ;
i;I"+for+ Loop;T@
o;
;[I"LThe +for+ loop consists of +for+ followed by a variable to contain the ;TI"Titeration argument followed by +in+ and the value to iterate over using #each. ;TI"The +do+ is optional:;T@
o;;[I"for value in [1, 2, 3] do
;TI" puts value
;TI" end
;T;0o;
;[I"Prints 1, 2 and 3.;T@
o;
;[I"4Like +while+ and +until+, the +do+ is optional.;T@
o;
;[I"RThe +for+ loop is similar to using #each, but does not create a new variable ;TI"scope.;T@
o;
;[I"SThe result value of a +for+ loop is the value iterated over unless +break+ is ;TI"
used.;T@
o;
;[I";The +for+ loop is rarely used in modern ruby programs.;T@
S; ;
i;I"!Modifier +while+ and +until+;T@
o;
;[I"JLike +if+ and +unless+, +while+ and +until+ can be used as modifiers:;T@
o;;[
I"a = 0
;TI"
;TI"a += 1 while a < 10
;TI"
;TI"p a # prints 10
;T;0o;
;[I" +until+ used as a modifier:;T@
o;;[
I"a = 0
;TI"
;TI"a += 1 until a > 10
;TI"
;TI"p a # prints 11
;T;0o;
;[I"TYou can use +begin+ and +end+ to create a +while+ loop that runs the body once ;TI"before the condition:;T@
o;;[I"a = 0
;TI"
;TI"begin
;TI" a += 1
;TI"end while a < 10
;TI"
;TI"p a # prints 10
;T;0o;
;[I"NIf you don't use +rescue+ or +ensure+, Ruby optimizes away any exception ;TI"handling overhead.;T@
S; ;
i;I"+break+ Statement;T@
o;
;[I"uUse +break+ to leave a block early. This will stop iterating over the items in +values+ if one of them is even:;T@
o;;[
I"values.each do |value|
;TI" break if value.even?
;TI"
;TI"
# ...
;TI" end
;T;0o;
;[I">You can also terminate from a +while+ loop using +break+:;T@
o;;[I"a = 0
;TI"
;TI"while true do
;TI" p a
;TI" a += 1
;TI"
;TI" break if a < 10
;TI" end
;TI"
;TI" p a
;T;0o;
;[I"%This prints the numbers 0 and 1.;T@
o;
;[I"N+break+ accepts a value that supplies the result of the expression it is ;TI""breaking" out of:;T@
o;;[
I"(result = [1, 2, 3].each do |value|
;TI"& break value * 2 if value.even?
;TI" end
;TI"
;TI"p result # prints 4
;T;0S; ;
i;I"+next+ Statement;T@
o;
;[I":Use +next+ to skip the rest of the current iteration:;T@
o;;[I"'result = [1, 2, 3].map do |value|
;TI" next if value.even?
;TI"
;TI" value * 2
;TI" end
;TI"
;TI"#p result # prints [2, nil, 6]
;T;0o;
;[I"N+next+ accepts an argument that can be used as the result of the current ;TI"block iteration:;T@
o;;[I"'result = [1, 2, 3].map do |value|
;TI"! next value if value.even?
;TI"
;TI" value * 2
;TI" end
;TI"
;TI"!p result # prints [2, 2, 6]
;T;0S; ;
i;I"+redo+ Statement;T@
o;
;[I".Use +redo+ to redo the current iteration:;T@
o;;[I"result = []
;TI"
;TI"!while result.length < 10 do
;TI" result << result.length
;TI"
;TI"! redo if result.last.even?
;TI"
;TI"# result << result.length + 1
;TI" end
;TI"
;TI"p result
;T;0o;
;[I"3This prints [0, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11];T@
o;
;[ I"PIn Ruby 1.8, you could also use +retry+ where you used +redo+. This is no ;TI"Rlonger true, now you will receive a SyntaxError when you use +retry+ outside ;TI"Mof a +rescue+ block. See {Exceptions}[rdoc-ref:syntax/exceptions.rdoc] ;TI"!for proper usage of +retry+.;T@
S; ;
i;I"Flip-Flop;T@
o;
;[I"QThe flip-flop is a rarely seen conditional expression. It's primary use is ;TI"Tfor processing text from ruby one-line programs used with ruby -n
;TI"or ruby -p
.;T@
o;
;[ I"HThe form of the flip-flop is an expression that indicates when the ;TI"Sflip-flop turns on, ..
(or ...
), then an expression ;TI"Tthat indicates when the flip-flop will turn off. While the flip-flop is on it ;TI"?will continue to evaluate to +true+, and +false+ when off.;T@
o;
;[I"Here is an example:;T@
o;;[I"selected = []
;TI"
;TI"0.upto 10 do |value|
;TI"/ selected << value if value==2..value==8
;TI" end
;TI"
;TI"/p selected # prints [2, 3, 4, 5, 6, 7, 8]
;T;0o;
;[I"QIn the above example, the on condition is n==2
. The flip-flop ;TI"Sis initially off (false) for 0 and 1, but becomes on (true) for 2 and remains ;TI"Fon through 8. After 8 it turns off and remains off for 9 and 10.;T@
o;
;[I"LThe flip-flop must be used inside a conditional such as +if+, +while+, ;TI"9+unless+, +until+ etc. including the modifier forms.;T@
o;
;[I"MWhen you use an inclusive range (..
), the off condition is ;TI"-evaluated when the on condition changes:;T@
o;;[I"selected = []
;TI"
;TI"0.upto 5 do |value|
;TI"/ selected << value if value==2..value==2
;TI" end
;TI"
;TI"p selected # prints [2]
;T;0o;
;[I"SHere, both sides of the flip-flop are evaluated so the flip-flop turns on and ;TI"Koff only when +value+ equals 2. Since the flip-flop turned on in the ;TI"iteration it returns true.;T@
o;
;[I"NWhen you use an exclusive range (...
), the off condition is ;TI"*evaluated on the following iteration:;T@
o;;[I"selected = []
;TI"
;TI"0.upto 5 do |value|
;TI"0 selected << value if value==2...value==2
;TI" end
;TI"
;TI"&p selected # prints [2, 3, 4, 5]
;T;0o;
;[I"UHere, the flip-flop turns on when +value+ equals 2, but doesn't turn off on the ;TI"Lsame iteration. The off condition isn't evaluated until the following ;TI"3iteration and +value+ will never be two again.;T:
@file@:0@omit_headings_from_table_of_contents_below0