Ruby 拯救类中所有方法的异常

Ruby 拯救类中所有方法的异常,ruby,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中,我可以使用\u call魔术方法创建抽象类,如下所示: class FooAb

基本上,这是正常代码:

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中,我可以使用
\u call
魔术方法创建抽象类,如下所示:

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

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

如何在Ruby类中使用uu call方法?

我不确定您想在这里实现什么,但Ruby等价于PHP的
\uu call()


默认情况下,当您尝试调用一个不存在的方法时,您将得到一个异常。但是如果你想实现一个“抽象类”。您也可以尝试这个解决方案:

我不确定您想要在这里实现什么,但是Ruby等价于PHP的
\u call()


默认情况下,当您尝试调用一个不存在的方法时,您将得到一个异常。但是如果你想实现一个“抽象类”。您也可以尝试此解决方案:

您可以定义一个模块,该模块在包含时定义了一个
方法\u添加的
钩子,该钩子将所有新方法包装在
开始..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
这将产生:

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..

(您只需将
handle\u method\u exceptions
重命名为
with\u rescue
并删除所有
@\u忽略\u添加的\u方法
技巧和
方法_添加的
方法,它应按说明工作).

您可以定义一个模块,其中包括定义一个
方法\u添加的
钩子,该钩子将所有新方法包装在
开始..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
这将产生:

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..

(您只需将
handle\u method\u exceptions
重命名为
with\u rescue
并删除所有
@\u忽略\u添加的\u方法
技巧和
method\u添加的
方法,它应该按说明工作)。

如果您想定义一个类,该类不能实例化,除非是子类,您可以执行
失败如果在FooAbstract中self.class==FooAbstract#initialize,则“尝试实例化抽象类”。这看起来像是一个XY问题。您试图实现什么?ruby中没有直接等价于
\u调用
;最接近的可能是
方法_缺少
。(同样,在PHP中也没有直接等价于
方法_missing
,但据我所知,
\u调用
可能是最接近的。)但是正如Stefan所说,你到底想在这里实现什么?我不能在不知道你想解决什么问题的情况下真正建议如何构造代码。我的猜测是完成rails类级别的
rescue\u from
,这样你就不必复制粘贴相同的
rescue
块到每个方法。不是你想用PHP代码说明什么,但是方法
hi
不会以任何方式调用
\uu调用
\uu调用
应该做什么,为子类的所有方法添加异常处理?如果你想定义一个类,除了子类之外不能实例化,你可以做一个
失败试图在FooAbstract中实例化抽象类“if self.class==FooAbstract
”初始化。这看起来像是一个XY问题。您试图实现什么?ruby中没有直接等价于
\u调用的方法;最接近的方法可能是
缺少的方法
。(同样,在PHP中也没有直接等价于
方法_missing
,但据我所知,
\u调用
可能是最接近的。)但是正如Stefan所说,你到底想在这里实现什么?我不能在不知道你想解决什么问题的情况下真正建议如何构造代码。我的猜测是完成rails类级别的
rescue\u from
,这样你就不必复制粘贴相同的
rescue
块到每个方法。不是你想用PHP代码说明什么,但是方法
hi
不会以任何方式调用
\uu调用
\uu调用
应该做什么,为子类的所有方法添加异常处理?这很好!但是如何使用实例方法作为
异常处理程序呢?我想知道无法以任何方式将异常记录到我的实例特定记录器。@meesern未经测试,但您可以尝试将
self.class.handle\u exception(ex)
替换为
(响应?(:handle\u exception)?self:self.class)。发送(:handle\u exception,ex)
并将异常处理程序定义为实例方法:
def handle\u exception(ex)…end
这很好!但是如何使用实例方法作为
异常处理程序呢?我希望能够将任何方法中的异常记录到我的实例特定记录器中。@meesern未经测试,但您可以尝试将
self.class.handle\u异常(ex)
替换为
(响应(:handle\u exception)?self:self.class).发送(:handle_exception,ex)
并将异常处理程序定义为实例方法:
def handle_exception(ex)…end