Есть ли существенное различие между load
и require
в Ruby On Rails приложений? Или у них обоих одинаковые функции?
ruby-on-rails
ruby
Арпит Вайшнав
источник
источник
require
,load
илиautoload
в Ruby?Ответы:
require
выполняет поиск библиотеки по всем заданным путям поиска, а также добавляет .rb или .so к имени файла, которое вы вводите. Это также гарантирует, что библиотека включается только один раз. Поэтому, если вашему приложению требуются библиотеки A и B и библиотека B, библиотека A тоже A будет загружена только один раз.При этом
load
вам нужно добавить полное имя библиотеки, и она будет загружаться каждый раз при вызове,load
даже если она уже находится в памяти.источник
require
отслеживает то, что уже было загружено через глобальный массив$LOADED_FEATURES
($"
), которыйload
игнорирует.Еще одно различие между
Kernel#require
иKernel#load
заключается в том, что онKernel#load
принимает необязательный второй аргумент, позволяющий обернуть загруженный код в анонимный пустой модуль.К сожалению, это не очень полезно. Во-первых,
load
редактируемому коду легко вырваться из модуля, просто получив доступ к глобальному пространству имен, то есть они все еще могут запрограммировать что-то вродеclass ::String; def foo; end end
. А во-вторых,load
не возвращает модуль, в который заключен код, поэтому вам в основном придется выудить егоObjectSpace::each_object(Module)
вручную.источник
Kernel#load
имел, есть еще один аргументload
редактируемому коду легко выйти из модуля, просто получив доступ к глобальному пространству имен, то есть они все еще могут запрограммировать что-то вродеclass ::String; def foo; end end
. А во-вторых,load
не возвращает модуль, в который заключен код, поэтому вам в основном придется выудить егоObjectSpace::each_object(Module)
вручную.Я запускал приложение Rails, и в Gemfile у меня был специальный гем, который я создал с опцией «require: false». Теперь, когда я загрузил сервер rails или консоль rails, я смог потребовать гем в инициализаторе, и гем был загружен. Однако, когда я провел тест функции спецификации с помощью rspec и capybara, у меня возникла ошибка загрузки. И я был совершенно сбит с толку, почему Gem не был найден в $ LOAD_PATH при запуске теста.
Итак, я рассмотрел все различные способы взаимодействия load, require, rubygems и Bundler. И это краткое изложение моих выводов, которые помогли мне найти решение моей конкретной проблемы:
грузить
1) Вы можете передать ему абсолютный путь к файлу ruby, и он выполнит код в этом файле.
load('/Users/myuser/foo.rb')
2) Вы можете передать относительный путь для загрузки. Если вы находитесь в том же каталоге, что и файл, он найдет его:
> load('./foo.rb') foo.rb loaded! => true
Но если вы попытаетесь загрузить файл из другого каталога с помощью load (), он не найдет его с относительным путем, основанным на текущем рабочем каталоге (например, ./):
> load('./foo.rb') LoadError: cannot load such file -- foo.rb
3) Как показано выше, load всегда возвращает true (если файл не может быть загружен, возникает a
LoadError
).4) Импортируются глобальные переменные, классы, константы и методы, но не локальные переменные.
5) Двойной вызов load для одного и того же файла приведет к двойному выполнению кода в этом файле. Если указанный файл определяет константу, он будет определять эту константу дважды, что вызывает предупреждение.
6) $ LOAD_PATH - массив абсолютных путей. Если вы передадите load только имя файла, он будет перебирать $ LOAD_PATH и искать файл в каждом каталоге.
> $LOAD_PATH.push("/Users/myuser") > load('foo.rb') foo.rb loaded! => true
требовать
1) Вызов require для одного и того же файла дважды выполнит его только один раз. Также достаточно умен, чтобы не загружать один и тот же файл дважды, если вы обращаетесь к нему один раз с относительным путем и один раз с абсолютным путем.
2) require возвращает true, если файл был выполнен, и false, если нет.
3) require отслеживает, какие файлы уже были загружены в глобальную переменную $ LOADED_FEATURES.
4) Вам не нужно указывать расширение файла:
require 'foo'
5) require будет искать foo.rb, а также файлы динамической библиотеки, такие как foo.so, foo.o или foo.dll. Вот как вы можете вызвать код C из ruby.
6) require не проверяет текущий каталог, поскольку текущий каталог по умолчанию не находится в $ LOAD_PATH.
7) require_relative принимает путь относительно текущего файла, а не рабочего каталога процесса.
Рубигемы
1) Rubygems - это менеджер пакетов, предназначенный для простого управления установкой библиотек Ruby, называемых гемами.
2) Он упаковывает свое содержимое в виде zip-файла, содержащего кучу файлов ruby и / или файлов динамической библиотеки, которые могут быть импортированы вашим кодом вместе с некоторыми метаданными.
3) Rubygems заменяет метод require по умолчанию собственной версией. Эта версия будет просматривать ваши установленные гемы в дополнение к каталогам в $ LOAD_PATH. Если Rubygems найдет файл в ваших гемах, он добавит этот гем в ваш $ LOAD_PATH.
4) Команда gem install определяет все зависимости драгоценного камня и устанавливает их. Фактически, он устанавливает все зависимости гема перед установкой самого гема.
Bundler
1) Bundler позволяет вам указать все драгоценные камни, необходимые вашему проекту, и, при необходимости, какие версии этих драгоценных камней. Затем команда bundle устанавливает все эти драгоценные камни и их зависимости.
2) Вы указываете, какие драгоценные камни вам нужны в файле Gemfile.
3) Команда bundle также устанавливает все драгоценные камни, перечисленные в Gemfile.lock, в конкретных перечисленных версиях.
4) Размещение пакета exec перед командой, например, bundle exec rspec, гарантирует, что require загрузит версию гема, указанную в вашем Gemfile.lock.
Рельсы и бандлер
1) В config / boot.rb запускается require 'bundler / setup'. Bundler гарантирует, что Ruby сможет найти все драгоценные камни в Gemfile (и все их зависимости). require 'bundler / setup' автоматически обнаружит ваш Gemfile и сделает все драгоценные камни в вашем Gemfile доступными для Ruby (с технической точки зрения он помещает драгоценные камни "на путь загрузки"). Вы можете думать об этом как о добавлении некоторых дополнительных способностей, требующих «рубиновых камней».
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
2) Теперь, когда ваш код доступен для Ruby, вы можете потребовать драгоценные камни, которые вам нужны. Например, вы можете потребовать «синатру». Если у вас много зависимостей, вы можете сказать «требовать все драгоценные камни в моем Gemfile». Для этого поместите следующий код сразу после require 'bundler / setup':
Bundler.require(:default)
3) По умолчанию для вызова Bundler.require потребуется каждый гем в вашем Gemfile. Если в строке Gemfile написано gem 'foo',: require => false, тогда он будет удостовериться, что foo установлен, но не будет вызывать require. Вам нужно будет вызвать require ('foo'), если вы хотите использовать драгоценный камень.
Итак, учитывая такой объем знаний, я вернулся к проблеме моего теста и понял, что мне нужно явно требовать драгоценный камень в rails_helper.rb, поскольку Bundler.setup добавил его в $ LOAD_PATH, но require: false не позволял Bundler.require явно требовать его . И тогда вопрос был решен.
источник