Operators & Expressions
Reviewed & published by Brayan K
Operators are the symbols — like +, ==, and && — that combine values into expressions, and an expression is any piece of Ruby code that evaluates to a single value.
Part of the free Ruby course at LearnCodingFast — hands-on lessons with worked examples and the output they print, plus practice exercises and a quick quiz.
By the end you'll do arithmetic, compare with the spaceship <=>, combine conditions with &&/||, and swap variables with parallel assignment.
What You'll Learn in This Lesson
- Arithmetic operators, including ** and %
- Comparison and the spaceship operator <=>
- Logical &&, ||, ! and the low-precedence and/or
- The ternary cond ? a : b shortcut
- Ranges as values with .. and ...
- Parallel assignment and the splat * to grab the rest
1️⃣ Arithmetic Operators
Ruby has the usual + - * /, plus % for the remainder (modulo) and ** for powers. The big gotcha: dividing two integers gives an integer, truncated toward zero. Mix in a .0 when you want decimals.
# Arithmetic operators
puts 7 + 3 # addition
puts 7 - 3 # subtraction
puts 7 * 3 # multiplication
puts 7 / 3 # integer division (truncates!)
puts 7 % 3 # modulo (remainder)
puts 7.0 / 3 # float division
puts 2 ** 10 # exponent (power)
puts(-7 % 3) # Ruby modulo follows the sign of the divisor2️⃣ Comparison & the Spaceship
Comparison operators return true or false. The star of the show is <=>, the spaceship operator: it returns -1, 0, or 1 and powers all of Ruby's sorting.
# Comparison & the spaceship operator
puts 5 > 3 # true
puts 5 <= 5 # true
puts 5 == 5.0 # true (value equality across Integer/Float)
puts 5.eql?(5.0) # false (eql? also checks type)
puts "abc" == "abc" # true
# <=> returns -1, 0, or 1 (or nil if not comparable)
puts(1 <=> 2) # -1 (left is smaller)
puts(2 <=> 2) # 0 (equal)
puts(3 <=> 2) # 1 (left is larger)
p ("a" <=> 1) # nil (not comparable)3️⃣ Logical, Ternary & Ranges
In Ruby && and || return one of their operands, which makes value || default a tidy way to supply fallbacks. The ternary cond ? a : b is a compact if/else, and ranges built with .. and ... are first-class values you can convert, test, and iterate.
# Logical operators
puts (true && false) # false
puts (true || false) # true
puts (!true) # false
# && and || return one of the OPERANDS, not just true/false
puts (nil || "default") # "default" (|| picks first truthy)
puts ("set" || "default") # "set"
puts (5 && 10) # 10 (&& returns last if all truthy)
# and / or have VERY low precedence — handy for control flow, not assignment
x = false || true # || binds tighter than =, so x = (false || true)
puts x # true# Ternary, ranges, parallel assignment
age = 20
status = age >= 18 ? "adult" : "minor" # ternary: cond ? a : b
puts status
# Ranges are values too: .. includes the end, ... excludes it
puts (1..5).to_a.inspect # [1, 2, 3, 4, 5]
puts (1...5).to_a.inspect # [1, 2, 3, 4]
puts ('a'..'e').to_a.inspect # ["a", "b", "c", "d", "e"]
puts (1..10).include?(7) # true
# Parallel (multiple) assignment
a, b, c = 1, 2, 3
puts "#{a} #{b} #{c}"
a, b = b, a # swap without a temp variable!
puts "#{a} #{b}"
first, *rest = [10, 20, 30, 40]
p first
p restYour turn. Fill in each ___ blank with the right operator, then run it.
# 🎯 YOUR TURN — fill in the blanks, then run with: ruby split.rb
total = 17
people = 5
each = total ___ people # 👉 integer division (one slash)
leftover = total ___ people # 👉 modulo (the remainder operator)
puts "Each gets #{each}, with #{leftover} left over."
score = 72
grade = score >= 60 ___ "pass" : "fail" # 👉 the ternary "then" symbol
puts "You #{grade}."
# ✅ Expected output:
# Each gets 3, with 2 left over.
# You pass.Mini-Challenge: FizzBuzz & a Range Fixer
Put modulo, logical operators, and parallel assignment together. Classify a number FizzBuzz-style, then swap two variables so the range comes out in order. Run with ruby ops.rb.
# 🎯 MINI-CHALLENGE: a tiny FizzBuzz + range fixer.
# Save as ops.rb and run with: ruby ops.rb
#
# 1. For n = 18, print "Fizz" if divisible by 3, "Buzz" if by 5,
# "FizzBuzz" if by both, otherwise the number — use % and && .
# 2. Given low, high = 5, 2, swap them with parallel assignment
# so low <= high, then print (low..high).to_a.
#
# ✅ Example output:
# Fizz
# Range: [2, 3, 4, 5]
# your code hereCommon Errors (and the fix)
- ❌ 7 / 3 expecting 2.33 → ✅ integer division truncates; use 7.0 / 3 or 7.fdiv(3).
- ❌ x = a and b behaving oddly → ✅ and has lower precedence than =; use x = a && b.
- ❌ if x = 5 (assigns, always truthy) → ✅ compare with ==: if x == 5.
- ❌ Forgetting the ternary colon → ✅ the form is cond ? a : b, with spaces around the ? and :.
- ❌ (1...5) includes 5 → ✅ three dots exclude the end; (1...5) is 1,2,3,4.
Pro Tips
- 💡 Swap in one line: a, b = b, a needs no temporary variable.
- 💡 Defaults with ||: name = input || "Guest" falls back when input is nil/false.
- 💡 Operators are methods: 1 + 2 is really 1.+(2), which is why your own classes can define +.
📋 Quick Reference — Operators
| Concept | Ruby Syntax |
|---|---|
| Power / modulo | 2 ** 10 , 7 % 3 |
| Float division | 7.0 / 3 |
| Spaceship | a <=> b |
| Logical (tight) | && , || , ! |
| Ternary | cond ? a : b |
| Ranges | 1..5 , 1...5 |
| Swap / splat | a, b = b, a |
🎉 Lesson Complete!
- ✅ Arithmetic with + - * / % ** — integer division truncates
- ✅ Comparison and the spaceship <=> returning -1/0/1
- ✅ &&/|| return operands; and/or bind loosely
- ✅ Ternary cond ? a : b and ranges .. / ...
- ✅ Parallel assignment and the splat *rest
Practice quiz
What does the spaceship operator return for (1 <=> 2)?
- 1
- 0
- -1
- nil
Answer: -1. <=> returns -1 when the left value is smaller than the right.
What does (3 <=> 2) return?
- -1
- 0
- 1
- nil
Answer: 1. <=> returns 1 when the left value is larger.
What does ("a" <=> 1) return?
- -1
- 0
- 1
- nil
Answer: nil. <=> returns nil when the two values cannot be compared.
What does 5 == 5.0 evaluate to?
- true
- false
- nil
- an error
Answer: true. == compares value across Integer and Float, so 5 == 5.0 is true.
What does 5.eql?(5.0) evaluate to?
- true
- false
- nil
- an error
Answer: false. eql? also requires the same type, and Integer 5 is not Float 5.0, so it's false.
What does (nil || "default") return?
- nil
- true
- "default"
- false
Answer: "default". || returns the first truthy operand; nil is falsy, so it returns "default".
What does (5 && 10) return?
- true
- 5
- 10
- false
Answer: 10. && returns the last operand when all are truthy, so it returns 10.
What does -7 % 3 evaluate to in Ruby?
- -1
- 1
- 2
- -2
Answer: 2. Ruby's % follows the sign of the divisor, so -7 % 3 is 2.
After a, b = 1, 2; a, b = b, a, what are a and b?
- 1 and 2
- 2 and 1
- 1 and 1
- 2 and 2
Answer: 2 and 1. Parallel assignment swaps without a temp variable, so a is 2 and b is 1.
After first, *rest = [10, 20, 30, 40], what is rest?
- [10, 20, 30]
- [20, 30, 40]
- 40
- [10]
Answer: [20, 30, 40]. The splat *rest grabs the leftover items into an array: [20, 30, 40].
Continue this course
- Previous: Variables & Types
- Next: nil, true, false & Truthiness — Only nil and false are falsy — plus &. , ||= and safe nil handling
- Quick reference: Ruby cheat sheet
Frequently asked questions
Why does 7 / 3 give 2 instead of 2.33 in Ruby?
When both operands are integers, Ruby uses integer division and throws away the fractional part, so 7 / 3 is 2. To get a floating-point result, make at least one side a Float: 7.0 / 3 or 7.fdiv(3) both give 2.333…. The matching remainder lives in the modulo operator, so 7 % 3 is 1. This integer-division behaviour trips up nearly every beginner, so reach for a .0 whenever you actually want decimals.
What is the spaceship operator <=> for?
The <=> operator compares two values and returns -1 if the left is smaller, 0 if they are equal, 1 if the left is larger, or nil if they cannot be compared. It is the engine behind sorting: sort and sort_by call <=> under the hood. When you define <=> on your own class and include the Comparable module, you instantly get <, <=, ==, >, >=, and between? for free.
What's the difference between && and 'and' in Ruby?
Both mean logical AND, but they have very different precedence. && binds tightly (tighter than assignment), so x = a && b assigns the result of a && b to x. The word 'and' binds very loosely (looser than =), so x = a and b actually parses as (x = a) and b — a classic bug. Use && and || for boolean logic in expressions, and reserve the low-precedence and/or for control-flow at the end of a line, like do_thing or raise.
Are 0 and an empty string falsy in Ruby?
No — and this surprises people coming from JavaScript or Python. In Ruby the ONLY falsy values are nil and false. Everything else, including 0, 0.0, an empty string "", and an empty array [], is truthy. So if 0 will run its block. You'll explore this fully in the next lesson on truthiness, but keep it in mind whenever you write a condition.