पाठ 11 / 25

Exceptions and Error Handling

Raise, rescue, retry and ensure, and design custom exception classes.

Handling failure gracefully

Raise exceptions with raise: raise ArgumentError, "amount must be positive". Handle them with begin ... rescue ... else ... ensure ... end, or directly in a method body: rescue clauses match exception classes (most specific first), else runs when nothing was raised, and ensure always runs, for cleanup. retry re-runs the begin block, useful with a counter for transient network errors. Rescue StandardError (what a bare rescue catches) or specific subclasses, never Exception, which also includes system signals and SystemExit, making programs hard to stop. Define custom exceptions by subclassing StandardError, adding attributes for context, and group them under a base class for your library (PaymentError < StandardError). Methods with ! commonly raise on failure while their plain versions return nil or false (save! versus save in Rails). Use ensure or block-based APIs (File.open with a block) so resources are always released. Inline rescue modifiers (value = risky rescue nil) hide all errors and should be avoided.

Custom errors, retry and ensure

Specific rescues, limited retries and guaranteed cleanup.

class PaymentError < StandardError; end

class PaymentDeclined < PaymentError
  attr_reader :reason
  def initialize(reason)
    @reason = reason
    super("Payment declined: #{reason}")
  end
end

class GatewayTimeout < PaymentError; end

def charge(amount, token)
  attempts = 0
  begin
    attempts += 1
    gateway_call(amount, token)
  rescue GatewayTimeout
    retry if attempts < 3                         # transient: try again
    raise
  rescue PaymentDeclined => e
    puts "Declined (#{e.reason}); not retrying"
    nil
  else
    puts "Charged on attempt #{attempts}"
  ensure
    puts "payment attempt finished"               # always runs
  end
end

def gateway_call(amount, token)
  raise ArgumentError, "amount must be positive" unless amount.positive?
  raise PaymentDeclined, "card blocked" if token.start_with?("blocked")
  "pay_123"
end

A safety net with a cleanup crew

rescue is the safety net that catches specific falls, retry lets the performer try the jump again a limited number of times, and ensure is the cleanup crew that sweeps the stage whatever happened.

त्वरित जाँच: Why should you rescue StandardError rather than Exception?

  • Exception does not exist
  • Exception also catches signals and SystemExit, making programs hard to interrupt or exit
  • StandardError is faster
  • Ruby forbids rescuing Exception
Answer

Exception also catches signals and SystemExit, making programs hard to interrupt or exit — Rescuing Exception swallows interrupts and exit requests, not just application errors.