Спасти все ошибки определенного типа внутри модуля

У меня есть модуль, в котором я выполняю все свои задачи по шифрованию/дешифрованию для проекта. Я хотел бы поймать любые OpenSSL::Cipher::CipherError исключения, возникающие в этом модуле, чтобы я мог их обработать.

Можно ли сделать что-то вроде

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

внутри модуля?


person Matt    schedule 15.05.2013    source источник
comment
вы включаете этот модуль в контроллер или нет? rescue_from предназначен для использования только внутри контроллеров, поэтому выполнение чего-то подобного внутри простых старых объектов ruby ​​​​будет включать в себя несколько очень грязных хаков.   -  person shime    schedule 15.05.2013
comment
А, понял. Спасибо @shime   -  person Matt    schedule 15.05.2013
comment
Рад помочь. Проверьте здесь, если хотите узнать, что я имел в виду под грязными хаками: simonecarletti.com/blog/2009/12/ — мне не нравится, как все выглядит, когда вы делаете это в Ruby, и это кажется добавлением ненужного беспорядка. Извлечение обработки исключений в отдельный метод — это способ повысить уверенность в вашем коде, который, кажется, больше всего подходит для вашего сценария. Подробнее об этом читайте здесь: avdi.org/talks/confident-code-railsconf-2011   -  person shime    schedule 15.05.2013
comment
@shime Если вы хотите опубликовать свой комментарий в качестве ответа, я могу принять и закрыть этот вопрос. Спасибо!   -  person Matt    schedule 09.06.2013


Ответы (1)


Я немного исследовал и нашел решение. Вы сказали, что у вас есть модуль, в котором вы выполняете шифрование. Я предполагаю, что этот модуль представляет собой синглтон. Однако мое решение требует, чтобы у вас был экземпляр.

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

Извлечение поведения шифрования в модуле.

module Encryptable
   def encrypt
      # ...
   end

   def decrypt
      # ...
   end
end

Создайте новый модуль, который обрабатывает исключения.

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

Так что теперь вы можете использовать только что определенный handle_known_exceptions внутри вашего Crypto. Это не очень удобно, потому что вы не заработали много. Вам все равно придется вызывать обработчик исключений внутри каждого метода:

class Crypto
  include ExceptionHandler

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

Нет необходимости делать это, если мы определим делегатора, который сделает это за нас:

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

Полностью переопределить инициализацию Crypto, чтобы вместо этого использовать делегатор.

class Crypto
  include Encryptable

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

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

Вот и все!

person shime    schedule 14.06.2013
comment
Святые дымы, это довольно круто - большое спасибо! Я попробую!! - person Matt; 14.06.2013
comment
Ха-ха, это беспокоило меня, потому что я пару раз задавал себе твой вопрос. Играть с этим было так весело для меня, что я решил сделать гем, который позволяет rescue_from работать вне Rails. github.com/shime/rescue_from_ruby - person shime; 15.06.2013