1= Control Expressions 2 3Ruby has a variety of ways to control execution. All the expressions described 4here return a value. 5 6For the tests in these control expressions, +nil+ and +false+ are false-values 7and +true+ and any other object are true-values. In this document "true" will 8mean "true-value" and "false" will mean "false-value". 9 10== +if+ Expression 11 12The simplest +if+ expression has two parts, a "test" expression and a "then" 13expression. If the "test" expression evaluates to a true then the "then" 14expression is evaluated. 15 16Here is a simple if statement: 17 18 if true then 19 puts "the test resulted in a true-value" 20 end 21 22This will print "the test resulted in a true-value". 23 24The +then+ is optional: 25 26 if true 27 puts "the test resulted in a true-value" 28 end 29 30This document will omit the optional +then+ for all expressions as that is the 31most common usage of +if+. 32 33You may also add an +else+ expression. If the test does not evaluate to true 34the +else+ expression will be executed: 35 36 if false 37 puts "the test resulted in a true-value" 38 else 39 puts "the test resulted in a false-value" 40 end 41 42This will print "the test resulted in a false-value". 43 44You may add an arbitrary number of extra tests to an if expression using 45+elsif+. An +elsif+ executes when all tests above the +elsif+ are false. 46 47 a = 1 48 49 if a == 0 50 puts "a is zero" 51 elsif a == 1 52 puts "a is one" 53 else 54 puts "a is some other value" 55 end 56 57This will print "a is one" as <code>1</code> is not equal to <code>0</code>. 58Since +else+ is only executed when there are no matching conditions. 59 60Once a condition matches, either the +if+ condition or any +elsif+ condition, 61the +if+ expression is complete and no further tests will be performed. 62 63Like an +if+, an +elsif+ condition may be followed by a +then+. 64 65In this example only "a is one" is printed: 66 67 a = 1 68 69 if a == 0 70 puts "a is zero" 71 elsif a == 1 72 puts "a is one" 73 elsif a >= 1 74 puts "a is greater than or equal to one" 75 else 76 puts "a is some other value" 77 end 78 79The tests for +if+ and +elsif+ may have side-effects. The most common use of 80side-effect is to cache a value into a local variable: 81 82 if a = object.some_value 83 # do something to a 84 end 85 86The result value of an +if+ expression is the last value executed in the 87expression. 88 89== Ternary if 90 91You may also write a if-then-else expression using <code>?</code> and 92<code>:</code>. This ternary if: 93 94 input_type = gets =~ /hello/i ? "greeting" : "other" 95 96Is the same as this +if+ expression: 97 98 input_type = 99 if gets =~ /hello/i 100 "greeting" 101 else 102 "other" 103 end 104 105While the ternary if is much shorter to write than the more verbose form, for 106readability it is recommended that the ternary if is only used for simple 107conditionals. Also, avoid using multiple ternary conditions in the same 108expression as this can be confusing. 109 110== +unless+ Expression 111 112The +unless+ expression is the opposite of the +if+ expression. If the value 113is false, the "then" expression is executed: 114 115 unless true 116 puts "the value is a false-value" 117 end 118 119This prints nothing as true is not a false-value. 120 121You may use an optional +then+ with +unless+ just like +if+. 122 123Note that the above +unless+ expression is the same as: 124 125 if not true 126 puts "the value is a false-value" 127 end 128 129Like an +if+ expression you may use an +else+ condition with +unless+: 130 131 unless true 132 puts "the value is false" 133 else 134 puts "the value is true" 135 end 136 137This prints "the value is true" from the +else+ condition. 138 139You may not use +elsif+ with an +unless+ expression. 140 141The result value of an +unless+ expression is the last value executed in the 142expression. 143 144== Modifier +if+ and +unless+ 145 146+if+ and +unless+ can also be used to modify an expression. When used as a 147modifier the left-hand side is the "then" expression and the right-hand side 148is the "test" expression: 149 150 a = 0 151 152 a += 1 if a.zero? 153 154 p a 155 156This will print 1. 157 158 a = 0 159 160 a += 1 unless a.zero? 161 162 p a 163 164This will print 0. 165 166While the modifier and standard versions have both a "test" expression and a 167"then" expression, they are not exact transformations of each other due to 168parse order. Here is an example that shows the difference: 169 170 p a if a = 0.zero? 171 172This raises the NameError "undefined local variable or method `a'". 173 174When ruby parses this expression it first encounters +a+ as a method call in 175the "then" expression, then later it sees the assignment to +a+ in the "test" 176expression and marks +a+ as a local variable. 177 178When running this line it first executes the "test" expression, <code>a = 1790.zero?</code>. 180 181Since the test is true it executes the "then" expression, <code>p a</code>. 182Since the +a+ in the body was recorded as a method which does not exist the 183NameError is raised. 184 185The same is true for +unless+. 186 187== +case+ Expression 188 189The +case+ expression can be used in two ways. 190 191The most common way is to compare an object against multiple patterns. The 192patterns are matched using the +===+ method which is aliased to +==+ on 193Object. Other classes must override it to give meaningful behavior. See 194Module#=== and Regexp#=== for examples. 195 196Here is an example of using +case+ to compare a String against a pattern: 197 198 case "12345" 199 when /^1/ 200 puts "the string starts with one" 201 else 202 puts "I don't know what the string starts with" 203 end 204 205Here the string <code>"12345"</code> is compared with <code>/^1/</code> by 206calling <code>/^1/ === "12345"</code> which returns +true+. Like the +if+ 207expression, the first +when+ that matches is executed and all other matches are 208ignored. 209 210If no matches are found, the +else+ is executed. 211 212The +else+ and +then+ are optional, this +case+ expression gives the same 213result as the one above: 214 215 case "12345" 216 when /^1/ 217 puts "the string starts with one" 218 end 219 220You may place multiple conditions on the same +when+: 221 222 case "2" 223 when /^1/, "2" 224 puts "the string starts with one or is '2'" 225 end 226 227Ruby will try each condition in turn, so first <code>/^1/ === "2"</code> 228returns +false+, then <code>"2" === "2"</code> returns +true+, so "the string 229starts with one or is '2'" is printed. 230 231You may use +then+ after the +when+ condition. This is most frequently used 232to place the body of the +when+ on a single line. 233 234 case a 235 when 1, 2 then puts "a is one or two 236 when 3 then puts "a is three" 237 else puts "I don't know what a is" 238 end 239 240The other way to use a +case+ expression is like an if-elsif expression: 241 242 a = 2 243 244 case 245 when a == 1, a == 2 246 puts "a is one or two" 247 when a == 3 248 puts "a is three" 249 else 250 puts "I don't know what a is" 251 end 252 253Again, the +then+ and +else+ are optional. 254 255The result value of a +case+ expression is the last value executed in the 256expression. 257 258== +while+ Loop 259 260The +while+ loop executes while a condition is true: 261 262 a = 0 263 264 while a < 10 do 265 p a 266 a += 1 267 end 268 269 p a 270 271Prints the numbers 0 through 10. The condition <code>a < 10</code> is checked 272before the loop is entered, then the body executes, then the condition is 273checked again. When the condition results in false the loop is terminated. 274 275The +do+ keyword is optional. The following loop is equivalent to the loop 276above: 277 278 while a < 10 279 p a 280 a += 1 281 end 282 283The result of a +while+ loop is +nil+ unless +break+ is used to supply a 284value. 285 286== +until+ Loop 287 288The +until+ loop executes while a condition is false: 289 290 a = 0 291 292 until a > 10 do 293 p a 294 a += 1 295 end 296 297 p a 298 299This prints the numbers 0 through 11. Like a while loop the condition <code>a 300> 10</code> is checked when entering the loop and each time the loop body 301executes. If the condition is false the loop will continue to execute. 302 303Like a +while+ loop, the +do+ is optional. 304 305Like a +while+ loop, the result of an +until+ loop is nil unless +break+ is 306used. 307 308== +for+ Loop 309 310The +for+ loop consists of +for+ followed by a variable to contain the 311iteration argument followed by +in+ and the value to iterate over using #each. 312The +do+ is optional: 313 314 for value in [1, 2, 3] do 315 puts value 316 end 317 318Prints 1, 2 and 3. 319 320Like +while+ and +until+, the +do+ is optional. 321 322The +for+ loop is similar to using #each, but does not create a new variable 323scope. 324 325The result value of a +for+ loop is the value iterated over unless +break+ is 326used. 327 328The +for+ loop is rarely used in modern ruby programs. 329 330== Modifier +while+ and +until+ 331 332Like +if+ and +unless+, +while+ and +until+ can be used as modifiers: 333 334 a = 0 335 336 a += 1 while a < 10 337 338 p a # prints 10 339 340+until+ used as a modifier: 341 342 a = 0 343 344 a += 1 until a > 10 345 346 p a # prints 11 347 348You can use +begin+ and +end+ to create a +while+ loop that runs the body once 349before the condition: 350 351 a = 0 352 353 begin 354 a += 1 355 end while a < 10 356 357 p a # prints 10 358 359If you don't use +rescue+ or +ensure+, Ruby optimizes away any exception 360handling overhead. 361 362== +break+ Statement 363 364Use +break+ to leave a block early. This will stop iterating over the items in +values+ if one of them is even: 365 366 values.each do |value| 367 break if value.even? 368 369 # ... 370 end 371 372You can also terminate from a +while+ loop using +break+: 373 374 a = 0 375 376 while true do 377 p a 378 a += 1 379 380 break if a < 10 381 end 382 383 p a 384 385This prints the numbers 0 and 1. 386 387+break+ accepts a value that supplies the result of the expression it is 388"breaking" out of: 389 390 result = [1, 2, 3].each do |value| 391 break value * 2 if value.even? 392 end 393 394 p result # prints 4 395 396== +next+ Statement 397 398Use +next+ to skip the rest of the current iteration: 399 400 result = [1, 2, 3].map do |value| 401 next if value.even? 402 403 value * 2 404 end 405 406 p result # prints [2, nil, 6] 407 408+next+ accepts an argument that can be used as the result of the current 409block iteration: 410 411 result = [1, 2, 3].map do |value| 412 next value if value.even? 413 414 value * 2 415 end 416 417 p result # prints [2, 2, 6] 418 419== +redo+ Statement 420 421Use +redo+ to redo the current iteration: 422 423 result = [] 424 425 while result.length < 10 do 426 result << result.length 427 428 redo if result.last.even? 429 430 result << result.length + 1 431 end 432 433 p result 434 435This prints [0, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11] 436 437In Ruby 1.8, you could also use +retry+ where you used +redo+. This is no 438longer true, now you will receive a SyntaxError when you use +retry+ outside 439of a +rescue+ block. See {Exceptions}[rdoc-ref:syntax/exceptions.rdoc] 440for proper usage of +retry+. 441 442== Flip-Flop 443 444The flip-flop is a rarely seen conditional expression. It's primary use is 445for processing text from ruby one-line programs used with <code>ruby -n</code> 446or <code>ruby -p</code>. 447 448The form of the flip-flop is an expression that indicates when the 449flip-flop turns on, <code>..</code> (or <code>...</code>), then an expression 450that indicates when the flip-flop will turn off. While the flip-flop is on it 451will continue to evaluate to +true+, and +false+ when off. 452 453Here is an example: 454 455 456 selected = [] 457 458 0.upto 10 do |value| 459 selected << value if value==2..value==8 460 end 461 462 p selected # prints [2, 3, 4, 5, 6, 7, 8] 463 464In the above example, the on condition is <code>n==2</code>. The flip-flop 465is initially off (false) for 0 and 1, but becomes on (true) for 2 and remains 466on through 8. After 8 it turns off and remains off for 9 and 10. 467 468The flip-flop must be used inside a conditional such as +if+, +while+, 469+unless+, +until+ etc. including the modifier forms. 470 471When you use an inclusive range (<code>..</code>), the off condition is 472evaluated when the on condition changes: 473 474 selected = [] 475 476 0.upto 5 do |value| 477 selected << value if value==2..value==2 478 end 479 480 p selected # prints [2] 481 482Here, both sides of the flip-flop are evaluated so the flip-flop turns on and 483off only when +value+ equals 2. Since the flip-flop turned on in the 484iteration it returns true. 485 486When you use an exclusive range (<code>...</code>), the off condition is 487evaluated on the following iteration: 488 489 selected = [] 490 491 0.upto 5 do |value| 492 selected << value if value==2...value==2 493 end 494 495 p selected # prints [2, 3, 4, 5] 496 497Here, the flip-flop turns on when +value+ equals 2, but doesn't turn off on the 498same iteration. The off condition isn't evaluated until the following 499iteration and +value+ will never be two again. 500