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__
.
В Ruby 2.0 есть функция Kernel
с именем __dir__
, которая реализована как File.dirname(File.realpath(__FILE__))
.