问题描述
我们刚刚在'lib'中创建了一个新文件,该文件引起了一系列涉及加载错误的麻烦.
We have just created a new file in 'lib' that has spawned a series of headaches involving load errors.
/lib/response_set.rb:
/lib/response_set.rb:
module MyCompany
class ResponseSet < Array
...
end
end
/spec/lib/response_set_spec.rb
/spec/lib/response_set_spec.rb
require 'spec_helper'
describe MyCompany::ResponseSet do
describe "..." do
...
end
end
在Rspec中运行此规范会在出现第一个描述"时给我们以下错误:
Running this spec in Rspec gives us the following error when it gets to the first 'describe':
/Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:492:in `load_missing_constant': Expected /Users/my_stuff/projects/my_project/lib/response_set.rb to define ResponseSet (LoadError)
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:183:in `block in const_missing'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `each'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `const_missing'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/backward_compatibility.rb:20:in `const_missing'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-expectations-2.5.0/lib/rspec/expectations/backward_compatibility.rb:6:in `const_missing'
from /Users/my_stuff/projects/my_project/spec/lib/response_set_spec.rb:4:in `<top (required)>'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `load'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `block in load_spec_files'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `map'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `load_spec_files'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/command_line.rb:18:in `run'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/runner.rb:55:in `run_in_process'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/runner.rb:46:in `run'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/runner.rb:10:in `block in autorun'
但是!长期以来,我们一直在使用许多其他具有相同结构的文件.例如,这是自创建以来一直运行良好的另一种:
HOWEVER! We have been using many other files for a long long time that have identical structure. For example, here's another one that has been working fine since it was created:
/lib/smart_set.rb
/lib/smart_set.rb
module MyCompany
class SmartSet < Array
...
end
end
和/spec/lib/smart_set_spec.rb
And /spec/lib/smart_set_spec.rb
require 'spec_helper'
describe MyCompany::SmartSet do
describe "..." do
...
end
end
此文件具有相同的结构,但完全没有问题.
This file has the identical structure but causes no problems at all.
ResponseSet(问题类)显然有正在加载的原因,而没有明显的原因.在rails控制台中,我第一次尝试创建一个,但是会出现错误,但之后可以创建一个:
ResponseSet ( the problem class ) apparently has loading issues for no discernable reason. In the rails console, the first time I try to create one, I get an error, but then I can create one afterwards:
Loading development environment (Rails 3.0.4)
ruby-1.9.2-p136 :001 > rs = MyCompany::ResponseSet.new
LoadError: Expected /Users/my_stuff/projects/my_project/lib/response_set.rb to define ResponseSet
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:492:in `load_missing_constant'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:183:in `block in const_missing'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `each'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `const_missing'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:503:in `load_missing_constant'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:183:in `block in const_missing'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `each'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `const_missing'
from (irb):1
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/railties-3.0.4/lib/rails/commands/console.rb:44:in `start'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/railties-3.0.4/lib/rails/commands/console.rb:8:in `start'
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/railties-3.0.4/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
ruby-1.9.2-p136 :002 > rs = MyCompany::ResponseSet.new
=> []
此外,添加
require 'response_set'
response_set_spec.rb顶部的
允许运行这些测试.但是smart_set_spec.rb不需要这样的东西.
at the top of response_set_spec.rb allows those tests to run. But no such thing is necessary for smart_set_spec.rb.
application.rb中存在以下内容:
The following is in place in application.rb:
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
现在,我了解Rails对于文件结构应如何与这些类型的事物的名称空间结构保持某种意见,并且我们为此已对模块和文件进行了重组.它似乎已经解决了该问题(尽管在运行完整的测试套件时有一段时间我们看到了一些其他奇怪的加载错误-这些已经神秘地消失了).但是,这里的每个人都感到困惑,并且对Rails如此的前后不一而感到有些烦恼,我们想知道为什么.如您所见,就命名空间和文件结构而言,有两个相同的文件,它们的处理方式完全不同.实际上,在"lib"的顶层,我们还有大约十二个其他文件,它们具有相似的命名空间,这些文件从未引起任何问题.谁能解释这到底是怎么回事?
Now, I understand that Rails has some sort of opinion on how file structure should match namespace structure for these types of things, and we have restructured our modules and files towards this end. It SEEMS to have fixed the issue (although we were seeing some other weird load errors for a while when we ran the full test suite - these have mysteriously gone away). Nonetheless everyone here is baffled and not a little annoyed that Rails is being so inconsistent and we would like to know why. As you can see there are two files that are identical as far as namespacing and file structure are concerned, being treated completely differently. In fact we have about a dozen other files in the top level of 'lib' with similar namespacing that have never caused any problems. Can anyone explain what the heck is going on here?
推荐答案
我们有一个类似的问题,经过挖掘后,原来是由Rails 3.x和autoload_paths
的更改引起的.
We had a similar issue which, after digging, turned out to be caused by the changes in Rails 3.x and autoload_paths
.
我们的案例仅在测试(RAILS_ENV=test
)中出现. Rails加载控制器时,它争先恐后地寻找每个控制器的匹配模型(由于在初始化器中设置了ActionController :: Base.wrap_parameters).最终,它归结为上述方法(load_missing_constant).由于我们的autoload_paths同时包含lib和lib/**,因此Rails从lib下所有子目录中提取了所有文件.不幸的是,当从子目录加载时,它似乎忽略了隐含的名称空间.它期望foo/base.rb定义Base
与Foo::Base
.这似乎是核心缺陷:load_missing_constant
调用search_for_file
会返回名称匹配的任何文件(例如,在我的示例中,与base.rb匹配时将返回foo/base.rb).
Our case appeared only in test (RAILS_ENV=test
). When Rails was loading the controllers, it scrambled about looking for each controller's matching model (due to a ActionController::Base.wrap_parameters set in an initializer). Eventually it wound down to the method mentioned above (load_missing_constant). Since our autoload_paths included both lib and lib/**, Rails pulled in all the files from all the subdirectories under lib. Unfortunately, it appears to ignore the implied namespace when loading from subdirectories. It expected foo/base.rb to define Base
vs. Foo::Base
. That seems to be the core flaw: load_missing_constant
invokes search_for_file
which returns any file whose name matches (e.g., in my example, foo/base.rb was returned as it matched base.rb).
很难说这是否是Rails中的错误-因为它违反了Ruby假定的名称空间到目录的映射-或滥用了autoload_paths.
It's hard to say if this is an error in Rails - in that it violates the namespace-to-directory mapping assumed by Ruby - or a misuse of autoload_paths.
我们现在已经通过从autoload_paths
中删除lib/**
并将必要的require语句添加到application.rb中来解决此问题.
We have worked around this for now by removing lib/**
from our autoload_paths
and adding the necessary require statements to application.rb.
这篇关于不一致的"LoadError" "lib"命名空间/自动加载的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!