如何在超时包装器中包装类中的所有类方法

时间:2014-03-18 04:27:58

标签: ruby methods timeout metaprogramming alias

我正在尝试创建一个类方法,该方法将超时包装器放在其他类方法周围。

class FooBar

  def self.slow_add(a,b,c)
    sleep 1
    a + b + c
  end

  LIST = [:slow_add]

  class << self
    LIST.each do |x|
      alias_method "#{x}_without_timeout", "#{x}"
      define_method("#{x}_with_timeout") do |*args|
        timeout(4){self.send(x, *args)}
      end
      alias_method "#{x}", "#{x}_with_timeout"
    end
  end
end

但是,生成的超时方法总是超时,即使它们不应该:

2.0.0p353 :152 >   FooBar.slow_add_without_timeout(1, 2, 3)
 => 6 
2.0.0p353 :153 > FooBar.slow_add_with_timeout(1, 2, 3)
Timeout::Error: execution expired
...
...
2.0.0p353 :156 >   FooBar.slow_add(1, 2, 3)
Timeout::Error: execution expired
...
...

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

如果您能够向您的班级发送超时消息非常重要,我建议您创建一个辅助类,它将在超时块中包装每个方法调用并将消息转发到原始类参考对象。像这样:

require 'timeout'

class TimeoutHandler
  attr_reader :seconds, :object
  def initialize(object, seconds)
    @seconds = seconds
    @object = object
  end

  def method_missing(name, *args, &block)
    Timeout::timeout(seconds){ object.send(name, *args, &block) }
  end
end

您可以像这样创建TimeoutHandler的实例:

class FooBar
  class << self
    def timeout(seconds = 4)
      TimeoutHandler.new(self, seconds)
    end
  end
end

因此,只要您需要使用超时块中断消息,您只需先在其上调用timeout

FooBar.timeout.slow_add(1, 2, 3)

您可以在mixin中编写timeout方法,以包含在您需要此功能的类中。

但是,所有这一切对我来说都是非常有用的,我需要一个很好的理由来实现它,而不是仅仅使用更简单的Timeout::timeout { FooBar.slow_add(1, 2, 3) },它不需要任何额外的实现。< / p>