U:RDoc::TopLevel[ iI"$syntax/control_expressions.rdoc:EFcRDoc::Parser::Simpleo:RDoc::Markup::Document: @parts[æS:RDoc::Markup::Heading: leveli: textI"Control Expressions;To:RDoc::Markup::BlankLineo: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