【问题标题】:Multiple classes of the same name in RubyRuby中的多个同名类
【发布时间】:2014-02-11 18:24:37
【问题描述】:

我有一个现有的单元测试代码库,其中为每个测试定义了相同的类,以及一个迭代它们的程序。像这样的:

test_files.each do |tf|   
  load "tests/#{tf}/"+tf
  test=     ::Kernel.const_get("my_class")
  Test::Unit::UI::Console::TestRunner.run( test )

在进行这些测试时,我意识到 ruby​​ 允许您从不同的文件中require 具有相同名称的类,并且它合并了两者的方法。一旦类层次结构不同,这就会导致问题:superclass mismatch for class ...

不幸的是,仅仅unloading the class 是不够的,因为层次结构中还有许多其他类仍处于加载状态。

有没有办法在不同的全局命名空间中执行每个测试?

虽然我认为使用模块是可行的方法,但我对手动更改数百个现有文件的想法并不感到兴奋。

--编辑--

按照 Cary Swoveland 的建议,我已将测试运行代码移至单独的 .rb 文件并使用反引号运行它。虽然这似乎运作良好,但再次加载 ruby​​ 解释器和 requireing 所有库都会产生相当大的开销。此外,跨平台兼容性需要一些额外的工作。

【问题讨论】:

  • 使用反引号或system 分别运行每个测试怎么样?
  • @CarySwoveland 这似乎主要工作(见编辑),感谢您的建议!
  • 为什么需要在测试中定义类?也许你有它的原因,但它似乎有点测试气味。
  • @MarkThomas 这些不是传统意义上的实际单元测试,而是使用Sipper 框架的功能测试,这是面向对象的并且要求您的测试是类。我无法判断框架是否需要以这种方式编写,但事实是确实如此。
  • 如何在循环中以动态方式包装带有模块的类?

标签: ruby namespaces


【解决方案1】:

首先我想提出以下解决方案:

#main.rb
modules = []

Dir.foreach('include') do |file|
  if file =~ /\w/
    new_module = Module.new

    load "include/#{file}"

    new_module.const_set("StandardClass", StandardClass)

    Object.send(:remove_const, :StandardClass)

    modules << new_module
  end

end

modules.each do |my_module|
  my_module::StandardClass.standard_method
end

#include/first.rb
class StandardClass
  def self.standard_method
    puts "first method"
  end
end

#include/second.rb
class StandardClass
  def self.standard_method
    puts "second method"
  end
end

这用它自己的模块包装每个类并调用它的模块内的类:

$ruby main.rb
second method
first method

但是正如您回答的那样,存在对其他类的引用,因此模块可以破坏它们。 我通过从其中一个包装类中调用第三个类来检查这一点并得到:

include/second.rb:5:in `standard_method': uninitialized constant StandardClass::Independent (NameError)

所以可能使用反引号是更好的解决方案,但我希望我的回答对其他类似情况有所帮助。

【讨论】:

    猜你喜欢
    • 2020-07-06
    • 2020-07-21
    • 2022-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-29
    • 2021-12-19
    相关资源
    最近更新 更多