Почему Ruby 1.9.2 удаляет "." из LOAD_PATH, а какая альтернатива?

Последние изменения в Ruby 1.9.2 больше не делают текущий каталог . часть вашего LOAD_PATH, У меня есть нетривиальное количество Rake-файлов, которые предполагают, что . является частью LOAD_PATH, так что это сломало их (они сообщили "нет такого файла для загрузки" для всех операторов require, основанных на пути проекта). Было ли какое-то конкретное оправдание для этого?

Что касается исправления, добавив $: << "." везде работает, но кажется невероятно хакерским, и я не хочу этого делать. Какой предпочтительный способ сделать мой Rakefiles 1.9.2+ совместимым?

7 ответов

Решение

Это считалось риском "безопасности".

Вы можете обойти это, используя абсолютные пути

File.expand_path(__FILE__) et al

или делать

require './filename' (ironically).

или с помощью

require_relative 'filename'

или добавив каталог "include"

ruby -I . ...

или то же самое, используя irb;

$irb -I .

Есть две причины:

  • надежность и
  • безопасность

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

Как указывают другие ответы, это угроза безопасности, потому что . в вашем пути загрузки ссылается на текущий рабочий каталог Dir.pwd, а не каталог текущего загружаемого файла. Так что, кто бы ни выполнял ваш скрипт, он может изменить это просто cdв другой каталог. Нехорошо!

Я использовал полные пути, построенные из __FILE__ как альтернатива.

require File.expand_path(File.join(File.dirname(__FILE__), 'filename'))

В отличие от require_relative, это обратно совместимо с Ruby 1.8.7.

Использование require_relative 'file_to_require'

Добавьте это в свой код, чтобы сделать require_relative работу в 1.8.7:

unless Kernel.respond_to?(:require_relative)
  module Kernel
    def require_relative(path)
      require File.join(File.dirname(caller.first), path.to_str)
    end
  end
end

'' Ваш путь уже давно считается плохим явлением в мире Unix (см., например, http://www.faqs.org/faqs/unix-faq/faq/part2/section-13.html). Я предполагаю, что ребята из Ruby были убеждены в том, что не стоит этого делать.

Я нашел, что это было смущающее изменение, пока я не понял пару вещей.

Вы можете установить RUBYLIB в свой.profile (Unix) и продолжить жизнь, как вы делали это раньше:

export RUBYLIB="."

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

В подавляющем большинстве случаев вы можете избежать проблем, просто вызывая свои сценарии Ruby с префиксом "." например./scripts/server.

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

Ваши зависимости должны быть относительно вашего файла сборки рейка.

Другие вопросы по тегам