Mengapa Ruby 1.9.2 menghapus "." dari LOAD_PATH, dan apa alternatifnya?

154

Perubahan terbaru ke Ruby 1.9.2 tidak lagi menjadikan direktori saat ini menjadi .bagian dari Anda LOAD_PATH. Saya memiliki sejumlah non-sepele dari Rakefiles yang menganggap itu .adalah bagian dari LOAD_PATH, jadi ini mematahkan mereka (mereka melaporkan "tidak ada file seperti itu untuk memuat" untuk semua memerlukan pernyataan yang didasarkan dari jalur proyek). Apakah ada pembenaran khusus untuk melakukan ini?

Adapun perbaikan, menambahkan di $: << "."mana-mana berfungsi, tetapi tampaknya sangat aneh dan saya tidak ingin melakukan itu. Apa cara yang disukai untuk membuat Rakefiles 1.9.2+ saya kompatibel?

John Feminella
sumber

Jawaban:

141

Itu dianggap sebagai risiko "keamanan".

Anda dapat mengatasinya dengan menggunakan jalur absolut

File.expand_path(__FILE__) et al

atau melakukan

require './filename' (ironically).

atau dengan menggunakan

require_relative 'filename'

atau menambahkan direktori "include"

ruby -I . ...

atau sama, menggunakan irb;

$irb -I .
rogerdpack
sumber
27
Saya akhirnya menggunakan require_relative. Terima kasih.
John Feminella
11
Apakah ini mirip dengan sebagian besar unix tidak termasuk direktori saat ini di jalur untuk menjalankan executable?
Andrew Grimm
5
require './filename'hanya berfungsi jika skrip Anda dieksekusi dengan direktori kerja diatur ke direktori yang sama dengan skrip tersebut. Ini sering tidak terjadi pada proyek multi-direktori.
mxcl
34

Ada dua alasan:

  • kekokohan dan
  • keamanan

Keduanya didasarkan pada prinsip dasar yang sama: secara umum, Anda tidak bisa tahu apa direktori saat ini, ketika kode Anda dijalankan. Yang berarti bahwa, ketika Anda memerlukan file dan bergantung padanya di direktori saat ini, Anda tidak memiliki cara untuk mengontrol apakah file itu akan ada di sana, atau apakah itu file yang sebenarnya Anda harapkan ada di sana.

Jörg W Mittag
sumber
5
Saya tidak berpikir bahwa menegakkan bahwa dua file berada di lokasi yang sama relatif satu sama lain merupakan persyaratan yang buruk. Jika itu benar, maka kita tidak akan menggunakan direktori.
John Feminella
4
@ John Feminella: apa hubungannya dengan meletakkan file di jalur relatif satu sama lain? Pertanyaannya adalah tentang menempatkan mereka relatif terhadap ., yaitu direktori kerja saat ini. Jika pengguna cdmasuk ke direktori yang berbeda, direktori kerja saat ini berubah, dan Anda sekarang memiliki file yang sama require sekali berbeda, tergantung pada direktori tempat pengguna tersebut berada ketika ia memanggil skrip Anda. Saya pikir itu bukan ide yang bagus.
Jörg W Mittag
Jadi untuk mempertahankan antarmuka yang layak, Anda harus melakukan ini? $: << File.dirname(__FILE__)
Joshua Cheek
4
@ Joshua Cheek: Secara pribadi, saya tidak suka itu. (Tapi tolong jangan melihat kode lama saya, karena penuh dengan hal-hal semacam itu :-)). Saya hanya berpura - pura bahwa libdirektori tersebut ada di $LOAD_PATHdan kemudian requiresemua file relatif terhadap lib. Dengan kata lain: Saya serahkan kepada administrator untuk mencari tahu cara mengatur dengan $LOAD_PATHbenar. Jika Anda menggunakan RubyGems, itu sepele, karena RubyGems secara otomatis melakukannya untuk Anda, dan jika Anda menggunakan paket Debian, maka itu adalah tugas pengelola paket. Semua dalam semua, tampaknya berhasil dengan cukup baik.
Jörg W Mittag
8
@ Joshua Cheek: Juga, sebagai semacam penyeimbang untuk dihapus .dari $LOAD_PATH, Ruby 1.9.2 memperkenalkan require_relative... kejutan ... requiresa file yang relatif terhadap lokasi file yang sedang dijalankan (yaitu relatif terhadap File.dirname(__FILE__)).
Jörg W Mittag
16

Seperti yang dijawab oleh orang lain, ini merupakan risiko keamanan karena .di jalur muat Anda merujuk ke direktori kerja saat ini Dir.pwd, bukan direktori file saat ini sedang dimuat. Jadi siapa pun yang menjalankan skrip Anda dapat mengubah ini hanya dengan masuk cdke direktori lain. Tidak baik!

Saya telah menggunakan jalur lengkap yang dibangun dari __FILE__sebagai alternatif.

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

Tidak seperti require_relativeini, ini kompatibel dengan Ruby 1.8.7.

Jonathan Tran
sumber
4
Ada juga variasi ini (yang menurut saya pribadi lebih mudah dibaca): require Pathname.new(__FILE__).dirname + 'filename'
Tyler Rick
8

Menggunakan require_relative 'file_to_require'

Lemparkan ini ke dalam kode Anda untuk membuat pekerjaan require_relative di 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
Tyler Brock
sumber
3

Saya menemukan ini sebagai perubahan yang membingungkan sampai saya menyadari beberapa hal.

Anda dapat mengatur RUBYLIB di profil Anda (Unix) dan melanjutkan hidup seperti yang Anda lakukan sebelumnya:

export RUBYLIB="."

Tapi seperti yang disebutkan di atas, sudah lama dianggap tidak aman untuk melakukannya.

Untuk sebagian besar kasus, Anda dapat menghindari masalah dengan hanya memanggil skrip Ruby Anda dengan huruf '.' mis ./scripts/server.

Dylan
sumber
3

Seperti yang ditunjukkan Jorg W Mittag, saya pikir apa yang ingin Anda gunakan adalah require_relativeagar file yang Anda perlukan relatif terhadap file sumber requiredeklarasi dan bukan direktori kerja saat ini.

Ketergantungan Anda harus relatif terhadap file rake build Anda.

Martin
sumber