- Home
- ruby Tutorial
- decision-making
Control Structures in Ruby
Conditional statements are used to alter the logic of the execution of the flow based on certain conditions. Here are a few conditional statements available to developers as a part of ruby.
Ruby if statement
The block of code mentioned in the if statement is executed only when the condition mentioned in the if statement becomes true.
age = gets.chomp.to_i
if age >= 18
puts "You are eligible to vote."
end
Flip-Flop operator
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 false until the first part becomes true. Then it evaluates to true until the second part becomes true. After that it switches to false again.
This example illustrates what is being selected:
[1, 2, 2, 3, 4, 4, 5].select do |e|
e if (e == 2) .. (e == 4)
end
# => [2, 2, 3, 4]
The flip-flop operator only works inside ifs (including unless) and ternary operator. Otherwise it is being considered as the range operator.
(1..5).select do |e|
(e == 2) .. (e == 4)
end
# => ArgumentError: bad value for range
It can switch from false to true and backwards multiple times:
((1..5).to_a * 2).select do |e|
e if (e == 2) .. (e == 4)
end
# => [2, 3, 4, 2, 3, 4]
while
A while loop keeps executing the code block till the conditional statement is rendered false:
i = 0
while i < 5
puts "Iteration ##{i}"
i +=1
end
Until statement
An until loop keeps executing the code block till the conditional statement is rendered true:
i = 0
until i == 5
puts "Iteration ##{i}"
i +=1
end
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.
A break statement terminates an ongoing iteration and stops the further iterations of the loop. It is used in conditions when we want the compiler to completely come out of the loop
:
actions = %w(run jump swim exit macarena)
index = 0
while index < actions.length
action = actions[index]
break if 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
The next statement terminates the ongoing iteration and starts with the next iteration immediately
:
actions = %w(run jump swim rest macarena)
index = 0
while index < actions.length
action = actions[index]
index += 1
next if 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
The redo statement terminates the ongoing statement and reiterates the terminated iteration
:
actions = %w(run jump swim sleep macarena)
index = 0
repeat_count = 0
while index < actions.length
action = actions[index]
puts "Currently doing this action: #{action}"
if action == "sleep"
repeat_count += 1
redo if repeat_count < 3
end
index += 1
end
# 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
Block result values
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:
def foo
bar = [1, 2, 3, 4].map do |x|
return 0 if 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.
def foo
bar = [1, 2, 3, 4].map do |x|
next 0 if 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.
Ruby if else
The code in if block is executed if the conditional statement is true. The else block is executed if the condition is false.
age = gets.chomp.to_i
if age >= 18
puts "You are eligible to vote."
else
puts "You are not eligible to vote."
end
Ruby if else if (elsif)
Ruby if else if statement tests the condition. The if block statement is executed if condition is true otherwise else block statement is executed.
age = gets.chomp.to_i
if age > 0 and age <= 2
puts "baby"
elsif age >= 3 and age <= 12
puts "child"
elsif age >=13 and age <= 19
puts "teenager"
elsif age >= 20 and age <= 60
puts "adult"
else
puts "old"
end
Ruby ternary Statement
In Ruby ternary statement, the if statement is shortened. First it evaluates an expression for true or false value then execute one of the statements.
age = gets.chomp.to_i
status = (age < 18 ? true : false)
Ruby Case Statement
Ruby uses the case keyword for switch statements.
As per the Ruby Docs:
- 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
when 1,2,3
puts "1, 2, or 3"
when 10
puts "10"
else
puts "Some other number"
end
Shorter version:
case x
when 1,2,3 then puts "1, 2, or 3"
when 10 then 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.
A case statement can be used with Ranges:
case 17
when 13..19
puts "teenager"
end
A case statement can be used with a Regexp:
case "google"
when /oo/
puts "word contains oo"
end
A case statement can be used with a Proc or lambda:
case 44
when -> (n) { n.even? or n < 0 }
puts "even or less than zero"
end
A case statement can be used with Classes:
case x
when Integer
puts "It's an integer"
when String
puts "It's a string"
end
By implementing the === method you can create your own match classes:
class Empty
def self.===(object)
!object or "" == object
end
end
case ""
when Empty
puts "name was empty"
else
puts "name is not empty"
end
A case statement can be used without a value to match against:
case
when ENV['A'] == 'Y'
puts 'A'
when ENV['B'] == 'Y'
puts 'B'
else
puts 'Neither A nor B'
end
A case statement has a value, so you can use it as a method argument or in an assignment:
description = case 16
when 13..19 then "teenager"
else ""
end
Truthy and Falsy values
In Ruby, there are exactly two values which are considered "falsy", and will return false when tested as a condition for an if expression. They are:
- nil
- boolean false
All other values are considered "truthy", including:
- numeric zero (Integer or otherwise)
- "" - Empty strings
- "\n" - Strings containing only whitespace
- [] - Empty arrays
- {} - Empty hashes
Take, for example, the following code:
def check_truthy(var_name, var)
is_truthy = var ? "truthy" : "falsy"
puts "#{var_name} is #{is_truthy}"
end
check_truthy("false", false)
check_truthy("nil", nil)
check_truthy("0", 0)
check_truthy("empty string", "")
check_truthy("\\n", "\n")
check_truthy("empty array", [])
check_truthy("empty hash", {})
Will output:
false is falsy
nil is falsy
0 is truthy
empty string is truthy
\n is truthy
empty array is truthy
empty hash is truthy
Inline if/unless
A common pattern is to use an inline, or trailing, if or unless:
puts "x is less than 5" if x < 5
This is known as a conditional modifier, and is a handy way of adding simple guard code and early returns:
hungry = true
unless hungry
puts "I'm learning Ruby course!"
else
puts "Time to eat!"
end
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.