Tại sao Ruby 1.9.2 lại loại bỏ. từ LOAD_PATH, và cái gì thay thế?


154

Các thay đổi mới nhất đối với Ruby 1.9.2 không còn làm cho thư mục hiện tại .của bạn LOAD_PATH. Tôi có một số lượng Rakefiles không tầm thường mà cho rằng đó .là một phần của nó LOAD_PATH, vì vậy điều này đã phá vỡ chúng (họ đã báo cáo "không có tệp nào để tải" cho tất cả các câu lệnh yêu cầu dựa trên đường dẫn dự án). Có một lý do cụ thể để làm điều này?

Đối với một sửa chữa, thêm $: << "."mọi nơi hoạt động, nhưng dường như vô cùng hack và tôi không muốn làm điều đó. Cách ưa thích để làm cho Rakefiles 1.9.2+ của tôi tương thích là gì?

Câu trả lời:


141

Nó được coi là rủi ro "bảo mật".

Bạn có thể đi xung quanh nó bằng cách sử dụng các đường dẫn tuyệt đối

File.expand_path(__FILE__) et al

hoặc làm

require './filename' (ironically).

hoặc bằng cách sử dụng

require_relative 'filename'

hoặc thêm thư mục "bao gồm"

ruby -I . ...

hoặc tương tự, sử dụng irb;

$irb -I .

27
Tôi sử dụng lên require_relative. Cảm ơn.
John Women'sella

11
Đây có giống với hầu hết các unix không bao gồm thư mục hiện tại trong đường dẫn để chạy các tệp thực thi không?
Andrew Grimm

5
require './filename'chỉ hoạt động nếu tập lệnh của bạn được thực thi với thư mục làm việc được đặt thành cùng thư mục chứa tập lệnh. Điều này thường không phải là trường hợp trong các dự án đa thư mục.
mxcl

34

Có hai lý do:

  • mạnh mẽ và
  • Bảo vệ

Cả hai đều dựa trên cùng một nguyên tắc cơ bản: nói chung, bạn chỉ đơn giản là không thể biết thư mục hiện tại là gì, khi mã của bạn được chạy. Điều đó có nghĩa là, khi bạn yêu cầu một tệp và phụ thuộc vào nó trong thư mục hiện tại, bạn không có cách nào kiểm soát liệu tệp đó có ở đó hay không, hoặc đó có phải là tệp mà bạn thực sự mong đợi ở đó không.


5
Tôi không nghĩ rằng việc ép buộc hai tệp ở cùng một vị trí so với nhau nhất thiết phải là một yêu cầu tồi. Nếu đó là sự thật, thì chúng tôi sẽ không sử dụng cho các thư mục.
John Women'sella

4
@ John Women'sella: điều này có liên quan gì đến việc đặt các tệp trong các đường dẫn liên quan đến nhau? Câu hỏi là về việc đặt chúng liên quan đến ., tức là thư mục làm việc hiện tại. Nếu người dùng cdvào một thư mục khác, thư mục làm việc hiện tại sẽ thay đổi và bây giờ bạn require hoàn toàn khác các tệp tùy thuộc vào thư mục nào mà người dùng tình cờ ở trong khi anh ta gọi tập lệnh của bạn. Tôi không nghĩ đó là một ý tưởng tốt.
Jörg W Mittag

Vì vậy, để duy trì một giao diện phong nha, bạn nên làm điều này? $: << File.dirname(__FILE__)
Joshua Cheek

4
@Joshua Cheek: Cá nhân tôi không thích điều đó. (Nhưng làm ơn đừng nhìn vào mã cũ của tôi, bởi vì nó bị vấy bẩn bởi những thứ đó :-)). Tôi chỉ đơn giản là giả vờ rằng libthư mục nằm trên $LOAD_PATHvà sau đó requiretất cả các tệp liên quan đến lib. Nói cách khác: Tôi để nó cho quản trị viên tìm ra cách thiết lập $LOAD_PATHchính xác. Nếu bạn sử dụng RubyGems, điều đó không quan trọng, vì RubyGems sẽ tự động làm điều đó cho bạn và nếu bạn sử dụng các gói Debian, thì đó là công việc của người bảo trì gói. Tất cả trong tất cả, nó dường như làm việc khá độc đáo.
Jörg W Mittag

8
@Joshua Cheek: Ngoài ra, như là một loại đối trọng để loại bỏ .khỏi $LOAD_PATH, Ruby 1.9.2 giới thiệu require_relativemà ... bất ngờ ... requiresa tập tin liên quan đến vị trí của tập tin hiện đang thực thi (tức là liên quan đến File.dirname(__FILE__)).
Jörg W Mittag

16

Như các câu trả lời khác chỉ ra, đó là một rủi ro bảo mật vì .trong đường dẫn tải của bạn đề cập đến thư mục làm việc hiện tại Dir.pwd, không phải thư mục của tệp hiện tại đang được tải. Vì vậy, bất cứ ai đang thực thi kịch bản của bạn có thể thay đổi điều này chỉ bằng cách cdchuyển sang thư mục khác. Không tốt!

Tôi đã sử dụng các đường dẫn đầy đủ được xây dựng từ __FILE__thay thế.

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

Không giống như require_relative, điều này tương thích ngược với Ruby 1.8.7.


4
Ngoài ra còn có biến thể này (mà cá nhân tôi thấy dễ đọc hơn): require Pathname.new(__FILE__).dirname + 'filename'
Tyler Rick

8

Sử dụng require_relative 'file_to_require'

Ném mã này vào mã của bạn để thực hiện công việc có yêu cầu trong 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

Tôi thấy đây là một sự thay đổi đáng kinh ngạc cho đến khi tôi nhận ra một vài điều.

Bạn có thể đặt RUBYLIB trong .profile (Unix) của mình và tiếp tục cuộc sống như trước đây:

export RUBYLIB="."

Nhưng như đã đề cập ở trên, từ lâu đã được coi là không an toàn để làm như vậy.

Đối với phần lớn các trường hợp, bạn có thể tránh các vấn đề bằng cách gọi các tập lệnh Ruby của bạn với một '.' ví dụ ./scripts/server.


3

Như Jorg W Mittag đã chỉ ra, tôi nghĩ những gì bạn muốn sử dụng là require_relativevì vậy tệp bạn yêu cầu có liên quan đến tệp nguồn của requirekhai báo chứ không phải là thư mục làm việc hiện tại.

Sự phụ thuộc của bạn nên liên quan đến tập tin xây dựng cào của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.