Как связаны require, require_dependency и перезагрузка констант в Rails?

Чем отличаются require и require_dependency?
Как require_dependency может автоматически перезагружать классы в процессе разработки, а require не может?

Я копался в коде Rails ActiveSupport::Dependencies и dispatcher.rb. Что я увидел в коде require_dependency, так это то, что он в основном добавляет константы в массив autoloaded_constants. Но он очищается в clear_application внутри диспетчера после каждого запроса.

Может ли кто-нибудь дать четкое объяснение или указать мне на некоторые ресурсы, которые помогут?


person wei    schedule 21.09.2009    source источник
comment
К вашему сведению: перезагрузка класса автоматически обрабатывается в движках (которые представляют собой не что иное, как плагины с приложениями/папками), точно так же, как и в обычных приложениях.   -  person August Lilleaas    schedule 22.09.2009
comment
Спасибо, да, я в курсе. Но тогда это приводит к моему другому вопросу: могу ли я использовать другие плагины внутри своего плагина? Скажем, я хочу использовать плагин act_as_xxx в своем собственном плагине, могу ли я просто поместить act_as_xxx в каталог vendor/plugins моего плагина, а затем добавить путь к $LOAD_PATH? Думаю, мне следует задать этот вопрос в другой ветке, хотя это не имеет отношения к моему первоначальному вопросу.   -  person wei    schedule 22.09.2009


Ответы (2)


require (и его двоюродный брат load) являются основными методами Ruby. require_dependency — это метод, помогающий Rails справиться с проблемой управления зависимостями. Короче говоря, это позволяет Rails перезагружать классы в режиме разработки, так что вам не нужно перезапускать сервер каждый раз, когда вы вносите изменения в код. Фреймворк Rails require_dependency изменит ваш код, чтобы отслеживать и перезагружать его при внесении изменений. Стандартный Ruby require этого не делает. Как разработчику приложения (или плагина/движка) вам не нужно беспокоиться о require_dependency, так как это чисто внутреннее свойство Rails.

Магия процесса загрузки классов Rails находится в модуле ActiveSupport::Dependencies. Этот код расширяет поведение Ruby по умолчанию, позволяя коду внутри вашего приложения Rails автоматически загружать модули (включая классы, которые унаследованы от Module) с использованием соглашений Rails об именах путей и файлов. Это избавляет программиста от необходимости засорять свой код вызовами require, как в обычном приложении Ruby.

Иными словами, это позволяет вам определить class Admin::User внутри файла app/models/admin/user.rb и заставить Rails знать, о чем вы говорите, когда вы вызываете Admin::User.new из другой части приложения, например из контроллера. Без участия ActiveSupport::Dependencies вам пришлось бы вручную require все, что вам нужно.

Если вы переходите со статически типизированного языка, такого как C#, Java и т. д., это может быть сюрпризом: код Rails не загружается до тех пор, пока он не понадобится. Например, класс модели User не определен, а user.rb не загружен до тех пор, пока ПОСЛЕ того, как вы попытаетесь вызвать User.whatever_method_here. Rails не позволяет Ruby жаловаться на отсутствие константы, загружает код для User, а затем позволяет Ruby продолжать работу в обычном режиме.

Хотя я не могу говорить о ваших конкретных потребностях, я был бы очень удивлен, если бы вам действительно понадобилось использовать метод require_dependency из плагина или движка. Если вы следуете соглашениям Rails, вам также не нужно настраивать $LOAD_PATH вручную. Это не "Путь Rails".

В мире Ruby, а также Rails простота и ясность являются ключевыми. Если все, что вы хотите сделать, это написать плагин или движок, и вы уже глубоко погружаетесь во внутренности, вы можете подумать о том, чтобы подойти к своей проблеме с другой стороны. Моя интуиция подсказывает мне, что вы, возможно, пытаетесь сделать что-то излишне сложное. Но опять же, я понятия не имею, что именно вы делаете!! :)

person MDaubs    schedule 07.03.2011

require_dependency полезен в движке, когда вы хотите повторно открыть класс, который не определен в вашем движке (например, в другом движке или приложении Rails) и перезагрузить его. В этом случае работает что-то вроде этого:

# 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
person Kris    schedule 14.11.2013