#---If, Else, Unless and Case When---
In Ruby, conditionals are used to run code based on certain conditions. They allow your program to make decisions and execute different pieces of code depending on whether a condition is true or false.
Ruby provides several constructs for implementing
conditionals, including if
, unless
, case-when
, and
ternary
operators.
if
is the most common conditional. It executes a block
of code if the supplied condition evaluates to true.
age = 25
if age >= 18
p "You can drive now"
end
## => "You can drive now"
You can add additional conditions using elsif
and
provide a default case with else.
age = 16
if age >= 18
p "You can drink now"
elsif age >= 13
p "You can't drink now"
else
p "You can drink water"
end
## => "You can't drink now"
unless
is the opposite of if
. It executes
a block of code if the condition is false.
raining = false
unless raining
p "Let's sprint up the hill"
end
## => "Let's sprint up the hill"
If unless condition
is hard to grok, you can totally
replace it with if !condition
, or
if not condition
(not
is a ruby keyword).
It’s all the same.
day_time = true
if not day_time
p "Let's train in the garage"
elsif !raining
p "Let's sprint up the hill"
else
p "Let's netflix and chill"
end
## => "Let's sprint up the hill"
Just like if-else
, there’s also unless-else
.
unless day_time
p "Let's train in the garage"
else
p "Let's sprint up the hill"
end
But don’t use this. It doesn’t read natural.
Instead, invert the condition and make it an if
.
if day_time
p "Let's sprint up the hill"
else
p "Let's train in the garage"
end
And whether you’re using it with an else
or not, don’t
chain multiple conditions to it. It’s hard to make sense
of the full condition.
run unless (x == y) || !(z != y) && friday? rescue nil
On second thought, it doesn’t make sense with if
too.
It’s better to extract these separate conditions into
separate methods that are well-named.
run if friday? && joe_mad? rescue nil
Note: The rescue nil
is only because the methods run
, friday?
, joe_mad?
are all undefined.
All of this is not to say unless
is bad. Use it like
you would in plain English. Like, “Walk the dog unless
it’s raining”.
In Ruby every statement evaluates to a single
expression. That means the whole if-else statement,
despite spanning multiple lines, evaluates to a single
value, noted by the last line of either of the blocks.
That value can be assigned to a variable.
So instead of writing this:
msg = ""
if day_time
thumbs_up = 'π' * 2
msg = "Hey, you're a cool person #{thumbs_up}"
else
thumbs_up = 'π'
msg = "Hey, you're a cool person #{thumbs_up}"
end
You can write this:
msg = if day_time
thumbs_up = 'π' * 2
"Hey, you're a cool person #{thumbs_up}"
else
thumbs_up = 'π'
"Hey, you're a cool person #{thumbs_up}"
end
p msg # => "Hey, you're a cool person ππ"
If the code you have to run based on a condition is just a single line, often you can write the whole thing as a one-liner.
Instead of this:
def greet(name)
if name
"You're stupid awesome #{name}!"
else
"You're stupid awesome!"
end
end
You can write this:
def greet(name)
return "You're stupid awesome!" unless name
"You're stupid awesome #{name}!"
end
Inside the if
block, if you don’t have very many
things to do except to just return a value for a
variable, use the ternary operator instead to write
simple one-line if-else statements.
It takes 3 operands: a condition, a value if true, and a value if false.
require 'date'
mood = Date.today.month <= 6 ? 'π' : 'π¬'
p mood # => "π"
centurion = [99, 100, 98].include?(100) ? true : false
p centurion # => true
This is Ruby’s “Switch” statement. Use it when you need multiple “if else” logic.
grade = 'B'
case grade
when 'A'
p 'Nice'
when 'B'
p 'Meh'
else
p 'lol'
end
## => "Meh"
But you can do so much more:
def case_demo(grade)
case grade
when 'A'..'C'
'within A and C'
when /^-/
'negative grade!'
when Numeric
'number grade'
when 'X', 'Y'
'grade is specifically X or Y'
else
'unknown grade'
end
end
p case_demo('A') # => "within A and C"
p case_demo(77) # => "number grade"
p case_demo('-A') # => "negative grade!"
p case_demo('X') # => "grade is specifically X or Y"
p case_demo('m') # => "unknown grade"
To understand how it works, you should know about the
===
method that’s implemented on a handful of ruby
classes.
This is how Ruby sees the above case statement:
if ('A'..'C').===(grade)
'within A and C'
elsif /^-/.===(grade)
'negative grade!'
elsif Numeric.===(grade)
'number grade'
elsif 'X'.===(grade) || 'Y'.===(grade)
'grade is specifically X or Y'
else
'unknown grade'
end
As you can see, the ===
method does different things
based on the class it’s implemented for.
Try adding one more codition to case_demo
with a
proc that returns a bool:
## A proc that returns a bool
a_proc = -> { it.is_a?(Numeric) && it.even? }
p a_proc.===(42) # => true
Also, the ===
thing is named confusingly. It’s usually
called the “triple equals operator” or “case equality
operator”.
But it’s neither an operator, nor about equality.
JΓΆrg W Mittag calls it the “case subsumption operator”
and I fully endorse it.