抢救类中所有方法的异常

时间:2018-06-18 09:14:20

标签: ruby

基本上,这是正常的代码:

class Foo
   def hi
      # your code here....
   rescue => e
      # Raise error here
   end

   def hello
      # your code here...
   rescue => e
      # Raise error here
   end
end

但在PHP中,我可以使用__call魔术方法来创建抽象类,如下所示:

class FooAbstract {
    public function __call($name, $args) {
       # Try catch in here...
    }
}

class Foo extends FooAbstract {
   public function hi() {
     # Code with try catch...
   }
}

如何在Ruby类中使用__call方法???

2 个答案:

答案 0 :(得分:1)

我不确定你想在这里实现什么,但PHP的__call()的Ruby等价物是method_missing

默认情况下,当您尝试调用不存在的方法时,您将收到异常。但是如果你想实现一个"抽象类"。您也可以尝试此解决方案:https://stackoverflow.com/a/512505/185870

答案 1 :(得分:1)

你可以定义一个模块,当包含它时定义一个method_added钩子,它将所有新方法包装在begin..rescue块中:

require 'set'

module ExceptionHandler

  def self.included(klass)
    super
    klass.send(:extend, ClassMethods)
  end

  module ClassMethods
    def exception_handler(&block)
      @__exception_handler = block.to_proc
    end

    def handle_exception(exception)
      defined?(@__exception_handler) ? @__exception_handler.call(exception) : super
    end

    def handle_method_exceptions(method_name)
      old_method = instance_method(method_name)
      return if (@__hooked_methods ||= Set.new).include?(method_name)

      @__ignoring_added_methods = true # avoid infinite define_method/method_added loop
      define_method method_name do |*args, &block|
        begin
          old_method.bind(self).(*args, &block)
        rescue => ex
          self.class.handle_exception(ex)
        end
      end
      @__ignoring_added_methods = false

      @__hooked_methods << method_name
    end

    def method_added(method_name)
      super
      unless @__ignoring_added_methods
        handle_method_exceptions(method_name)
      end
    end
  end
end

这将用作:

class Foo
  include ExceptionHandler

  exception_handler do |exception|
    puts "Catched an exception:"
    puts "---------------------"
    puts "Exception class: #{exception.class}"
    puts "Message: #{exception.message}"
    puts "Backtrace:"
    puts exception.backtrace.join("\n  ")
    puts
    puts "reraising.."
    puts
    raise exception
  end

  def this_raises
    raise "somebody set up us the bomb"
  end
end

Foo.new.this_raises

这将输出:

Catched an exception:
---------------------
Exception class: RuntimeError
Message: somebody set up us the bomb
Backtrace:
errorhandler.rb:62:in `this_raises'
  errorhandler.rb:26:in `call'
  errorhandler.rb:26:in `block in handle_exceptions'
  errorhandler.rb:67:in `<main>'

reraising..

我不确定这是不是一个好主意。

您可以取出method_added部分,它看起来像:

class Foo
  with_rescue def foofoo(arg)
    puts arg.inspect
  end
end

(您可以将handle_method_exceptions重命名为with_rescue并删除所有@__ignoring_added_methods欺骗和method_added方法,它应按照描述运行。