Ruby Exceptions
Handling errors gracefully in your Ruby programs
⚠️ What are Exceptions?
Exceptions are errors that occur during program execution. Ruby provides a robust exception handling mechanism to catch and manage errors, preventing your program from crashing unexpectedly.
# Basic exception handling
begin
result = 10 / 0
rescue ZeroDivisionError
puts "Cannot divide by zero!"
end
Output:
Cannot divide by zero!
Key Exception Concepts
begin-rescue
Catch and handle exceptions
begin
# risky code
rescue
# handle error
end
Specific Errors
Catch specific exception types
rescue TypeError
puts "Type error!"
end
ensure
Code that always runs
ensure
# cleanup code
file.close
end
raise
Throw custom exceptions
raise "Error!"
raise TypeError
end
🔹 Basic Exception Handling
Use begin-rescue blocks to catch exceptions and prevent your program from crashing. The code in the begin block is executed, and if an error occurs, the rescue block handles it gracefully.
begin
puts "Enter a number:"
num = gets.chomp.to_i
result = 100 / num
puts "Result: #{result}"
rescue ZeroDivisionError
puts "Error: Cannot divide by zero!"
rescue => e
puts "An error occurred: #{e.message}"
end
puts "Program continues..."
Output (if user enters 0):
Enter a number: Error: Cannot divide by zero! Program continues...
🔹 Multiple Rescue Clauses
You can handle different types of exceptions separately by using multiple rescue clauses. This allows you to provide specific error messages and recovery actions for different error scenarios.
def process_data(data)
begin
number = Integer(data)
result = 100 / number
puts "Result: #{result}"
rescue ZeroDivisionError
puts "Error: Division by zero is not allowed"
rescue ArgumentError
puts "Error: Invalid number format"
rescue TypeError
puts "Error: Wrong data type provided"
end
end
process_data("0") # Division by zero
process_data("abc") # Invalid format
process_data(nil) # Wrong type
Output:
Error: Division by zero is not allowed Error: Invalid number format Error: Wrong data type provided
🔹 Using ensure
The ensure block always executes, whether an exception occurs or not. This is perfect for cleanup operations like closing files, database connections, or releasing resources that must happen regardless of errors.
def read_file(filename)
begin
file = File.open(filename, "r")
content = file.read
puts "File content: #{content}"
rescue Errno::ENOENT
puts "Error: File not found!"
rescue => e
puts "Error reading file: #{e.message}"
ensure
file.close if file
puts "File operation completed"
end
end
read_file("test.txt")
Output:
Error: File not found! File operation completed
🔹 Raising Exceptions
You can manually raise exceptions using the raise keyword. This is useful for validating input, enforcing business rules, or signaling error conditions in your code that should be handled by calling code.
def check_age(age)
raise ArgumentError, "Age cannot be negative" if age < 0
raise ArgumentError, "Age must be a number" unless age.is_a?(Integer)
if age < 18
puts "You are a minor"
else
puts "You are an adult"
end
end
begin
check_age(-5)
rescue ArgumentError => e
puts "Invalid age: #{e.message}"
end
begin
check_age(25)
rescue ArgumentError => e
puts "Invalid age: #{e.message}"
end
Output:
Invalid age: Age cannot be negative You are an adult
🔹 Custom Exception Classes
Create your own exception classes by inheriting from StandardError. Custom exceptions make your code more readable and allow you to handle specific application errors differently from system errors.
class InsufficientFundsError < StandardError
def initialize(amount, balance)
super("Insufficient funds: tried to withdraw #{amount}, but balance is #{balance}")
end
end
class BankAccount
attr_reader :balance
def initialize(balance)
@balance = balance
end
def withdraw(amount)
raise InsufficientFundsError.new(amount, @balance) if amount > @balance
@balance -= amount
puts "Withdrew #{amount}. New balance: #{@balance}"
end
end
account = BankAccount.new(100)
begin
account.withdraw(50)
account.withdraw(80)
rescue InsufficientFundsError => e
puts "Transaction failed: #{e.message}"
end
Output:
Withdrew 50. New balance: 50 Transaction failed: Insufficient funds: tried to withdraw 80, but balance is 50