Nic*_*k M 24 namespaces ruby-on-rails-3
我们刚刚在'lib'中创建了一个新文件,它产生了一系列涉及加载错误的麻烦.
/lib/response_set.rb:
module MyCompany
class ResponseSet < Array
...
end
end
Run Code Online (Sandbox Code Playgroud)
/spec/lib/response_set_spec.rb
require 'spec_helper'
describe MyCompany::ResponseSet do
describe "..." do
...
end
end
Run Code Online (Sandbox Code Playgroud)
在Rspec中运行此规范会在到达第一个'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'
Run Code Online (Sandbox Code Playgroud)
然而!我们长期使用许多其他文件具有相同的结构.例如,这是另一个自创建以来一直工作正常的:
/lib/smart_set.rb
module MyCompany
class SmartSet < Array
...
end
end
Run Code Online (Sandbox Code Playgroud)
和/spec/lib/smart_set_spec.rb
require 'spec_helper'
describe MyCompany::SmartSet do
describe "..." do
...
end
end
Run Code Online (Sandbox Code Playgroud)
此文件具有相同的结构,但完全没有问题.
ResponseSet(问题类)显然有加载问题,没有明显的原因.在rails控制台中,我第一次尝试创建一个,我收到一个错误,但之后我可以创建一个:
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
=> []
Run Code Online (Sandbox Code Playgroud)
另外,添加
require 'response_set'
Run Code Online (Sandbox Code Playgroud)
在response_set_spec.rb的顶部允许运行这些测试.但是smart_set_spec.rb不需要这样的东西.
application.rb中包含以下内容:
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
Run Code Online (Sandbox Code Playgroud)
现在,我理解Rails对文件结构如何匹配这些类型的命名空间结构有一些意见,我们已经为此重组了我们的模块和文件.它看起来已经解决了这个问题(虽然我们在运行完整的测试套件时会看到一些其他奇怪的负载错误 - 这些已经神秘地消失了).尽管如此,这里的每个人都感到困惑,并且对Rails如此不一致并且我们想知道原因并不感到有点恼火.正如您所看到的那样,就命名空间和文件结构而言,有两个文件完全相同,完全不同.事实上,我们在"lib"的顶层有大约十几个其他文件,这些文件具有类似的命名空间,从未引起任何问题.谁能解释这里到底发生了什么?
Bre*_*dan 27
我们有一个类似的问题,经过挖掘,结果是由Rails 3.x和autoload_paths
.的变化引起的.
我们的案例只出现在test(RAILS_ENV=test
)中.当Rails加载控制器时,它忙于寻找每个控制器的匹配模型(由于在初始化器中设置了ActionController :: Base.wrap_parameters).最终它结束了上面提到的方法(load_missing_constant).由于我们的autoload_paths包含lib和lib/**,因此Rails从lib下的所有子目录中提取所有文件.不幸的是,从子目录加载时似乎忽略了隐含的命名空间.它期望foo/base.rb定义Base
vs Foo::Base
..这似乎是核心缺陷:load_missing_constant
所调用search_for_file
返回其名称匹配(例如,在我的例子,被送回富/ base.rb因为它匹配base.rb)的任何文件.
很难说这是否是Rails中的错误 - 因为它违反了Ruby假定的命名空间到目录的映射 - 或者滥用了autoload_paths.
我们现在解决了这个问题,方法是lib/**
从我们中删除autoload_paths
并向application.rb添加必要的require语句.
我查看了 Rails 源代码,有一个
if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load
require_or_load file_path
raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless local_const_defined?(from_mod, const_name)
return from_mod.const_get(const_name)
elsif ...
Run Code Online (Sandbox Code Playgroud)
方法中的子句load_missing_constant
。我可能猜想,正如require_or_load
之前所调用的那样raise
,这可能是您的示例中第二次调用时没有错误的原因......
看到一个最小的例子会很有趣,其中两个具有相同结构的文件的行为不同。在您的位置,我将复制该应用程序,并在出现不一致行为时不断从中删除某些部分,以查看最小的不一致示例。
PS我在这里提交了类似的问题:http ://www.ruby-forum.com/topic/2376956
归档时间: |
|
查看次数: |
6226 次 |
最近记录: |