ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
Я просто пытаюсь получить доступ к файлу .rb из некоторого каталога, и учебник говорит мне использовать этот код, но я не вижу, как он находит файл gem.
ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
Я просто пытаюсь получить доступ к файлу .rb из некоторого каталога, и учебник говорит мне использовать этот код, но я не вижу, как он находит файл gem.
File.expand_path('../../Gemfile', __FILE__)
- несколько уродливая идиома Ruby для получения абсолютного пути к файлу, когда вы знаете путь к текущему файлу. Другой способ написать это:
File.expand_path('../Gemfile', File.dirname(__FILE__))
оба уродливые, но первый вариант короче. Первый вариант, однако, также очень неинтуитивный, пока вы не повесите его. Почему дополнительный ..
? (но второй вариант может дать представление о том, почему это необходимо).
Вот как это работает: File.expand_path
возвращает абсолютный путь первого аргумента относительно второго аргумента (который по умолчанию относится к текущему рабочему каталогу). __FILE__
- это путь к файлу, в котором находится код. Поскольку второй аргумент в этом случае является путем к файлу, а File.expand_path
принимает каталог, мы должны вставить дополнительный ..
в путь для получения путь вправо. Вот как это работает:
File.expand_path
в основном реализуется следующим образом (в следующем коде path
будет иметь значение ../../Gemfile
и relative_to
будет иметь значение /path/to/file.rb
):
def File.expand_path(path, relative_to=Dir.getwd)
# first the two arguments are concatenated, with the second argument first
absolute_path = File.join(relative_to, path)
while absolute_path.include?('..')
# remove the first occurrence of /<something>/..
absolute_path = absolute_path.sub(%r{/[^/]+/\.\.}, '')
end
absolute_path
end
(там немного больше, он расширяет ~
в домашний каталог и т.д. - вероятно, есть и другие проблемы с кодом выше)
Выполняя вызов кода выше absolute_path
, сначала получите значение /path/to/file.rb/../../Gemfile
, затем для каждого раунда в цикле будет удален первый ..
вместе с компонентом пути перед ним. Сначала /file.rb/..
удаляется, затем в следующем раунде /to/..
удаляется, и мы получаем /path/Gemfile
.
Короче говоря, File.expand_path('../../Gemfile', __FILE__)
- это трюк, чтобы получить абсолютный путь к файлу, когда вы знаете путь к текущему файлу. Дополнительный ..
в относительном пути - исключить имя файла в __FILE__
.
Две ссылки:
Я наткнулся на это сегодня:
Если вы запустите два каталога из boot.rb в дереве каталогов:
/railties/lib/rails/generators/rails/app/templates
вы видите Gemfile, что заставляет меня думать, что File.expand_path("../../Gemfile", __FILE__)
ссылается на следующий файл: /path/to/this/file/../../Gemfile