Skip to main content
View
Chapter 5 / 16Conditionals
1. Variables and data types
2. Strings and symbols
3. Arrays
4. Hashes
5. Conditionals
6. Loops and iterators
7. Methods and blocks
8. Classes and objects
9. Inheritance
10. Modules
11. Extending code with prepend
12. Enumerable
13. Where to go next
14. Error handling
15. Reading and writing files
16. Advanced class features

Conditionals

This chapter introduces conditionals, the mechanism that allows a program to make decisions. Depending on the situation, the code executes one branch or another.

Principle

Up until now, our programs ran from top to bottom, line by line. But a useful program needs to be able to react: if the Pokemon is fainted, display a message. If the attack is super effective, double the damage. That is the role of conditionals: test a situation and act accordingly.

True or false in Ruby (truthiness)

Before looking at conditionals, we need to understand how Ruby decides if something is "true" or "false".

The rule is very simple: only false and nil are considered false. Everything else is true, even values that seem "empty" in other languages:

# These values are all considered true
puts 'oui' if 0 # 0 is true!
puts 'oui' if '' # an empty String is true!
puts 'oui' if [] # an empty Array is true!

# Only false and nil are false
puts 'oui' if false # not printed
puts 'oui' if nil # not printed
  • This is a Ruby-specific behavior. In other languages, 0 or "" are often false. Not in Ruby.
  • To test if a number equals zero, write number == 0. To test if a String is empty, use .empty?.

if / elsif / else

The most common structure for executing code based on a condition:

level = 50

if level >= 100
puts 'Maximum level reached!'
elsif level >= 50
puts 'High-level Pokémon'
elsif level >= 20
puts 'Medium-level Pokémon'
else
puts 'Low-level Pokémon'
end
  • Ruby evaluates each condition from top to bottom and executes the first one that is true.
  • elsif (not elseif or else if) adds additional conditions.
  • else executes when none of the previous conditions are true. It is optional.
  • The block ends with end.

A simple if without elsif or else:

health_points = 0

if health_points <= 0
puts 'The Pokémon is KO!'
end

unless

unless is the opposite of if. It executes the code when the condition is false:

held_item = nil

unless held_item
puts 'The Pokémon holds no item.'
end
  • unless held_item means "if held_item is false (i.e., nil or false)".
  • unless makes the code more readable when testing a simple negation. The golden rule is to avoid double negations: unless !condition is confusing, a simple if condition is much clearer. unless with && is acceptable as long as the sentence remains easy to understand. However, avoid unless with else: if you need an else, then an if would be more readable.

Postfix form (one-liner)

When the code to execute fits on a single line, you can put the condition at the end:

level = 100
health_points = 0

puts 'Maximum level!' if level >= 100
puts 'The Pokémon is KO!' if health_points <= 0
puts 'The Pokémon is healthy.' unless health_points <= 0
  • This is exactly the same as an if ... end, but more compact.
  • It reads naturally: "print this message if the level is greater than or equal to 100".
  • Use it only when the code fits on one line. For longer blocks, use the classic form.

case / when

When comparing the same value against multiple possibilities, case/when is more readable than a chain of if/elsif:

pokemon_type = :fire

case pokemon_type
when :fire
puts 'Strong against Grass, weak against Water'
when :water
puts 'Strong against Fire, weak against Grass'
when :grass
puts 'Strong against Water, weak against Fire'
when :electric
puts 'Strong against Water'
else
puts "Unknown type: #{pokemon_type}"
end
  • case takes the value to compare. Each when tests a possibility.
  • Only one when executes (no "fall-through" like in C or JavaScript).
  • else is optional, it covers all cases not listed.

case/when also works with ranges (intervals):

level = 45

case level
when 1..30
puts 'Low level'
when 31..60
puts 'Medium level'
when 61..100
puts 'High level'
end
  • 1..30 is a Range (interval) that includes 1 and 30. Ruby checks if level falls within this interval.

And with classes (types):

value = 42

case value
when Integer
puts 'An integer'
when String
puts 'Some text'
when Symbol
puts 'A symbol'
end

Comparison operators

puts 50 == 50 # => true (equal)
puts 50 != 75 # => true (not equal)
puts 50 < 75 # => true (less than)
puts 50 > 75 # => false (greater than)
puts 50 <= 50 # => true (less than or equal)
puts 50 >= 75 # => false (greater than or equal)
  • == compares values. Be careful not to confuse it with = which is assignment.

There is also the "spaceship" operator <=> which returns -1, 0, or 1:

puts 10 <=> 20 # => -1 (10 is smaller)
puts 20 <=> 20 # => 0 (equal)
puts 30 <=> 20 # => 1 (30 is larger)
  • <=> is used by .sort to compare elements against each other. We will revisit it in later chapters.

Logical operators

To combine multiple conditions, use && (and), || (or), and ! (not):

level = 80
is_legendary = false

# && : BOTH conditions must be true
if level >= 50 && !is_legendary
puts 'Powerful and non-legendary Pokémon'
end

# || : at least ONE condition must be true
if is_legendary || level >= 80
puts 'Rare Pokémon!'
end

# ! : inverts the value
if !is_legendary
puts 'Non-legendary Pokémon'
end
  • && returns true if both sides are true.
  • || returns true if at least one side is true.
  • ! inverts: !true gives false, !false gives true, !nil gives true.

Ruby also provides and, or, and not which do the same thing but with lower precedence. In practice, always use &&, ||, and ! to avoid surprises.

The ||= operator (or-equals)

||= is a very common shortcut. It assigns a value only if the variable is nil or false:

ability = nil
ability ||= :static
puts ability # => static (ability was nil, so :static was assigned)

ability ||= :lightning_rod
puts ability # => static (ability already had a value, nothing changes)
  • ability ||= :static is equivalent to ability = ability || :static.
  • If ability is nil, || takes the right-hand value (:static). If ability already has a value, || keeps the left-hand one.
  • This is very useful for defining default values.

The ternary operator

To choose between two values in a single line:

level = 50
category = level >= 50 ? 'strong' : 'weak'
puts category # => fort
  • condition ? value_if_true : value_if_false is a shortcut for an if/else that returns a value.
  • Use it when the choice is simple and fits on one line. For more complex cases, prefer if/else.

Conclusion

  • In Ruby, only false and nil are false. Everything else (0, "", []) is true.
  • if/elsif/else/end for conditionals. The keyword is elsif (not elseif).
  • unless for simple negations. Do not use it with else or compound conditions.
  • The postfix form (puts 'message' if condition) is ideal for simple one-liners.
  • case/when compares a value against multiple possibilities (values, ranges, classes).
  • == compares values. && (and), || (or), ! (not) combine conditions.
  • ||= assigns a value only if the variable is nil or false.
  • The ternary operator condition ? true : false chooses between two values in one line.