Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rescue all errors of a specific type inside a module

I have a module in which I am performing all of my encryption/decryption tasks for a project. I would like to catch any OpenSSL::Cipher::CipherError exceptions that occur in this module so that I can handle them.

Is it possible to do something like

rescue_from OpenSSL::Cipher::CipherError, :with => :cipher_error

inside of a module?

like image 781
Matt Avatar asked May 15 '13 14:05

Matt


People also ask

How do I rescue a specific error in Ruby?

In Ruby, we use the rescue keyword for that. When rescuing an exception in Ruby, you can specify a specific error class that should be rescued from. Note: When using raise without specifying an exception class, Ruby will default to RuntimeError .

How can you catch a specific type of exception in Python?

Try and except statements are used to catch and handle exceptions in Python. Statements that can raise exceptions are kept inside the try clause and the statements that handle the exception are written inside except clause.

What is the use of rescue in rails?

In a nutshell, the begin-rescue is a code block that can be used to deal with raised exceptions without interrupting program execution. In other words, you can begin to execute a block of code, and rescue any exceptions that are raised.

How do you catch errors in Python?

The try and except block in Python is used to catch and handle exceptions. Python executes code following the try statement as a “normal” part of the program. The code that follows the except statement is the program's response to any exceptions in the preceding try clause.


1 Answers

I've investigated a little and came with a solution. You said you have a module in which you do your encryption. I'm guessing that module represents a singleton. My solution, however, requires you have an instance instead.

class Crypto
   def self.instance
      @__instance__ ||= new
   end
end

Extract encryption behavior in a module.

module Encryptable
   def encrypt
      # ...
   end

   def decrypt
      # ...
   end
end

Create a new module that handles exceptions.

module ExceptionHandler
  extend ActiveSupport::Concern

  included do
    include ActiveSupport::Rescuable
    rescue_from StandardError, :with => :known_error
  end

  def handle_known_exceptions
     yield
  rescue => ex
     rescue_with_handler(ex) || raise
  end

  def known_error(ex)
    Rails.logger.error "[ExceptionHandler] Exception #{ex.class}: #{ex.message}"
  end
end

So now you can use the newly defined handle_known_exceptions inside your Crypto. This is not very convenient because you haven't gained much. You still have to call the exception handler inside every method:

class Crypto
  include ExceptionHandler

  def print_bunnies
    handle_known_exceptions do
      File.open("bunnies")
    end
  end
end

No need to do this if we define a delegator that does that for us:

class CryptoDelegator
  include ExceptionHandler

  def initialize(target)
    @target = target
  end

  def method_missing(*args, &block)
    handle_known_exceptions do
      @target.send(*args, &block)
    end
  end
end

Completely override the initialization of Crypto, to use the delegator instead.

class Crypto
  include Encryptable

  def self.new(*args, &block)
    CryptoDelegator.new(super)
  end

  def self.instance
      @__instance__ ||= new
  end
end

And that's it!

like image 99
shime Avatar answered Sep 18 '22 00:09

shime