Ruby:在代码块中更改类静态方法 [英] Ruby: Alter class static method in a code block

查看:84
本文介绍了Ruby:在代码块中更改类静态方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出Thread类的当前方法. 现在在测试中,我想这样做:

Given the Thread class with it current method. Now inside a test, I want to do this:

def test_alter_current_thread
  Thread.current = a_stubbed_method
  # do something that involve the work of Thread.current
  Thread.current = default_thread_current
end

基本上,我想在测试方法中更改类的方法,然后再将其恢复. 我知道对于另一种语言(例如Java& Java)来说,这听起来很复杂C#(在Java中,只有强大的模拟框架才能做到).但是它是红宝石,我希望这样的讨厌东西会可用

Basically, I want to alter the method of a class inside a test method and recover it after that. I know it sound complex for another language, like Java & C# (in Java, only powerful mock framework can do it). But it's ruby and I hope such nasty stuff would be available

推荐答案

您可能想看看Ruby模拟框架,例如此处)例如

You might want to take a look at a Ruby mocking framework like Mocha, but in terms of using plain Ruby it can be done using alias_method (documentation here) e.g.

事先:

class Thread
  class << self
    alias_method :old_current, :current
  end
end

然后定义您的新方法

class Thread
  def self.current
    # implementation here
  end
end

然后恢复旧方法:

class Thread
  class << self
    alias_method :current, :old_current
  end
end

更新以说明在测试中执行此操作

如果要在测试中执行此操作,可以定义一些辅助方法,如下所示:

If you want to do this from within a test you could define some helper methods as follows:

def replace_class_method(cls, meth, new_impl)
  cls.class_eval("class << self; alias_method :old_#{meth}, :#{meth}; end")
  cls.class_eval(new_impl)
end

def restore_class_method(cls, meth)
  cls.class_eval("class << self; alias_method :#{meth}, :old_#{meth}; end")
end

replace_class_method需要一个类常量,一个类方法的名称和新方法定义作为字符串. restore_class_method获取类和方法名称,然后将原始方法重新命名为别名.

replace_class_method is expecting a class constant, the name of a class method and the new method definition as a string. restore_class_method takes the class and the method name and then aliases the original method back in place.

您的测试将遵循以下条件:

Your test would then be along the lines of:

def test
  new_impl = <<EOM
  def self.current
    "replaced!"
  end
EOM
  replace_class_method(Thread, 'current', s)
  puts "Replaced method call: #{Thread.current}"
  restore_class_method(Thread, 'current')
  puts "Restored method call: #{Thread.current}"
end

您还可以编写一个小的包装方法,该方法将替换一个方法,屈服于一个块,然后确保随后恢复原始方法,例如.

You could also write a little wrapper method which would replace a method, yield to a block and then ensure that the original method was reinstated afterwards e.g.

def with_replaced_method(cls, meth, new_impl)
    replace_class_method(cls, meth, new_impl)
    begin
        result = yield
    ensure
        restore_class_method(cls, meth)
    end
    return result
end

在您的测试方法中,可以将其用作:

Inside your test method this could then be used as:

with_replaced_method(Thread, 'current', new_impl) do
  # test code using the replaced method goes here
end
# after this point the original method definition is restored

如原始答案中所述,您可能可以找到一个框架为您完成此操作,但是希望以上代码无论如何都是有趣且有用的.

As mentioned in the original answer, you can probably find a framework to do this for you but hopefully the above code is interesting and useful anyway.

这篇关于Ruby:在代码块中更改类静态方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆