2011-08-16 13 views
24

Właśnie utworzyliśmy nowy plik w bibliotece 'lib', który spowodował szereg problemów związanych z błędami ładowania.Niespójne zachowanie "LoadError" z zachowaniem nazw/ładowaniem "lib"

/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 

Uruchomienie tego specyfikację w rspec daje nam następujący komunikat o błędzie, gdy dostaje się do pierwszej " opis ":

/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' 

JEDNAKŻE! Od dłuższego czasu używamy wielu innych plików o identycznej strukturze. Na przykład, oto jeszcze jeden, który pracuje w porządku, ponieważ został stworzony:

/lib/smart_set.rb

module MyCompany 
    class SmartSet < Array 
    ... 
    end 
end 

I /spec/lib/smart_set_spec.rb

require 'spec_helper' 

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

ten plik ma identyczną strukturę, ale nie powoduje żadnych problemów.

ResponseSet (klasa problemu) najwyraźniej ma problemy z ładowaniem bez widocznego powodu. W konsoli szyn, po raz pierwszy staram się stworzyć jeden, pojawia się błąd, ale potem można utworzyć później:

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 
=> [] 

również dodanie

require 'response_set' 

na szczycie response_set_spec. rb pozwala na uruchomienie tych testów. Ale nie ma czegoś takiego dla smart_set_spec.rb.

Poniżej znajduje się na miejscu w environment.rb:

config.autoload_paths += %W(#{config.root}/lib) 
config.autoload_paths += Dir["#{config.root}/lib/**/"] 
config.autoload_paths += Dir["#{config.root}/app/models/**/"] 

Teraz rozumiem, że Rails ma jakąś opinię na temat struktury pliku należy dopasować strukturę nazw dla tego typu rzeczy, a my zrestrukturyzowane nasze moduły i pliki w tym celu. SEEMS naprawił problem (chociaż przez jakiś czas widzieliśmy inne dziwne błędy ładowania, gdy uruchomiliśmy pełny zestaw testów - te w tajemniczy sposób zniknęły). Mimo to wszyscy tutaj są zdumieni i nie denerwują się, że Rails jest tak niekonsekwentny i chcielibyśmy wiedzieć dlaczego. Jak widać, istnieją dwa pliki, które są identyczne pod względem przestrzeni nazw i struktury plików, traktowane są zupełnie inaczej. W rzeczywistości mamy około tuzina innych plików na najwyższym poziomie "lib" o podobnym ustawieniu przestrzeni nazw, które nigdy nie powodowały żadnych problemów. Czy ktoś może wyjaśnić, co tu się dzieje?

Odpowiedz

4

zajrzałem do źródła szyn i jest

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

klauzula load_missing_constant metody. Mogę zgadnąć, że jako require_or_load jest wywoływana przed raise, może to być powodem, że na drugim wywołaniu w twoim przykładzie nie ma błędu ...

Byłoby interesujące zobaczyć minimalny przykład, w którym dwa pliki o identycznej strukturze zachowuj się inaczej. Na twoim miejscu utworzę kopię aplikacji i będę usuwał z niej części, podczas gdy niespójne zachowanie jest obecne, aby zobaczyć minimalny niespójny przykład.

P.S. Złożyłem podobne pytanie tutaj: http://www.ruby-forum.com/topic/2376956

+0

Dziękuję Alexey. To wygląda podejrzanie. Wydaje mi się, że podniesienie wyjątku powinno zależeć od pogody "require_or_load". Ale znowu nie jestem zaznajomiony z labiryntem, którym są Railsowe jelita. –

+0

@Nick, najwyraźniej wyjątek jest wywoływany, gdy po załadowaniu pliku stała nadal nie jest zdefiniowana. W twoim przypadku wygląda na to, że plik ma zdefiniować 'ResponseSet' podczas definiowania' MyCompany :: ResponseSet' (tak to wygląda, ale nie jestem specjalistą). Ta niespójność jest najdziwniejsza. Czy jesteś pewien, że nie upraszczałeś oryginalnego problemu? Może 'MyCompany :: SmartSet' znajduje się w'/lib/my_company/smart_set.rb', a nie tylko '/ lib/smart_set.rb'? Przesłałem [zgłoszenie błędu na GitHub] (https://github.com/rails/rails/issues/2572) o podobnym problemie. – Alexey

+0

Nie. Struktury plików były identyczne. Spędziliśmy kilka godzin sprawdzając każdą możliwą różnicę, jaką mogliśmy wymyślić. Jedyne różnice dotyczą rzeczywistej implementacji każdej klasy (tj. Atrybutów i metod), ale żaden z nich nie powinien wpływać na sposób wczytywania plików! –

27

Mieliśmy podobny problem, który po wykopaniu okazał się spowodowany zmianami w Railsach 3.x i autoload_paths.

Nasz przypadek pojawił się tylko w teście (RAILS_ENV=test). Kiedy Railsy ładowały kontrolery, szukały dopasowanego modelu każdego kontrolera (z powodu ustawienia ActionController :: Base.wrap_parameters w inicjatorze). Ostatecznie został zwinięty do metody wspomnianej powyżej (load_missing_constant). Ponieważ nasze ścieżki autoload_ zawierały zarówno lib, jak i lib/**, Railsy pobierały wszystkie pliki ze wszystkich podkatalogów pod biblioteką lib. Niestety, wydaje się zignorować domniemane przestrzenie nazw podczas ładowania z podkatalogów. Oczekiwano, że foo/base.rb zdefiniuje Base vs. Foo::Base. Wydaje się, że jest to główna luka: load_missing_constant wywołuje search_for_file, która zwraca dowolny plik, którego nazwa jest zgodna (np. W moim przykładzie, foo/base.rb zostało zwrócone zgodnie z base.rb).

Trudno powiedzieć, czy jest to błąd w Railsach - w tym, że narusza mapowanie przestrzeni nazw do katalogu założone przez Ruby - lub niewłaściwe użycie ścieżek autoloadowania.

Pracowaliśmy nad tym na teraz usuwając lib/** z naszego autoload_paths i dodając niezbędne instrukcje wymagające do application.rb.

+2

Musiałem zrobić to samo. Myślę, że jesteś na właściwej drodze, jeśli chodzi o problem z rootem ... Zaskoczony, nikt nie narzeka na to. –

+8

Szyny zaczyna mnie denerwować. – Zabba

+0

@Zabba: Tak, zamienia się w prostą kurtkę. –

4

Został wskazany we właściwym kierunku przez Brendana, sprawdź ścieżki autoload_. Miałem podobny błąd i to było dla mnie winowajcą w environment.rb:

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

Moja aplikacja nie była szczęśliwa gdy zacząłem używać modułów dla modeli wraz z konieczności podkatalogów. Zmieniłem kopalni autoload tylko katalogi non-module:

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

jakie ponieśli z tego samego problemu z przestrzeni nazw Klasy są ładowane automatycznie niepoprawnie. To jest klucz do rozwiązania go (z odpowiedzią Brendana):

Ponieważ nasze autoload_paths zawarte zarówno lib i lib/**, Szyny wyciągnął wszystkie pliki ze wszystkich podkatalogów pod lib. Niestety, wydaje się zignorować domniemane przestrzenie nazw podczas ładowania z podkatalogów. Oczekiwano, że foo/base.rb zdefiniuje Base vs. Foo :: Base. Wydaje się, że jest to główna luka: load_missing_constant wywołuje search_for_file, który zwraca dowolny plik, którego nazwa jest zgodna (np. W moim przykładzie, foo/base.rb zostało zwrócone zgodnie z base.rb).

A ja rozwiązałem przesuwając wszystkie moje zajęcia przestrzeni nazw, nazwanych Events::Something, w app/components/events/* i tworzenia pliku app/components/events.rb o następującej treści:

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

I choć jest to mało obsługi bit, działa zarówno w trybie aplikacji, konsoli i testowania.

0

Innym punktem wartym zauważenia jest to, czy masz poprawną ścieżkę w folderze usług.

Dla właściwej ścieżce, to znaczy

ENGINE_NAME/app/usług/ENGINE_NAME/your_service.rb

Mam przypadkowo zapomniał ENGINE_NAME folderu wewnątrz służb i got to dziwne zachowanie.

Powiązane problemy