File: C:/Ruby27-x64/share/ri/2.7.0/system/syntax/page-control_expressions_rdoc.ri
U:RDoc::TopLevel[ i I"$syntax/control_expressions.rdoc:ETcRDoc::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 <code>1</code> is not equal to <code>0</code>. ;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 <code>?</code> and ;TI"&<code>:</code>. 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"<Note that the above +unless+ expression is the same as:;T@
o;;[I"if not true
;TI") puts "the value is a false-value"
;TI" end
;T;0o;
;[I"KLike an +if+ expression you may use an +else+ condition with +unless+:;T@
o;;[
I"unless true
;TI"! puts "the value is false"
;TI"
else
;TI" puts "the value is true"
;TI" end
;T;0o;
;[I"?This prints "the value is true" from the +else+ condition.;T@
o;
;[I"9You may not use +elsif+ with an +unless+ expression.;T@
o;
;[I"RThe result value of an +unless+ expression is the last value executed in the ;TI"expression.;T@
S; ;
i;I"Modifier +if+ and +unless+;T@
o;
;[I"Q+if+ and +unless+ can also be used to modify an expression. When used as a ;TI"Qmodifier the left-hand side is the "then" statement and the right-hand side ;TI"is the "test" expression:;T@
o;;[
I"a = 0
;TI"
;TI"a += 1 if a.zero?
;TI"
;TI" p a
;T;0o;
;[I"This will print 1.;T@
o;;[
I"a = 0
;TI"
;TI"a += 1 unless a.zero?
;TI"
;TI" p a
;T;0o;
;[I"This will print 0.;T@
o;
;[I"RWhile the modifier and standard versions have both a "test" expression and a ;TI"O"then" statement, they are not exact transformations of each other due to ;TI"@parse order. Here is an example that shows the difference:;T@
o;;[I"p a if a = 0.zero?
;T;0o;
;[I"HThis raises the NameError "undefined local variable or method `a'".;T@
o;
;[I"RWhen ruby parses this expression it first encounters +a+ as a method call in ;TI"Sthe "then" expression, then later it sees the assignment to +a+ in the "test" ;TI"2expression and marks +a+ as a local variable.;T@
o;
;[I"OWhen running this line it first executes the "test" expression, <code>a = ;TI"0.zero?</code>.;T@
o;
;[I"QSince the test is true it executes the "then" expression, <code>p a</code>. ;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 <code>"12345"</code> is compared with <code>/^1/</code> by ;TI"Pcalling <code>/^1/ === "12345"</code> 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 <code>/^1/ === "2"</code> ;TI"Sreturns +false+, then <code>"2" === "2"</code> 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 <code>a < 10</code> 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 <code>a ;TI"O> 10</code> 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"Modifier Statements;T@
o;
;[
I"LRuby's grammar differentiates between statements and expressions. All ;TI"Lexpressions are statements (an expression is a type of statement), but ;TI"Knot all statements are expressions. Some parts of the grammar accept ;TI"Kexpressions and not other types of statements, which causes code that ;TI",looks similar to be parsed differently.;T@
o;
;[ I"OFor example, when not used as a modifier, +if+, +else+, +while+, +until+, ;TI"Gand +begin+ are expressions (and also statements). However, when ;TI"Eused as a modifier, +if+, +else+, +while+, +until+ and +rescue+ ;TI"(are statements but not expressions.;T@
o;;[I";if true; 1 end # expression (and therefore statement)
;TI"11 if true # statement (not expression)
;T;0o;
;[I"MStatements that are not expressions cannot be used in contexts where an ;TI"6expression is expected, such as method arguments.;T@
o;;[I",puts( 1 if true ) #=> SyntaxError
;T;0o;
;[I"EYou can wrap a statement in parentheses to create an expression.;T@
o;;[I""puts((1 if true)) #=> 1
;T;0o;
;[I"MIf you put a space between the method name and opening parenthesis, you ;TI")do not need two sets of parentheses.;T@
o;;[I"Nputs (1 if true) #=> 1, because of optional parentheses for method
;T;0o;
;[I"EThis is because this is parsed similar to a method call without ;TI"Pparentheses. It is equivalent to the following code, without the creation ;TI"of a local variable:;T@
o;;[I"x = (1 if true)
;TI" p x
;T;0o;
;[I"MIn a modifier statement, the left-hand side must be a statement and the ;TI"+right-hand side must be an expression.;T@
o;
;[ I"NSo in <code>a if b rescue c</code>, because <code>b rescue c</code> is a ;TI"Nstatement that is not an expression, and therefore is not allowed as the ;TI"Mright-hand side of the +if+ modifier statement, the code is necessarily ;TI".parsed as <code>(a if b) rescue c</code>.;T@
o;
;[I"@This interacts with operator precedence in such a way that:;T@
o;;[I"stmt if v = expr rescue x
;TI"stmt if v = expr unless x
;T;0o;
;[I"are parsed as:;T@
o;;[I"!stmt if v = (expr rescue x)
;TI"!(stmt if v = expr) unless x
;T;0o;
;[I"RThis is because modifier +rescue+ has higher precedence than <code>=</code>, ;TI"@and modifier +if+ has lower precedence than <code>=</code>.;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 <code>ruby -n</code> ;TI"or <code>ruby -p</code>.;T@
o;
;[ I"HThe form of the flip-flop is an expression that indicates when the ;TI"Sflip-flop turns on, <code>..</code> (or <code>...</code>), 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 <code>n==2</code>. 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 (<code>..</code>), 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 (<code>...</code>), 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