我不能为我的生活找到任何简单的解释。
我正在开发一个拥有自己的自定义代码的项目,但也有一些扩展/覆盖可用的类虽然包含了宝石。
实现此目的的正确文件夹结构和模块命名模式是什么?
例如,以下是我如何为第三方“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
下被命名空间这令人困惑,因为在this extension of the RSpec HTML formatter之类的东西中,格式化程序在gem的顶级命名空间下使用。那是因为在这种情况下,它创建了一个类似命名但不同的类吗?意图不是覆盖,而是扩展?
答案 0 :(得分: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
现在即使你这样做,还有一个问题就是用这种方式修改类。因为你想要替换你必须首先删除它,否则你将只修改现有的类(如果你指定一个不同的超类,你不能重新打开一个类,rspec运行器已经是Object的子类,你可以不要改变。这就是我的第一个例子中remove_const
调用的内容。
然而,额外的模块实际上并没有在上面的例子中做任何事情,除非让事情变得不那么清楚。在修改现有gem的代码时,只需将所有代码放在rspec子文件夹中(就像你一样),但使用与原始代码完全相同的模块名称。
请记住,以这种方式修改类很容易失败。例如,如果在需要时使用该类,则直到事后才能进行更换,这可能会导致无法预料的问题。这就是为什么你链接的格式化程序示例采用不同的方法,代码不是monkeypatch RSpec,而是在运行时附加它的新类。