Ruby offers the expected if and else expressions for branching logic, terminated by the end keyword:
# Simulate flipping a coin
result =[:heads,:tails].sample
if result ==:heads
puts 'The coin-toss came up "heads"'else
puts 'The coin-toss came up "tails"'end
In Ruby, if statements are expressions that evaluate to a value, and the result can be assigned to a variable:
If none of the conditions in an if/elsif chain are true, and there is no else clause, then the expression evaluates to nil. This can be useful inside string interpolation, since nil.to_s is the empty string:
Case statements consist of an optional condition, which is in the
position of an argument to `case`, and zero or more `when` clauses.
The first `when` clause to match the condition (or to evaluate to
Boolean truth, if the condition is null) “wins”, and its code stanza
is executed. The value of the case statement is the value of the
successful `when` clause, or `nil` if there is no such clause.
A case statement can end with an `else` clause. Each `when` a
statement can have multiple candidate values, separated by commas.
Example:
case x
when1,2,3
puts "1, 2, or 3"when10
puts "10"else
puts "Some other number"end
Shorter version:
case x
when1,2,3then puts "1, 2, or 3"when10then puts "10"else puts "Some other number"end
The value of the case clause is matched with each when clause using the === method (not ==). Therefore it can be used with a variety of different types of objects.
It is not possible to add an else clause to these modifiers. Also it is generally not recommended to use conditional modifiers inside the main logic -- For complex code one should use normal if, elsif, else instead.
while, until
A while loop executes the block while the given condition is met:
i =0while i <5
puts "Iteration ##{i}"
i +=1end
An until loop executes the block while the conditional is false:
i =0until i ==5
puts "Iteration ##{i}"
i +=1end
Or-Equals/Conditional assignment operator (||=)
Ruby has an or-equals operator that allows a value to be assigned to a variable if and only if that variable evaluates to either nil or false.
||= # this is the operator that achieves this.
this operator with the double pipes representing or and the equals sign representing assigning of a value. You may think it represents something like this:
x = x || y
this above example is not correct. The or-equals operator actually represents this:
x || x = y
If x evaluates to nil or false then x is assigned the value of y, and left unchanged otherwise.
Here is a practical use-case of the or-equals operator. Imagine you have a portion of your code that is expected to send an email to a user. What do you do if for what ever reason there is no email for this user. You might write something like this:
The flip flop operator .. is used between two conditions in a conditional statement:
(1..5).select do|e|
e if(e ==2)..(e ==4)end# => [2, 3, 4]
The condition evaluates to falseuntil the first part becomes true. Then it evaluates to trueuntil the second part becomes true. After that it switches to false again.
It is not possible to add an else clause to these modifiers. Also it is generally not recommended to use conditional modifiers inside the main logic -- For complex code one should use normal if, elsif, else instead.
throw, catch
Unlike many other programming languages, the throw and catch keywords are not related to exception handling in Ruby.
In Ruby, throw and catch act a bit like labels in other languages. They are used to change the control flow, but are not related to a concept of "error" like Exceptions are.
catch(:out)do
catch(:nested)do
puts "nested"end
puts "before"throw:out
puts "will not be executed"end
puts "after"# prints "nested", "before", "after"
Ternary operator
Ruby has a ternary operator (?:), which returns one of two value based on if a condition evaluates as truthy:
conditional ? value_if_truthy : value_if_falsy
value =true
value ?"true":"false"#=> "true"
value =false
value ?"true":"false"#=> "false"
it is the same as writing if a then b else c end, though the ternary is preferred
Examples:
puts (if1then2else3end)# => 2
puts 1?2:3# => 2
x =if1then2else3end
puts x # => 2
Loop control with break, next, and redo
The flow of execution of a Ruby block may be controlled with the break, next, and redo statements.
break
The break statement will exit the block immediately. Any remaining instructions in the block will be skipped, and the iteration will end:
actions =%w(run jump swim exit macarena)
index =0while index < actions.length
action = actions[index]breakif action =="exit"
index +=1
puts "Currently doing this action: #{action}"end# Currently doing this action: run# Currently doing this action: jump# Currently doing this action: swim
next
The next statement will return to the top of the block immediately, and proceed with the next iteration. Any remaining instructions in the block will be skipped:
actions =%w(run jump swim rest macarena)
index =0while index < actions.length
action = actions[index]
index +=1nextif action =="rest"
puts "Currently doing this action: #{action}"end# Currently doing this action: run# Currently doing this action: jump# Currently doing this action: swim# Currently doing this action: macarena
redo
The redo statement will return to the top of the block immediately, and retry the same iteration. Any remaining instructions in the block will be skipped:
actions =%w(run jump swim sleep macarena)
index =0
repeat_count =0while index < actions.length
action = actions[index]
puts "Currently doing this action: #{action}"if action =="sleep"
repeat_count +=1redoif repeat_count <3end
index +=1end# Currently doing this action: run# Currently doing this action: jump# Currently doing this action: swim# Currently doing this action: sleep# Currently doing this action: sleep# Currently doing this action: sleep# Currently doing this action: macarena
Enumerable iteration
In addition to loops, these statements work with Enumerable iteration methods, such as each and map:
In both the break and next statements, a value may be provided, and will be used as a block result value:
even_value =for value in[1,2,3]break value if value.even?end
puts "The first even value is: #{even_value}"# The first even value is: 2
return vs. next: non-local return in a block
Consider this broken snippet:
deffoo
bar =[1,2,3,4].map do|x|return0if x.even?
x
end
puts 'baz'
bar
end
foo # => 0
One might expect return to yield a value for map's array of block results. So the return value of foo would be [1, 0, 3, 0]. Instead, return returns a value from the method foo. Notice that baz isn't printed, which means execution never reached that line.
next with a value does the trick. It acts as a block-level return.
deffoo
bar =[1,2,3,4].map do|x|next0if x.even?
x
end
puts 'baz'
bar
end
foo # baz# => [1, 0, 3, 0]
In the absence of a return, the value returned by the block is the value of its last expression.
Control flow with logic statements
While it might seem counterintuitive, you can use logical operators to determine whether or not a statement is run. For instance:
File.exist?(filename)orSTDERR.puts "#{filename} does not exist!"
This will check to see if the file exists and only print the error message if it doesn't. The or statement is lazy, which means it'll stop executing once it's sure which whether it's value is true or false. As soon as the first term is found to be true, there's no need to check the value of the other term. But if the first term is false, it must check the second term.
A common use is to set a default value:
glass = glass or'full'# Optimist!
That sets the value of glass to 'full' if it's not already set. More concisely, you can use the symbolic version of or:
glass ||='empty'# Pessimist.
It's also possible to run the second statement only if the first one is false:
Again, and is lazy so it will only execute the second statement if necessary to arrive at a value.
The or operator has lower precedence than and. Similarly, || has lower precedence than &&. The symbol forms have higher precedence than the word forms. This is handy to know when you want to mix this technique with assignment:
The and and or keywords are banned. The minimal added readability is just not worth the high probability of introducing subtle bugs. For boolean expressions, always use && and || instead. For flow control, use if and unless; && and || are also acceptable but less clear.
begin, end
The begin block is a control structure that groups together multiple statements.
begin
a =7
b =6
a * b
end
A begin block will return the value of the last statement in the block. The following example will return 3.
begin123end
The begin block is useful for conditional assignment using the ||= operator where multiple statements may be required to return a result.
circumference ||=begin
radius =7
tau =Math::PI*2
tau * radius
end
It can also be combined with other block structures such as rescue, ensure, while, if, unless, etc to provide greater control of program flow.
Begin blocks are not code blocks, like { ... } or do ... end; they cannot be passed to functions.