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