Чому Ruby 1.9.2 видаляє "." від LOAD_PATH, а яка альтернатива?


154

Останні набори змін у Ruby 1.9.2 більше не роблять поточний каталог .частиною вашого LOAD_PATH. У мене є нетривіальна кількість Rakefiles, які припускають, що вони .є частиною LOAD_PATH, тому це порушило їх (вони повідомили, що "немає такого файлу для завантаження" для всіх потрібних операторів, які базуються на шляху проекту). Чи було якесь виправдання для цього?

Що стосується виправлення, додавання $: << "."скрізь працює, але здається неймовірно хитким, і я не хочу цього робити. Який найкращий спосіб зробити сумісність Rakefiles 1.9.2+?

Відповіді:


141

Це було визнано ризиком "безпеки".

Ви можете її обійти, використовуючи абсолютні шляхи

File.expand_path(__FILE__) et al

або робити

require './filename' (ironically).

або за допомогою

require_relative 'filename'

або додавання каталогу "включити"

ruby -I . ...

або те саме, використовуючи irb;

$irb -I .

27
Я завершив використання require_relative. Дякую.
Джон Фемінелла

11
Це схоже на більшість unixes, не включаючи поточний каталог у шлях для запуску виконуваних файлів?
Ендрю Грімм

5
require './filename'працює лише в тому випадку, якщо ваш скрипт виконаний із робочим каталогом, встановленим у тому самому каталозі, у якому знаходиться скрипт. Це часто не трапляється у проектах із кількома довідниками.
mxcl

34

Є дві причини:

  • стійкість і
  • безпека

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


5
Я не думаю, що примусовий прийом того, щоб два файли знаходилися в одному місці один щодо одного, обов'язково є поганою вимогою. Якби це було правдою, тоді ми б не мали користі для каталогів.
Джон Фемінелла

4
@John Feminella: що це стосується розміщення файлів у шляхах відносно один одного? Питання полягає в їх розміщенні стосовно .поточного робочого каталогу. Якщо користувач cdпотрапляє в інший каталог, поточний робочий каталог змінюється, і ви тепер require зовсім інші файли залежно від того, в якому каталозі трапився користувач, коли він зателефонував до вашого сценарію. Я не думаю, що це гарна ідея.
Йорг W Міттаг

Отже, щоб підтримувати гідний інтерфейс, вам слід це зробити? $: << File.dirname(__FILE__)
Джошуа Щока

4
@ Джошуа Щок: Особисто мені це не подобається. (Але, будь ласка, не дивіться на мій старший код, тому що він завалений такими матеріалами :-)). Я просто роблю вигляд, що libкаталог знаходиться на, $LOAD_PATHа потім requireусі файли відносно lib. Іншими словами: я залишаю це адміністратору, щоб зрозуміти, як правильно налаштувати $LOAD_PATH. Якщо ви використовуєте RubyGems, це тривіально, тому що RubyGems автоматично робить це за вас, а якщо ви використовуєте пакети Debian, то це робота супроводу пакета. Загалом, здається, це виходить досить непогано.
Йорг W Міттаг

8
@Joshua Щоки: Крім того , в якості свого роду-противагою для видалення .з $LOAD_PATH, Ruby 1.9.2 вводить require_relativeякий ... сюрприз ... requireса файл щодо місця розташування діючого виконуваного файлу (тобто щодо File.dirname(__FILE__)).
Йорг W Міттаг

16

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

Я використовую цілі шляхи, побудовані з __FILE__альтернативи.

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

На відміну від require_relativeцього, це сумісність із Ruby 1.8.7.


4
Є також такий варіант (який я особисто вважаю більш читаним): require Pathname.new(__FILE__).dirname + 'filename'
Тайлер Рік

8

Використовуйте require_relative 'file_to_require'

Введіть це у свій код, щоб виконати вимогу відносної роботи в 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


3

Я вважав це заплутаною зміною, поки не зрозумів пару речей.

Ви можете встановити RUBYLIB у своєму .profile (Unix) та продовжувати життя, як це було раніше:

export RUBYLIB="."

Але, як згадувалося вище, це давно вважається небезпечним.

У переважній більшості випадків ви можете уникнути проблем, просто зателефонувавши своїм сценаріям Ruby заздалегідь "." наприклад ./scripts/server.


3

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

Ваші залежності повинні відповідати вашому файлу збирання граблів.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.