Как отличается от нагрузки в Ruby?

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

Ответ 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. И это краткое изложение моих результатов, которые помогли мне найти решение моей конкретной проблемы:

нагрузка

  1. Вы можете передать ему абсолютный путь к рубиновому файлу, и он выполнит код в этом файле.

    нагрузка ( '/Users/MyUser/foo.rb')

  2. Вы можете передать относительный путь для загрузки. Если вы находитесь в том же каталоге, что и файл, он найдет его:

    load ('./foo.rb') foo.rb загружен! => true

Но если вы попытаетесь загрузить файл из другого каталога с помощью load(), он не найдет его с относительным путем на основе текущего рабочего каталога (например./):

> load('./foo.rb')
LoadError: cannot load such file -- foo.rb
  1. Как показано выше, load всегда возвращает true (если файл не может быть загружен, он вызывает LoadError).

  2. Глобальные переменные, классы, константы и методы импортируются, но не локальные.

  3. При вызове нагрузки дважды в одном файле дважды выполняется код в этом файле. Если указанный файл определяет константу, он будет определять эту константу дважды, что создает предупреждение.

  4. $ LOAD_PATH - это массив абсолютных путей. Если вы передаете нагрузку только имя файла, оно будет проходить через $ LOAD_PATH и искать файл в каждом каталоге.

    $ LOAD_PATH.push("/Users/myuser") load ('foo.rb') foo.rb загружен! => true

требовать

  1. Требование вызова в том же файле дважды выполнит его только один раз. Его также достаточно умны, чтобы не загружать один и тот же файл дважды, если вы ссылаетесь на него один раз с относительным путем и один раз с абсолютным путем.

  2. require возвращает true, если файл был выполнен и false, если он не был.

  3. require отслеживает, какие файлы были загружены уже в глобальной переменной $ LOADED_FEATURES.

  4. Вам не нужно включать расширение файла:

    требуют 'foo'

  5. require будет искать foo.rb, но также и файлы динамической библиотеки, такие как foo.so, foo.o или foo.dll. Так вы можете вызвать код C из ruby.

  6. require не проверяет текущий каталог, так как текущий каталог по умолчанию не находится в $ LOAD_PATH.

  7. require_relative принимает путь относительно текущего файла, а не рабочий каталог процесса.

Rubygems

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

  2. Он упаковывает его содержимое в виде zip файла, содержащего кучу рубиновых файлов и/или файлов динамической библиотеки, которые могут быть импортированы вашим кодом вместе с некоторыми метаданными.

  3. Rubygems заменяет используемый по умолчанию метод своей собственной версией. Эта версия будет просматривать ваши установленные камни в дополнение к каталогам в $ LOAD_PATH. Если Rubygems найдет файл в ваших драгоценных камнях, он добавит этот драгоценный камень в ваш $ LOAD_PATH.

  4. Команда установки gem определяет все зависимости драгоценного камня и устанавливает их. Фактически, он устанавливает все зависимости от драгоценных камней, прежде чем устанавливает сам камень.

Bundler

  1. Bundler позволяет вам указать все драгоценности, необходимые вашему проекту, и, при необходимости, какие версии этих драгоценных камней. Затем команда bundle устанавливает все эти драгоценные камни и их зависимости.

  2. Вы указываете, какие камни вам нужны в файле Gemfile.

  3. Команда bundle также устанавливает все драгоценные камни, перечисленные в Gemfile.lock, в определенных версиях.

  4. Помещение пакета exec перед командой, например bundle exec rspec, гарантирует, что require будет загружать версию драгоценного камня, указанную в вашем Gemfile.lock.

Rails и Bundler

  1. В 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'])

  2. Теперь, когда ваш код доступен для Ruby, вам могут понадобиться драгоценные камни, которые вам нужны. Например, вы можете потребовать "синатра". Если у вас много зависимостей, вы можете сказать "потребовать все драгоценные камни в моем Gemfile". Для этого сразу же введите следующий код: "bundler/setup":

    Bundler.require(: по умолчанию)

  3. По умолчанию вызов Bundler.require потребует каждого драгоценного камня в вашем Gemfile. Если строка в Gemfile говорит gem 'foo',: require => false, то он будет уверен, что foo установлен, но он не потребует вызова. Вам нужно будет потребовать ("foo"), если вы хотите использовать драгоценный камень.

Поэтому, учитывая эту широту знаний, я вернулся к вопросу о своем тестировании и понял, что мне нужно явно требовать камень в rails_helper.rb, поскольку Bundler.setup добавил его в $ LOAD_PATH, но требует: false исключает Bundler.require из необходимости его явно, И тогда проблема была решена.