В чем разница между require_relative и require в Ruby?

302

В чем разница между require_relative и requireв Ruby?

agentbanks217
источник
9
До 1.9.2 не было необходимости в require_relative, потому что текущий каталог скрипта находился в $:. См stackoverflow.com/questions/2900370
Nakilon
1
require_relative требует файл, на который конкретно указывается относительно файла, который его вызывает. require требует файл, включенный в $ LOAD_PATH.
Донато
полезная статья о различиях => medium.com/@ellishim/...
Ahmed Хамди

Ответы:

298

Просто посмотрите на документы :

require_relativeдополняет встроенный метод require, позволяя загружать файл относительно файла, содержащего require_relativeинструкцию.

Например, если у вас есть классы модульных тестов в каталоге «test», а данные для них - в каталоге «test / data», то вы можете использовать такую ​​строку в тестовом примере:

require_relative "data/customer_data_1"
Мик
источник
28
Есть ли разница между require './file.rb'и require_relative 'file.rb'?
Сиро Сантилли 法轮功 冠状 病 六四 事件 法轮功
69
@CiroSantilli Да. require_relativeпозволяет вам «загрузить файл, относящийся к файлу, содержащему require_relativeинструкцию ». С require, ./указывает путь относительно вашего текущего рабочего каталога.
Ajedi32
17
Я думаю, что более важно отметить, что require strвсегда будет искать по каталогам в $ LOAD_PATH. Вы должны использовать, require_relativeкогда файл, который вам нужно загрузить, существует где-то относительно файла, который вызывает загрузку. Резерв requireдля «внешних» зависимостей.
rthbound
97

require_relative является удобным подмножеством require

require_relative('path')

равна:

require(File.expand_path('path', File.dirname(__FILE__)))

если __FILE__определено, или оно поднимается LoadErrorиначе.

Это подразумевает, что:

  • require_relative 'a'и require_relative './a'требует относительно текущего файла ( __FILE__).

    Это то, что вы хотите использовать, когда требуется внутри вашей библиотеки, так как вы не хотите, чтобы результат зависел от текущего каталога вызывающей стороны.

  • eval('require_relative("a.rb")')повышает, LoadErrorпотому что __FILE__не определяется внутри eval.

    Вот почему вы не можете использовать require_relativeв тестах RSpec, которые получают evalред.

Следующие операции возможны только с require:

  • require './a.rb'требует относительно текущего каталога

  • require 'a.rb'использует для поиска путь ( $LOAD_PATH). Он не находит файлы относительно текущего каталога или пути.

    Это невозможно, require_relativeпоскольку в документах говорится, что поиск пути происходит только тогда, когда «имя файла не разрешается до абсолютного пути» (т. Е. Начинается с /или ./или ../), что всегда имеет место для File.expand_path.

Следующая операция возможна с обоими, но вы захотите использовать, requireпоскольку она короче и эффективнее:

  • require '/a.rb'и require_relative '/a.rb'оба требуют абсолютного пути.

Чтение источника

Когда документы не ясны, я рекомендую вам взглянуть на источники (переключать источник в документах). В некоторых случаях это помогает понять, что происходит.

требуется:

VALUE rb_f_require(VALUE obj, VALUE fname) {
  return rb_require_safe(fname, rb_safe_level());
}

require_relative:

VALUE rb_f_require_relative(VALUE obj, VALUE fname) {
    VALUE base = rb_current_realfilepath();
    if (NIL_P(base)) {
        rb_loaderror("cannot infer basepath");
    }
    base = rb_file_dirname(base);
    return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
}

Это позволяет нам сделать вывод, что

require_relative('path')

такой же как:

require(File.expand_path('path', File.dirname(__FILE__)))

так как:

rb_file_absolute_path   =~ File.expand_path
rb_file_dirname1        =~ File.dirname
rb_current_realfilepath =~ __FILE__
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
источник
74

Из Ruby API :

require_relative дополняет встроенный метод require, позволяя загрузить файл, относящийся к файлу, содержащему оператор require_relative.

Когда вы используете требование загрузки файла, вы обычно получаете доступ к функциональности, которая была правильно установлена ​​и сделана доступной в вашей системе. require не предлагает хорошего решения для загрузки файлов в коде проекта. Это может быть полезно на этапе разработки, для доступа к тестовым данным или даже для доступа к файлам, которые «заблокированы» внутри проекта и не предназначены для внешнего использования.

Например, если у вас есть классы модульных тестов в каталоге «test», а данные для них - в каталоге «test / data», то вы можете использовать такую ​​строку в тестовом примере:

require_relative "data/customer_data_1" 

Поскольку ни «test», ни «test / data», скорее всего, не находятся в пути к библиотеке Ruby (и по уважительной причине), обычное требование не найдет их. require_relative - хорошее решение для этой конкретной проблемы.

Вы можете включить или опустить расширение (.rb или .so) загружаемого вами файла.

путь должен отвечать to_str.

Вы можете найти документацию по адресу http://extensions.rubyforge.org/rdoc/classes/Kernel.html.

svilenv
источник
50

Резюме

Используйте requireдля установленных драгоценных камней

Использовать require_relativeдля локальных файлов

requireиспользует ваш, $LOAD_PATHчтобы найти файлы.
require_relativeиспользует текущее местоположение файла, используя инструкцию


требовать

Require зависит от того, что вы установили (например gem install [package]) пакет где-то в вашей системе для этой функции.

При использовании requireвы можете использовать ./формат " " для файла в текущем каталоге, например, require "./my_file"но это не является обычной или рекомендуемой практикой, и вы должны использовать require_relativeвместо этого.

require_relative

Это просто означает включение файла «относительно местоположения файла с оператором require_relative». Обычно я рекомендую, чтобы файлы находились «внутри» текущего дерева каталогов, а не «вверх», например , не используйте

require_relative '../../../filename'

(до 3 уровней каталогов) в файловой системе, потому что это имеет тенденцию создавать ненужные и хрупкие зависимости. Однако в некоторых случаях, если вы уже «глубоко» в дереве каталогов, тогда может понадобиться «вверх и вниз» другой ветви дерева каталогов. Проще говоря, не используйте require_relative для файлов за пределами этого репозитория (при условии, что вы используете git, который на данный момент является стандартом де-факто, конец 2018 года).

Обратите внимание, что require_relativeиспользуется текущий каталог файла с оператором require_relative (поэтому не обязательно ваш текущий каталог, из которого вы используете команду). Это сохраняет require_relativeпуть «стабильным», так как он всегда будет относиться к файлу, требующему его одинаковым образом.

Майкл Даррант
источник
27

Лучшие ответы правильные, но глубоко технические. Для новичков в Ruby:

  • require_relative Скорее всего, будет использоваться для ввода кода из другого файла, который вы написали.

например, что если у вас есть данные, ~/my-project/data.rbи вы хотите включить их в ~/my-project/solution.rb? в solution.rbты бы добавилrequire_relative 'data' .

важно отметить, что эти файлы не обязательно должны находиться в одном каталоге. require_relative '../../folder1/folder2/data'также действует.

  • require скорее всего, будет использоваться для ввода кода из библиотеки, написанной кем-то другим.

например, что если вы хотите использовать одну из вспомогательных функций, предоставляемых в active_supportбиблиотеке? вам нужно установить гем с, gem install activesupportа затем в файл require 'active_support'.

require 'active_support/all'
"FooBar".underscore

Сказал иначе

  • require_relative Требуется файл, специально указанный относительно файла, который его вызывает.

  • requireтребуется файл, включенный в $LOAD_PATH.

общий Nighthawk
источник
3
Как я могу проголосовать за этот ответ и довести его до самого верха, чтобы каждый посетитель этой страницы вопросов сразу же получил ясный и понятный ответ, не ломая мозги?
TiredOfProgramming
16

Я только что видел, что в коде RSpec есть некоторые комментарии о том, require_relativeчто O (1) константа и requireO (N) линейно. Так что, вероятно, разница в том, что require_relativeпредпочтительнее, чем require.

Мех
источник
1
Интересный. Я приземлился здесь в поисках информации о сравнении скорости. Я думал, что это require_relativeбыло быстрее, потому что загрузчик не должен пересекать путь загрузки при поиске файла. По сути, require_relativeобеспечивает прямую ссылку.
Клинт Пахл
Раннее обсуждение вопроса о относительной скорости require_relative и RSpec changelog .
Клинт Пахл
1

Я хочу добавить, что при использовании Windows вы можете использовать, require './1.rb'если скрипт запускается локально или с подключенного сетевого диска, но при запуске с UNC- \\servername\sharename\folderпути вам нужно использоватьrequire_relative './1.rb' .

Я не смешиваюсь в обсуждении, которое можно использовать по другим причинам.

Питер
источник
Я хотел знать, как вы загружаете require_relativeфайл. Не могли бы вы
высказать