Ruby has a variety of ways to control execution. All the expressionsdescribed here return a value.
For the tests in these control expressions,nil
andfalse
are false-values andtrue
and any otherobject are true-values. In this document “true” will mean “true-value” and“false” will mean “false-value”.
if
Expression¶↑The simplestif
expression has two parts, a “test” expressionand a “then” expression. If the “test” expression evaluates to a true thenthe “then” expression is evaluated.
Here is a simple if statement:
iftruethenputs"the test resulted in a true-value"end
This will print “the test resulted in a true-value”.
Thethen
is optional:
iftrueputs"the test resulted in a true-value"end
This document will omit the optionalthen
for all expressionsas that is the most common usage ofif
.
You may also add anelse
expression. If the test does notevaluate to true theelse
expression will be executed:
iffalseputs"the test resulted in a true-value"elseputs"the test resulted in a false-value"end
This will print “the test resulted in a false-value”.
You may add an arbitrary number of extra tests to an if expression usingelsif
. Anelsif
executes when all tests abovetheelsif
are false.
a =1ifa==0puts"a is zero"elsifa==1puts"a is one"elseputs"a is some other value"end
This will print “a is one” as1
is not equal to0
. Sinceelse
is only executed when there are nomatching conditions.
Once a condition matches, either theif
condition or anyelsif
condition, theif
expression is completeand no further tests will be performed.
Like anif
, anelsif
condition may be followed byathen
.
In this example only “a is one” is printed:
a =1ifa==0puts"a is zero"elsifa==1puts"a is one"elsifa>=1puts"a is greater than or equal to one"elseputs"a is some other value"end
The tests forif
andelsif
may have side-effects.The most common use of side-effect is to cache a value into a localvariable:
ifa =object.some_value# do something to aend
The result value of anif
expression is the last valueexecuted in the expression.
You may also write a if-then-else expression using?
and:
. This ternary if:
input_type =gets=~/hello/i?"greeting":"other"
Is the same as thisif
expression:
input_type =ifgets=~/hello/i"greeting"else"other"end
While the ternary if is much shorter to write than the more verbose form,for readability it is recommended that the ternary if is only used forsimple conditionals. Also, avoid using multiple ternary conditions in thesame expression as this can be confusing.
unless
Expression¶↑Theunless
expression is the opposite of theif
expression. If the value is false, the “then” expression is executed:
unlesstrueputs"the value is a false-value"end
This prints nothing as true is not a false-value.
You may use an optionalthen
withunless
justlikeif
.
Note that the aboveunless
expression is the same as:
ifnottrueputs"the value is a false-value"end
Like anif
expression you may use anelse
condition withunless
:
unlesstrueputs"the value is false"elseputs"the value is true"end
This prints “the value is true” from theelse
condition.
You may not useelsif
with anunless
expression.
The result value of anunless
expression is the last valueexecuted in the expression.
if
andunless
¶↑if
andunless
can also be used to modify anexpression. When used as a modifier the left-hand side is the “then”statement and the right-hand side is the “test” expression:
a =0a+=1ifa.zero?pa
This will print 1.
a =0a+=1unlessa.zero?pa
This will print 0.
While the modifier and standard versions have both a “test” expression anda “then” statement, they are not exact transformations of each other due toparse order. Here is an example that shows the difference:
paifa =0.zero?
This raises theNameError “undefinedlocal variable or method `a'”.
When ruby parses this expression it first encountersa
as amethod call in the “then” expression, then later it sees the assignment toa
in the “test” expression and marksa
as a localvariable.
When running this line it first executes the “test” expression,a =0.zero?
.
Since the test is true it executes the “then” expression,p a
.Since thea
in the body was recorded as a method which doesnot exist theNameError is raised.
The same is true forunless
.
case
Expression¶↑Thecase
expression can be used in two ways.
The most common way is to compare an object against multiple patterns. Thepatterns are matched using the +===+ method which is aliased to +==+ onObject. Other classes must override it togive meaningful behavior. SeeModule#=== andRegexp#=== for examples.
Here is an example of usingcase
to compare aString against a pattern:
case"12345"when/^1/puts"the string starts with one"elseputs"I don't know what the string starts with"end
Here the string"12345"
is compared with/^1/
by calling/^1/ === "12345"
whichreturnstrue
. Like theif
expression, the firstwhen
that matches is executed and all other matches areignored.
If no matches are found, theelse
is executed.
Theelse
andthen
are optional, thiscase
expression gives the same result as the one above:
case"12345"when/^1/puts"the string starts with one"end
You may place multiple conditions on the samewhen
:
case"2"when/^1/,"2"puts"the string starts with one or is '2'"end
Ruby will try each condition in turn, so first/^1/ ==="2"
returnsfalse
, then"2"=== "2"
returnstrue
, so “the string startswith one or is '2'” is printed.
You may usethen
after thewhen
condition. Thisis most frequently used to place the body of thewhen
on asingle line.
caseawhen1,2thenputs"a is one or two"when3thenputs"a is three"elseputs"I don't know what a is"end
The other way to use acase
expression is like an if-elsifexpression:
a =2casewhena==1,a==2puts"a is one or two"whena==3puts"a is three"elseputs"I don't know what a is"end
Again, thethen
andelse
are optional.
The result value of acase
expression is the last valueexecuted in the expression.
Since Ruby 2.7,case
expressions also provide a more powerfulexperimental pattern matching feature via thein
keyword:
case {a: 1, b: 2, c: 3}in a: Integer => m "matched: #{m}"else "not matched"end# => "matched: 1"
The pattern matching syntax is described on its own page.
while
Loop¶↑Thewhile
loop executes while a condition is true:
a =0whilea<10dopaa+=1endpa
Prints the numbers 0 through 10. The conditiona < 10
ischecked before the loop is entered, then the body executes, then thecondition is checked again. When the condition results in false the loopis terminated.
Thedo
keyword is optional. The following loop is equivalentto the loop above:
whilea<10paa+=1end
The result of awhile
loop isnil
unlessbreak
is used to supply a value.
until
Loop¶↑Theuntil
loop executes while a condition is false:
a =0untila>10dopaa+=1endpa
This prints the numbers 0 through 11. Like a while loop the conditiona > 10
is checked when entering the loop and each time theloop body executes. If the condition is false the loop will continue toexecute.
Like awhile
loop, thedo
is optional.
Like awhile
loop, the result of anuntil
loop isnil unlessbreak
is used.
for
Loop¶↑Thefor
loop consists offor
followed by avariable to contain the iteration argument followed byin
andthe value to iterate over using each. Thedo
is optional:
forvaluein [1,2,3]doputsvalueend
Prints 1, 2 and 3.
Likewhile
anduntil
, thedo
isoptional.
Thefor
loop is similar to using each, but does not create anew variable scope.
The result value of afor
loop is the value iterated overunlessbreak
is used.
Thefor
loop is rarely used in modern ruby programs.
while
anduntil
¶↑Likeif
andunless
,while
anduntil
can be used as modifiers:
a =0a+=1whilea<10pa# prints 10
until
used as a modifier:
a =0a+=1untila>10pa# prints 11
You can usebegin
andend
to create awhile
loop that runs the body once before the condition:
a =0begina+=1endwhilea<10pa# prints 10
If you don't userescue
orensure
, Rubyoptimizes away any exception handling overhead.
break
Statement¶↑Usebreak
to leave a block early. This will stop iteratingover the items invalues
if one of them is even:
values.eachdo|value|breakifvalue.even?# ...end
You can also terminate from awhile
loop usingbreak
:
a =0whiletruedopaa+=1breakifa<10endpa
This prints the numbers 0 and 1.
break
accepts a value that supplies the result of theexpression it is “breaking” out of:
result = [1,2,3].eachdo|value|breakvalue*2ifvalue.even?endpresult# prints 4
next
Statement¶↑Usenext
to skip the rest of the current iteration:
result = [1,2,3].mapdo|value|nextifvalue.even?value*2endpresult# prints [2, nil, 6]
next
accepts an argument that can be used as the result of thecurrent block iteration:
result = [1,2,3].mapdo|value|nextvalueifvalue.even?value*2endpresult# prints [2, 2, 6]
redo
Statement¶↑Useredo
to redo the current iteration:
result = []whileresult.length<10doresult<<result.lengthredoifresult.last.even?result<<result.length+1endpresult
This prints [0, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11]
In Ruby 1.8, you could also useretry
where you usedredo
. This is no longer true, now you will receive aSyntaxError when you useretry
outside of arescue
block. See Exceptionsfor proper usage ofretry
.
Ruby's grammar differentiates between statements and expressions. Allexpressions are statements (an expression is a type of statement), but notall statements are expressions. Some parts of the grammar acceptexpressions and not other types of statements, which causes code that lookssimilar to be parsed differently.
For example, when not used as a modifier,if
,else
,while
,until
, andbegin
are expressions (and also statements). However, whenused as a modifier,if
,else
,while
,until
andrescue
are statements but notexpressions.
iftrue;1end# expression (and therefore statement)1iftrue# statement (not expression)
Statements that are not expressions cannot be used in contexts where anexpression is expected, such as method arguments.
puts( 1 if true ) #=> SyntaxError
You can wrap a statement in parentheses to create an expression.
puts((1iftrue))#=> 1
If you put a space between the method name and opening parenthesis, you donot need two sets of parentheses.
puts (1iftrue)#=> 1, because of optional parentheses for method
This is because this is parsed similar to a method call withoutparentheses. It is equivalent to the following code, without the creationof a local variable:
x = (1iftrue)px
In a modifier statement, the left-hand side must be a statement and theright-hand side must be an expression.
So ina if b rescue c
, becauseb rescue c
is astatement that is not an expression, and therefore is not allowed as theright-hand side of theif
modifier statement, the code isnecessarily parsed as(a if b) rescue c
.
This interacts with operator precedence in such a way that:
stmtifv =exprrescuexstmtifv =exprunlessx
are parsed as:
stmtifv = (exprrescuex)(stmtifv =expr)unlessx
This is because modifierrescue
has higher precedence than=
, and modifierif
has lower precedence than=
.
The flip-flop is a rarely seen conditional expression. It's primaryuse is for processing text from ruby one-line programs used withruby-n
orruby -p
.
The form of the flip-flop is an expression that indicates when theflip-flop turns on,..
(or...
), then anexpression that indicates when the flip-flop will turn off. While theflip-flop is on it will continue to evaluate totrue
, andfalse
when off.
Here is an example:
selected = []0.upto10do|value|selected<<valueifvalue==2..value==8endpselected# prints [2, 3, 4, 5, 6, 7, 8]
In the above example, the on condition isn==2
. The flip-flopis initially off (false) for 0 and 1, but becomes on (true) for 2 andremains on through 8. After 8 it turns off and remains off for 9 and 10.
The flip-flop must be used inside a conditional such asif
,while
,unless
,until
etc. includingthe modifier forms.
When you use an inclusive range (..
), the off condition isevaluated when the on condition changes:
selected = []0.upto5do|value|selected<<valueifvalue==2..value==2endpselected# prints [2]
Here, both sides of the flip-flop are evaluated so the flip-flop turns onand off only whenvalue
equals 2. Since the flip-flop turnedon in the iteration it returns true.
When you use an exclusive range (...
), the off condition isevaluated on the following iteration:
selected = []0.upto5do|value|selected<<valueifvalue==2...value==2endpselected# prints [2, 3, 4, 5]
Here, the flip-flop turns on whenvalue
equals 2, butdoesn't turn off on the same iteration. The off condition isn'tevaluated until the following iteration andvalue
will neverbe two again.
Generated with Rubydoc Rdoc Generator 0.42.0.