2011-08-16 4 views
24

「lib」にロードエラーを含む一連の頭痛を引き起こした新しいファイルを作成しました。「lib」ネームスペース/オートローディングで一貫性のない「LoadError」動作

/lib/response_set.rb:それは最初に到達したときに

module MyCompany 
    class ResponseSet < Array 
    ... 
    end 
end 

/spec/lib/response_set_spec.rb

require 'spec_helper' 

describe MyCompany::ResponseSet do 
    describe "..." do 
    ... 
    end 
end 

はRSpecの中に、この仕様を実行すると、「私たちに次のエラーを与えます記述する:

/Users/my_stuff/.rvm/gems/[email protected]_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/[email protected]_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:183:in `block in const_missing' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `each' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `const_missing' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/rspec-core-2.5.1/lib/rspec/core/backward_compatibility.rb:20:in `const_missing' 
    from /Users/my_stuff/.rvm/gems/[email protected]_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/[email protected]_project/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `load' 
    from /Users/my_stuff/.rvm/gems/[email protected]_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/[email protected]_project/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `map' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `load_spec_files' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/rspec-core-2.5.1/lib/rspec/core/command_line.rb:18:in `run' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/rspec-core-2.5.1/lib/rspec/core/runner.rb:55:in `run_in_process' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/rspec-core-2.5.1/lib/rspec/core/runner.rb:46:in `run' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/rspec-core-2.5.1/lib/rspec/core/runner.rb:10:in `block in autorun' 

どのように!私たちは長い間、同じ構造を持つ他の多くのファイルを使用してきました。

/lib/smart_set.rb

module MyCompany 
    class SmartSet < Array 
    ... 
    end 
end 

とは

require 'spec_helper' 

describe MyCompany::SmartSet do 
    describe "..." do 
    ... 
    end 
end 

これを/spec/lib/smart_set_spec.rb:たとえば、ここではそれが作成されましたので、細かい作業をされてきた別の一つですファイルは同じ構造を持ちますが、まったく問題はありません。

ResponseSet(問題クラス)は、識別可能な理由がないため、明らかに読み込みの問題があります。レールコンソールで、私は1つを作成しようとする最初の時間は、私はエラーを取得し、その後私は後で1を作成することができます。

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/[email protected]_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:492:in `load_missing_constant' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:183:in `block in const_missing' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `each' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `const_missing' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:503:in `load_missing_constant' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:183:in `block in const_missing' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `each' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `const_missing' 
    from (irb):1 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/railties-3.0.4/lib/rails/commands/console.rb:44:in `start' 
    from /Users/my_stuff/.rvm/gems/[email protected]_project/gems/railties-3.0.4/lib/rails/commands/console.rb:8:in `start' 
    from /Users/my_stuff/.rvm/gems/[email protected]_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 
=> [] 

をまた、response_set_specの上部に

require 'response_set' 

を追加します。 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/**/"] 

は今、私はRailsは、ファイル構造は、物事のこれらのタイプの名前空間の構造と一致する必要があります方法についての意見のいくつかの並べ替えを持っていることを理解し、私たちは再構築しています私たちのモジュールとファイルはこの目的のために作られました。それは問題を解決したことを示しています(ただし、完全なテストスイートを実行している間に奇妙な負荷エラーが発生していましたが、これは不思議なことです)。それにもかかわらず、ここの誰もがう​​んざりしていて、Railsが矛盾していて少し悩まされているわけではありません。あなたが見ることができるように、名前空間とファイル構造に関して全く同じ2つのファイルがあり、完全に異なった扱いをしています。実際、私たちには、全く問題を引き起こさなかった類似の名前空間を持つ、「lib」の最上位レベルの約12のファイルがあります。誰でもここで何が起こっているのか説明できますか?

答えて

4

私はレールソースに見て、load_missing_constant方法で

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 ... 

句があります。私は最小限の例を見るのは興味深いだろう

... require_or_loadraise前に呼び出されるように、これはあなたの例では2回目の呼び出しでエラーがないことを理由かもしれないと推測している同一の構造を持つ2つのファイル異なって振る舞う。 あなたの場所では、アプリケーションのコピーを作成し、一貫性のない動作が存在する場合に、不整合な例が最小限になるように、アプリケーションの一部を削除し続けます。

P.S.私はここに同様の質問を提出しました:http://www.ruby-forum.com/topic/2376956

+0

ありがとうございました。それは疑わしいと思われます。 Exceptionを呼び出すことはweather 'require_or_load'に依存しているはずです。しかし、再び私はRailsの勇気である迷路にはあまり慣れていません。 –

+0

@Nick、明らかに、ファイルをロードした後に定数がまだ定義されていないときに例外が発生します。あなたの場合、ファイルは 'MyCompany :: ResponseSet'を定義している間に' ResponseSet'を定義すると思われます(これは私の見た目ですが、私は専門家ではありません)。不一致は最も奇妙なことです。元の問題を単純化していないことを確かめていますか?多分 'MyCompany :: SmartSet'は'/lib/smart_set.rb'だけでなく '/ lib/my_company/smart_set.rb'にありますか?私は[GitHubのバグ報告](https://github.com/rails/rails/issues/2572)に同様の問題について提出しました。 – Alexey

+0

Nope。ファイル構造は同一でした。私たちは思っていたすべての可能な違いをチェックするのに数時間を費やしました。唯一の違いは、各クラス(つまり属性とメソッド)の実際の実装にありますが、ファイルの読み込み方法には影響しません! –

27

掘り出した後、Rails 3.xと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_constantsearch_for_fileを呼び出し、名前が一致するファイルを返します(たとえば、私の例では、foo/base.rbがbase.rbと一致するため返されました)。またはautoload_pathsの誤用 - それはルビーが想定している名前空間へのディレクトリのマッピングに違反することに -

これはRailsの中に誤りがある場合に言うのは難しいです。

autoload_pathsからlib/**を削除し、必要なrequire文をapplication.rbに追加することで、この問題を回避しました。

+2

私は同じことをしなければならなかった。私はあなたが根本的な問題について適切な道を歩んでいると思う...驚いた誰もこれについて不平を言う。 –

+8

Railsが私を悩ませ始めています。 – Zabba

+0

@ザバ:うん、まっすぐなジャケットになっているようだ。 –

4

はあなたautoload_pathsをチェックし、ブレンダンによって正しい方向に指摘されました。私は、同様のエラーを持っていたし、これはapplication.rbで私のために犯人だった:私はサブディレクトリを持つとともに、モデル用のモジュールを使用し始めたら

config.autoload_paths += Dir["#{Rails.root}/app/models/[a-z]*"] 

マイアプリは幸せではなかったです。私は非モジュールディレクトリのautoloadに地雷を変更:

config.autoload_paths += Dir["#{Rails.root}/app/models/aaaaaaaaa"] 
config.autoload_paths += Dir["#{Rails.root}/app/models/bbbbbbbbb"] 
1

私が間違って自動的にロードされている名前空間のクラスと非常に同じ問題に悩まされてきました。これは、(ブレンダンの回答から)それを解決するための手がかりである:

当社autoload_pathsはlibとlibの両方含まれているので/ **、Railsはlibの下にあるすべてのサブディレクトリからすべてのファイルに引っ張ります。残念ながら、サブディレクトリからロードする際に暗黙の名前空間を無視しているようです。それはfoo/base.rbがBase対Foo :: Baseを定義することを期待していました。これはコアの欠陥です:load_missing_constantは、名前が一致するファイルを返すsearch_for_fileを呼び出します(たとえば、私の例では、foo/base.rbがbase.rbと一致するため返されました)。

そして私はapp/components/events/*に、Events::Somethingという名前のすべての私の名前空間のクラスを、移動して次の内容のファイルapp/components/events.rb作成することによって、それを解決してきました:

%w(file1 file2 ...).each do |file| 
    require "events/#{file}" 
end 

を、これは少しマニュアルですが、アプリケーション、コンソール、テストモードの両方で動作します。気づくする価値

0

もう一つのポイントは、あなたがサービスフォルダ内の正しいパスを持っているかどうかということです。

は正しいパスすることによって、私は意味

ENGINE_NAME /アプリ/サービス/ ENGINE_NAME/your_service.rb

私が誤ってサービス内ENGINE_NAMEフォルダを忘れてしまった、そしてこの奇妙な行動を持っています。

関連する問題