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!
rescue_from
is meant to be used inside controllers only, so doing something like this inside plain old ruby objects would include some very dirty hacks. – Duwe