File.expand_path ("../../ Gemfile", __FILE__) Как это работает?Где файл? - PullRequest
78 голосов
/ 18 декабря 2010

ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)

Я просто пытаюсь получить доступ к файлу .rb из некоторого каталога, и учебник подсказывает мне использовать этот код, но я не вижу, как он находит файл gem.

Ответы [ 2 ]

183 голосов
/ 18 декабря 2010
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__)).

9 голосов
/ 18 декабря 2010

Две ссылки:

  1. Файл :: документация метода метод_расширения
  2. Как __FILE__ работает в Ruby

Я наткнулся на это сегодня:

boot.rb commit в Rails Github

Если вы идете вверх по двум каталогам из boot.rb в дереве каталогов:

/ Railties / Lib / Рельсы / Генераторы / Рельсы / приложение / шаблоны

вы видите Gemfile, что наводит меня на мысль, что File.expand_path("../../Gemfile", __FILE__) ссылается на следующий файл: /path/to/this/file/../../Gemfile

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