不一致的“LoadError"“lib"命名空间/自动加载的行为 [英] Inconsistent "LoadError" behavior with 'lib' namespacing/autoloading

查看:15
本文介绍了不一致的“LoadError"“lib"命名空间/自动加载的行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们刚刚在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 定义 BaseFoo::Base.这似乎是核心缺陷: load_missing_constant 调用 search_for_file 它返回任何名称匹配的文件(例如,在我的示例中, foo/base.rb 在匹配 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"命名空间/自动加载的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆