0

我终其一生都找不到任何简单的解释。

我正在开发一个项目,该项目拥有自己的自定义代码,但也对包含的 gem 可用的类进行了一些扩展/覆盖。

实现此目的的正确文件夹结构和模块命名模式是什么?

例如,这是我为第三方“parallel_tests”gem 的扩展组织代码的方式,我正在研究的库称为“ChemistyKit

lib/
  chemistrykit/
     parallel_tests/ # the gem name space i'm extending
       rspec/ 
         runner.rb

所以我基本上遵循该parallel_tests文件夹下的 gem 相同的命名结构。

然后在那个runner.rb文件中我有类似的东西:

module ChemistryKit
  module ParallelTests
    module RSpec
      class Runner < ParallelTests::Test::Runner

但是,使用它会导致错误。我认为这是因为它实际上从未覆盖有问题的类,因为它的命名空间在ChemistryKit这很令人困惑,因为在RSpec HTML 格式化程序的这种扩展中,格式化程序是在 gem 的顶级命名空间下使用的。那是因为在这种情况下它创建了一个名称相似但不同的类吗?目的不是覆盖,而是扩展?

4

1 回答 1

1

要完全替换 RSpec 中的 Runner 类,您需要执行以下操作

module RSpec
  module Core
    remove_const(:Runner)
    class Runner < ParallelTests::Test::Runner
      ...
    end
  end
end

模块内部的代码使用基于其名称的路径查找常量。因此,您在示例中定义的 Runner 类指的是常量ChemistryKit::ParallelTests::RSpec::Runner

您可以通过指定您的 RSpec 模块位于全局命名空间中来从您的模块之一引用 RSpec Runner,如下例所示。

module ChemistryKit
  module ParallelTests
    module ::RSpec
      module Core
        class Runner < ParallelTests::Test::Runner

现在即使你这样做了,以这种方式修改类还有另一个问题。因为你想替换 Class 你必须先删除它否则你只会修改现有的类(如果你指定不同的超类,你不能重新打开一个类,rspec runner 已经是 Object 的子类,你可以不要改变它)。这就是remove_const我在第一个示例中调用的目的。

然而,额外的模块实际上并没有在上面的例子中做任何事情,只是让事情变得不太清楚。修改现有 gem 的代码时,只需将所有代码放在 rspec 子文件夹中(就像您一样),但模块名称与原始代码完全相同。

请记住,以这种方式修改类很容易失败。例如,如果在需要时使用该类,则您的替换要等到之后才会发生,这可能会导致无法预料的问题。这就是您链接的格式化程序示例采用不同方法的原因,代码不会猴子补丁 RSpec,而是在运行时附加其新类。

于 2013-08-10T18:56:18.587 回答