【发布时间】:2011-12-24 20:24:55
【问题描述】:
今天我遇到了一个奇怪的问题: 在模块上出现“缺少方法”错误,但该方法在那里并且需要定义该模块的文件。经过一番搜索,我发现了一个循环依赖项,其中 2 个文件相互需要,现在我假设 ruby 默默地中止循环需要。
编辑开始:示例
文件'a.rb':
require './b.rb'
module A
def self.do_something
puts 'doing..'
end
end
文件'b.rb':
require './a.rb'
module B
def self.calling
::A.do_something
end
end
B.calling
执行 b.rb 会得到b.rb:5:in 'calling': uninitialized constant A (NameError)。这两个文件都必须存在要求,因为它们旨在从命令行自行运行(我省略了该代码以使其简短)。
所以 B.calling 必须在那里。一种可能的解决方案是将需求包装在 if __FILE__ == $0 中,但这似乎不是正确的方法。
编辑结束
为了避免这些难以发现的错误(顺便说一句,如果 require 抛出异常不是更好吗?),是否有一些关于如何构建项目以及在哪里需要什么的指南/规则?例如,如果我有
module MainModule
module SubModule
module SubSubModule
end
end
end
我应该在哪里需要子模块?全部在 main 中,还是只有在 main 中的 sub 和 sub 中的 subsub?
任何帮助都会非常好。
总结
forforfs answer 和 cmets 中讨论了为什么会发生这种情况。
到目前为止,最佳实践(正如lain指出或暗示的那样)似乎如下(如果我错了,请纠正我):
- 将顶层命名空间中的每个模块或类放入以模块/类命名的文件中。在我的示例中,这将是 1 个名为“main_module.rb”的文件。 如果有子模块或子类,则创建一个以模块/类命名的目录(在我的示例中为目录'main_module',并将子类/子模块的文件放在那里(在示例1中名为'sub_module.rb'的文件中) . 对命名空间的每个级别重复此操作。
- 需要逐步说明(在示例中,
MainModule需要SubModule,Submodule需要SubSubModule) - 将“运行”代码与“定义”代码分开。在运行代码中需要一次您的顶级模块/类,因此由于 2. 您现在应该可以使用所有库功能,并且您可以运行任何已定义的方法。
感谢所有回答/评论的人,对我帮助很大!
【问题讨论】:
-
您的示例不会产生 NameError;这个对我有用。看起来您已经将代码过度简化到无法证明您的问题的程度。我对您有关加载顺序的问题的回答将是您的示例代码! :-)
-
这很奇怪,我实际上运行了代码,它确实产生了那个错误消息。我用的是 ruby 1.9.2p180,你用的是什么?
-
好吧,我用 ruby 1.8.7p330 试过了,这也给了我同样的错误。也许你没有正确复制/粘贴。
标签: ruby dependencies dependency-management circular-dependency