2009-09-21 9 views
54

Czym różnią się require i require_dependency?
Jak można require_dependency automatycznie przeładować klasy w rozwoju, ale require nie może?Jak są wymagane ponowne ładowanie wymagające i stałe powiązane w Railsach?

Przeszukałem kod Rails 'ActiveSupport::Dependencies i dispatcher.rb. To, co widziałem w kodzie require_dependency, polega w zasadzie na dodaniu stałych do tablicy autoloaded_constants. Zostanie jednak wyczyszczony w wewnętrznym kontrolerze clear_application po każdym żądaniu.

Czy ktoś może dać jasne wyjaśnienie lub wskazać mi jakieś zasoby, które pomogą?

+0

FYI: Przeładowanie klasy jest automatycznie obsługiwane w silnikach (które są niczym innym jak wtyczkami z aplikacjami/folderami), tak jak w zwykłych aplikacjach. –

+0

Dzięki, tak, jestem tego świadomy. Ale to prowadzi do mojego drugiego pytania: Czy mogę używać innych wtyczek w mojej wtyczce? Powiedzmy, chcę użyć wtyczki act_as_xxx w mojej własnej wtyczce, czy mogę po prostu wstawić act_as_xxx do katalogu/wtyczek mojego dostawcy wtyczki, a następnie dodać ścieżkę do zmiennej $ LOAD_PATH? Chyba powinienem zapytać o to w innym wątku, nie ma to związku z moim pierwotnym pytaniem. – wei

Odpowiedz

108

require (i jego kuzyn load) to podstawowe metody Rubiego. require_dependency to metoda, która pomaga Railsowi radzić sobie z problemem zarządzania zależnościami. Krótko mówiąc, pozwala Railsom na przeładowanie klas w trybie programowania, dzięki czemu nie trzeba ponownie uruchamiać serwera za każdym razem, gdy wprowadzana jest zmiana kodu. Railsowy framework będzie miał kod require_dependency, dzięki czemu będzie mógł go śledzić i ładować po wprowadzeniu zmian. Standardowy Ruby require tego nie robi. Jako programista aplikacji (lub wtyczki/silnika) nie powinieneś martwić się o require_dependency, ponieważ jest to czysto wewnętrzny Rails.

Magia procesu ładowania klas Rails znajduje się w module ActiveSupport :: Dependencies. Ten kod rozszerza domyślne zachowanie Ruby, aby kod wewnątrz aplikacji Railsowy automatycznie ładował moduły (w tym klasy dziedziczące z modułu), używając konwencji Railsowych i nazewnictwa plików. Eliminuje to potrzebę programistą do zaśmiecania kodu wywoływaniem require, tak jak w zwykłej aplikacji Ruby. Innymi słowy, pozwala to zdefiniować class Admin::User wewnątrz pliku app/models/admin/user.rb i mieć Railsy, ​​o czym mówisz, gdy wywołujesz Admin::User.new z innej części aplikacji, takiej jak kontroler. Bez udziału ActiveSupport :: Dependencies musiałbyś ręcznie wszystko, co potrzebne.

Jeśli pochodzisz ze statycznie napisanego języka, takiego jak C#, Java, itd., Może to być zaskoczeniem: kod Railsowy nie jest ładowany, dopóki nie jest potrzebny. Na przykład klasa modelu User nie jest zdefiniowana i user.rb nie zostanie załadowana do czasu, gdy spróbujesz zadzwonić pod numer User.whatever_method_here. Szyny uniemożliwiają Ruby narzekanie na tę brakującą stałą, ładuje kod dla User, a następnie pozwala na normalne działanie Rubiego.

Chociaż nie mogę mówić w konkretnej potrzebie, byłbym bardzo zaskoczony, gdyby rzeczywiście trzeba było użyć metody require_dependency z wtyczki lub silnika. Jeśli podążasz za konwencjami Railsowymi, nie powinieneś też ręcznie modyfikować wartości $ LOAD_PATH. To nie jest "sposób Rails".

W świecie Ruby i Railsów liczy się prostota i przejrzystość. Jeśli chcesz tylko napisać wtyczkę lub silnik i już nurkujesz w głąb wnętrza, możesz rozważyć podchodzenie do problemu pod innym kątem. Moje jelito mówi mi, że możesz próbować zrobić coś, co jest niepotrzebnie skomplikowane. Ale znowu nie mam pojęcia, co dokładnie robisz! :)

16

jest przydatny w silniku, gdy chce się ponownie otworzyć klasę, która nie jest zdefiniowana w silniku (na przykład w innym silniku lub aplikacji Rails) i została ponownie załadowana.W takim przypadku coś takiego działa:

# app/controllers/my_engine/documents_controller.rb 
require_dependency MyEngine::Engine.root.join('app', 'controllers', 'my_engine', 'documents_controller').to_s 

module MyEngine 
    class DocumentsController 
    def show 
     render :text => 'different' 
    end 
    end 
end