Sự khác biệt giữa allow_relative và request trong Ruby là gì?


302

Sự khác biệt giữa require_relativerequiretrong Ruby là gì?


9
Trước 1.9.2, không cần request_relative, vì thư mục hiện tại của tập lệnh đã được đặt $:. Xem stackoverflow.com/questions/2900370
Nakilon

1
Yêu cầu_relative yêu cầu một tệp được chỉ định cụ thể liên quan đến tệp gọi nó. yêu cầu yêu cầu một tệp có trong $ LOAD_PATH.
Donato

bài viết hữu ích về sự khác biệt => Medium.com/@ellishim/ từ
ahmed

Câu trả lời:


298

Chỉ cần nhìn vào các tài liệu :

require_relativebổ sung cho phương thức dựng sẵn requirebằng cách cho phép bạn tải một tệp có liên quan đến tệp chứa require_relativecâu lệnh.

Ví dụ: nếu bạn có các lớp kiểm tra đơn vị trong thư mục "kiểm tra" và dữ liệu cho chúng trong thư mục "kiểm tra / dữ liệu" kiểm tra, thì bạn có thể sử dụng một dòng như thế này trong trường hợp kiểm tra:

require_relative "data/customer_data_1"

28
Có sự khác biệt giữa require './file.rb'require_relative 'file.rb'?
Ciro Santilli 郝海东 冠状 病 事件

69
@CiroSantilli Vâng. require_relativecho phép bạn "tải một tệp có liên quan đến tệp chứa require_relativecâu lệnh ". Với require, ./chỉ ra một đường dẫn có liên quan đến thư mục làm việc hiện tại của bạn.
Ajedi32

16
Tôi nghĩ điều quan trọng hơn cần lưu ý là require strsẽ luôn tìm kiếm thông qua các thư mục trong $ LOAD_PATH. Bạn nên sử dụng require_relativekhi tệp bạn cần tải tồn tại ở đâu đó so với tệp yêu cầu tải. Dự trữ requirecho các phụ thuộc "bên ngoài".
rthbound

97

require_relative là một tập hợp con thuận tiện của require

require_relative('path')

bằng:

require(File.expand_path('path', File.dirname(__FILE__)))

nếu __FILE__được định nghĩa, hoặc nó tăng LoadErrorkhác.

Điều này ngụ ý rằng:

  • require_relative 'a'require_relative './a'yêu cầu liên quan đến tập tin hiện tại ( __FILE__).

    Đây là những gì bạn muốn sử dụng khi yêu cầu trong thư viện của mình, vì bạn không muốn kết quả phụ thuộc vào thư mục hiện tại của người gọi.

  • eval('require_relative("a.rb")')tăng LoadError__FILE__không được xác định bên trong eval.

    Đây là lý do tại sao bạn không thể sử dụng require_relativetrong các thử nghiệm RSpec, có được evaled.

Các hoạt động sau đây chỉ có thể với require:

  • require './a.rb'yêu cầu liên quan đến thư mục hiện tại

  • require 'a.rb'sử dụng đường dẫn tìm kiếm ( $LOAD_PATH) để yêu cầu. Nó không tìm thấy các tập tin liên quan đến thư mục hoặc đường dẫn hiện tại.

    Điều này là không thể require_relativebởi vì các tài liệu nói rằng tìm kiếm đường dẫn chỉ xảy ra khi "tên tệp không phân giải thành một đường dẫn tuyệt đối" (nghĩa là bắt đầu bằng /hoặc ./hoặc ../), luôn luôn là trường hợp File.expand_path.

Hoạt động sau đây có thể với cả hai, nhưng bạn sẽ muốn sử dụng requirevì nó ngắn hơn và hiệu quả hơn:

  • require '/a.rb'require_relative '/a.rb'cả hai đều yêu cầu con đường tuyệt đối.

Đọc nguồn

Khi tài liệu không rõ ràng, tôi khuyên bạn nên xem các nguồn (chuyển nguồn trong tài liệu). Trong một số trường hợp, nó giúp hiểu những gì đang xảy ra.

yêu cầu:

VALUE rb_f_require(VALUE obj, VALUE fname) {
  return rb_require_safe(fname, rb_safe_level());
}

Yêu cầu: có liên quan:

VALUE rb_f_require_relative(VALUE obj, VALUE fname) {
    VALUE base = rb_current_realfilepath();
    if (NIL_P(base)) {
        rb_loaderror("cannot infer basepath");
    }
    base = rb_file_dirname(base);
    return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
}

Điều này cho phép chúng tôi kết luận rằng

require_relative('path')

giống như:

require(File.expand_path('path', File.dirname(__FILE__)))

bởi vì:

rb_file_absolute_path   =~ File.expand_path
rb_file_dirname1        =~ File.dirname
rb_current_realfilepath =~ __FILE__

74

Từ API Ruby :

allow_relative bổ sung cho phương thức dựng sẵn yêu cầu bằng cách cho phép bạn tải một tệp có liên quan đến tệp có chứa câu lệnh allow_relative.

Khi bạn sử dụng yêu cầu tải tệp, bạn thường truy cập chức năng đã được cài đặt đúng cách và có thể truy cập được trong hệ thống của bạn. yêu cầu không cung cấp một giải pháp tốt để tải các tệp trong mã của dự án. Điều này có thể hữu ích trong giai đoạn phát triển, để truy cập dữ liệu thử nghiệm hoặc thậm chí để truy cập các tệp bị "khóa" bên trong dự án, không dành cho sử dụng bên ngoài.

Ví dụ: nếu bạn có các lớp kiểm tra đơn vị trong thư mục "kiểm tra" và dữ liệu cho chúng trong thư mục "kiểm tra / dữ liệu" kiểm tra, thì bạn có thể sử dụng một dòng như thế này trong trường hợp kiểm tra:

require_relative "data/customer_data_1" 

Vì cả "test" hay "test / data" đều không có khả năng nằm trong đường dẫn thư viện của Ruby (và vì lý do chính đáng), nên một yêu cầu bình thường sẽ không tìm thấy chúng. Yêu cầu là một giải pháp tốt cho vấn đề cụ thể này.

Bạn có thể bao gồm hoặc bỏ qua phần mở rộng (.rb hoặc .so) của tệp bạn đang tải.

đường dẫn phải trả lời to_str.

Bạn có thể tìm thấy tài liệu tại http://extensions.rubyforge.org/rdoc/groupes/Kernel.html


50

Tóm lược

Sử dụng requirecho đá quý được cài đặt

Sử dụng require_relativecho các tệp cục bộ

requiresử dụng của bạn $LOAD_PATHđể tìm các tập tin.
require_relativesử dụng vị trí hiện tại của tệp bằng cách sử dụng câu lệnh


yêu cầu

Yêu cầu phụ thuộc vào bạn đã cài đặt (ví dụ gem install [package]) một gói ở đâu đó trên hệ thống của bạn cho chức năng đó.

Khi sử dụng, requirebạn có thể sử dụng ./định dạng "" cho một tệp trong thư mục hiện tại, ví dụ: require "./my_file"nhưng đó không phải là cách làm phổ biến hoặc được khuyến nghị và bạn nên sử dụng require_relativethay thế.

Yêu cầu

Điều này chỉ có nghĩa là bao gồm tệp 'liên quan đến vị trí của tệp với câu lệnh notify_relative'. Tôi thường khuyên các tệp nên "trong" cây thư mục hiện tại thay vì "lên", ví dụ: không sử dụng

require_relative '../../../filename'

(tăng 3 cấp độ thư mục) trong hệ thống tệp vì điều đó có xu hướng tạo ra các phụ thuộc không cần thiết và dễ vỡ. Tuy nhiên, trong một số trường hợp nếu bạn đã 'sâu' trong cây thư mục thì "lên và xuống" một nhánh cây thư mục khác có thể là cần thiết. Đơn giản hơn có lẽ, không sử dụng allow_relative cho các tệp bên ngoài kho lưu trữ này (giả sử bạn đang sử dụng git, phần lớn là một tiêu chuẩn không chính thức tại thời điểm này, vào cuối năm 2018).

Lưu ý rằng require_relativesử dụng thư mục hiện tại của tệp với câu lệnh allow_relative (vì vậy không nhất thiết là thư mục hiện tại của bạn mà bạn đang sử dụng lệnh từ). Điều này giữ cho require_relativeđường dẫn "ổn định" vì nó luôn luôn liên quan đến tệp yêu cầu nó theo cùng một cách.


27

Các câu trả lời hàng đầu là chính xác, nhưng kỹ thuật sâu sắc. Đối với những người mới hơn với Ruby:

  • require_relative rất có thể sẽ được sử dụng để mang mã từ một tệp khác mà bạn đã viết.

ví dụ, nếu bạn có dữ liệu ~/my-project/data.rbvà bạn muốn đưa dữ liệu đó vào ~/my-project/solution.rbthì sao? trong solution.rbbạn sẽ thêm require_relative 'data'.

điều quan trọng cần lưu ý là các tệp này không cần phải nằm trong cùng một thư mục. require_relative '../../folder1/folder2/data'cũng có giá trị

  • require rất có thể sẽ được sử dụng để mang mã từ thư viện mà người khác đã viết.

ví dụ, nếu bạn muốn sử dụng một trong các hàm trợ giúp được cung cấp trong active_supportthư viện thì sao? bạn sẽ cần cài đặt đá quý với gem install activesupportvà sau đó trong tệp require 'active_support'.

require 'active_support/all'
"FooBar".underscore

Nói khác đi--

  • require_relative yêu cầu một tệp được chỉ định cụ thể liên quan đến tệp gọi nó.

  • requireyêu cầu một tập tin bao gồm trong $LOAD_PATH.


3
Làm thế nào tôi có thể bỏ phiếu cho câu trả lời này và đưa nó lên đầu, vì vậy mọi khách truy cập của trang câu hỏi này sẽ nhận được câu trả lời rõ ràng và dễ hiểu ngay lập tức mà không làm hỏng bộ não của họ?
TiredOfProgramming

16

Tôi chỉ thấy mã của RSpec có một số nhận xét về require_relativehằng số O (1) và requirelà O (N) tuyến tính. Vì vậy, có lẽ sự khác biệt là đó require_relativelà một trong những ưa thích hơn require.


1
Hấp dẫn. Tôi hạ cánh ở đây để tìm kiếm thông tin về một so sánh tốc độ. Suy nghĩ của tôi require_relativelà nhanh hơn vì trình tải không phải đi qua đường tải trong tìm kiếm tệp. Về cơ bản, require_relativecung cấp một liên kết trực tiếp.
Clint Pachl

Tuyên bố sớm về tốc độ request_relative và thay đổi RSpec .
Clint Pachl

1

Tôi muốn thêm rằng khi sử dụng Windows, bạn có thể sử dụng require './1.rb'nếu tập lệnh được chạy cục bộ hoặc từ ổ đĩa mạng được ánh xạ nhưng khi chạy từ \\servername\sharename\folderđường dẫn UNC bạn cần sử dụng require_relative './1.rb'.

Tôi không hòa mình vào cuộc thảo luận sẽ sử dụng cho những lý do khác.


Tôi muốn biết làm thế nào để bạn tải các require_relativetập tin mà bạn có thể xin vui lòng ném một ý tưởng ở đây stackoverflow.com/questions/43487784/...
Emjey
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.