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