ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
Tôi chỉ đang cố gắng truy cập tệp .rb từ một số thư mục và một hướng dẫn cho tôi biết sử dụng mã này nhưng tôi không hiểu cách nó tìm thấy tệp gem.
Câu trả lời:
File.expand_path('../../Gemfile', __FILE__)
là một thành ngữ Ruby hơi xấu xí để lấy đường dẫn tuyệt đối đến một tệp khi bạn biết đường dẫn liên quan đến tệp hiện tại. Một cách viết khác là:
File.expand_path('../Gemfile', File.dirname(__FILE__))
cả hai đều xấu, nhưng biến thể đầu tiên ngắn hơn. Tuy nhiên, biến thể đầu tiên cũng không trực quan cho đến khi bạn hiểu rõ về nó. Tại sao thêm ..
? (nhưng biến thể thứ hai có thể cung cấp manh mối về lý do tại sao nó lại cần thiết).
Đây là cách hoạt động: File.expand_path
trả về đường dẫn tuyệt đối của đối số đầu tiên, liên quan đến đối số thứ hai (mặc định là thư mục làm việc hiện tại). __FILE__
là đường dẫn đến tệp có mã. Vì đối số thứ hai trong trường hợp này là đường dẫn đến tệp và File.expand_path
giả sử là một thư mục, chúng ta phải thêm một phần bổ sung ..
vào đường dẫn để đường dẫn đúng. Đây là cách nó hoạt động:
File.expand_path
về cơ bản được thực hiện như thế này (trong đoạn mã sau path
sẽ có giá trị là ../../Gemfile
và relative_to
sẽ có giá trị là /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
(có một chút nữa về nó, nó mở rộng ~
đến thư mục chính, v.v. - có lẽ cũng có một số vấn đề khác với đoạn mã ở trên)
Bước qua một lệnh gọi đến mã trên absolute_path
trước tiên sẽ nhận được giá trị /path/to/file.rb/../../Gemfile
, sau đó đối với mỗi vòng trong vòng lặp, phần đầu tiên ..
sẽ bị xóa, cùng với thành phần đường dẫn trước nó. Đầu tiên /file.rb/..
bị loại bỏ, sau đó vào vòng tiếp theo /to/..
bị loại bỏ, và chúng tôi nhận được /path/Gemfile
.
Để làm cho một câu chuyện dài ngắn, File.expand_path('../../Gemfile', __FILE__)
là một mẹo để có được đường dẫn tuyệt đối của một tệp khi bạn biết đường dẫn liên quan đến tệp hiện tại. Phần bổ sung ..
trong đường dẫn tương đối là loại bỏ tên của tệp trong đó __FILE__
.
Trong Ruby 2.0, có một Kernel
hàm được gọi __dir__
là được thực hiện dưới dạng File.dirname(File.realpath(__FILE__))
.
File.expand_path('../Gemfile',__dir__)
File.expand_path assumes a directory
, mặc dù __FILE__
không phải là một danh bạ. Để mọi thứ có ý nghĩa, hãy sử dụng __dir__
nó thực sự là một thư mục.
Hai tài liệu tham khảo:
Tôi tình cờ thấy điều này hôm nay:
boot.rb cam kết trong Rails Github
Nếu bạn đi lên hai thư mục từ boot.rb trong cây thư mục:
/ railties / lib / rails / máy phát điện / đường ray / ứng dụng / mẫu
bạn thấy Gemfile, khiến tôi tin rằng File.expand_path("../../Gemfile", __FILE__)
tham chiếu đến tệp sau:/path/to/this/file/../../Gemfile