Question

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?

Was it helpful?

Solution

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!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top