Чем загрузка отличается от требуемой в Ruby? - PullRequest
76 голосов
/ 03 июля 2010

Есть ли существенная разница между load и require в приложениях Ruby on Rails?Или они оба имеют одинаковую функциональность?

Ответы [ 3 ]

93 голосов
/ 03 июля 2010

require ищет библиотеку по всем заданным путям поиска, а также добавляет .rb или .so к имени файла, которое вы вводите.Это также гарантирует, что библиотека включена только один раз.Поэтому, если вашему приложению требуются библиотека A и B, а библиотека B запрашивает библиотеку A, она также будет загружена только один раз.

С load вам нужно добавить полное имя библиотеки, и она будет загружаться каждый развызов load - даже если он уже находится в памяти.

39 голосов
/ 04 июля 2010

Другое различие между Kernel#require и Kernel#load заключается в том, что Kernel#load принимает необязательный второй аргумент, который позволяет обернуть загруженный код в анонимный пустой модуль.

К сожалению, это не очень полезно. Во-первых, для load редактируемого кода легко вырваться из модуля, просто получив доступ к глобальному пространству имен, т.е. они все еще могут monkeypatch что-то вроде class ::String; def foo; end end. И, во-вторых, load не возвращает модуль, в который он упаковывает код, так что вам, в основном, нужно вытащить его из ObjectSpace::each_object(Module) вручную.

1 голос
/ 05 декабря 2018

Я запускал приложение 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 (если файл не может быть загружен, возникает 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 принимает путь относительно текущего файла, а не рабочего каталога процесса.

Rubygems

1) Rubygems - менеджер пакетов, предназначенный для простого управления установкой библиотек Ruby, называемых gems.

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 перед командой, например связывает exec rspec, гарантирует, что require загрузит версию гема, указанную в вашем Gemfile.lock.

Рельсы и Bundler

1)В config / boot.rb требуется 'bundler / setup'.Bundler гарантирует, что Ruby сможет найти все гемы в Gemfile (и все их зависимости).require 'bundler / setup' автоматически обнаружит ваш Gemfile и сделает все драгоценные камни в вашем Gemfile доступными для Ruby (с технической точки зрения, эти камни помещаются на пути загрузки).Вы можете думать об этом как о добавлении некоторых дополнительных способностей, требующих 'rubygems'.

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, но требует: ложь не позволила Bundler.require требовать его явно.И тогда проблема была решена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...