Computer >> Máy Tính >  >> Lập trình >> Ruby

Code Loaders trong Ruby:Hiểu về Zeitwerk

Trình tải mã trong Ruby - Hiểu Zeitwerk

Với Zeitwerk, bạn có thể hợp lý hóa chương trình của mình khi biết rằng các lớp và mô-đun có sẵn ở mọi nơi.

Trình tải mã là gì?

Trình tải mã cho phép các nhà phát triển xác định các lớp classesmodules trên các tệp và thư mục khác nhau và sử dụng chúng trong toàn bộ cơ sở mã mà không yêu cầu chúng một cách rõ ràng. Rails là một ví dụ điển hình về một phần mềm sử dụng bộ nạp mã. Lập trình trong Rails không yêu cầu require rõ ràng lệnh gọi để tải các mô hình trước khi sử dụng chúng trong bộ điều khiển. Trên thực tế, trong Rails 6, mọi thứ trong ứng dụng classes thư mục được tải tự động khi khởi động ứng dụng, với một vài ngoại lệ.

Mặc dù dễ dàng nghĩ rằng việc tải mã là tất cả về việc thực hiện các cuộc gọi đến require , nó không phải là đơn giản. Quá trình tải mã có thể được chia nhỏ thành ba phần như sau.

  • Tải tự động: Điều này có nghĩa là mã được tải nhanh chóng theo yêu cầu. Ví dụ:trong Rails, chạy rails s không tải tất cả các mô hình, bộ điều khiển, v.v. Nhưng, trong lần truy cập đầu tiên của mô hình User , nó chạy cơ chế tải tự động để tìm và sử dụng mô hình. Đây là chế độ tải tự động đang hoạt động. Điều này có một số lợi thế cho môi trường phát triển của chúng tôi, vì chúng tôi có ứng dụng nhanh hơn và rails console thời gian khởi động. Rails.config.autoload_path kiểm soát các đường dẫn được tải tự động.
  • Đang tải háo hức: Điều này có nghĩa là mã được tải vào bộ nhớ khi khởi động ứng dụng và không đợi các hằng số được gọi trước khi yêu cầu nó. Trong Rails, mã được tải sẵn sàng trong quá trình sản xuất. Từ giải thích ở trên, mã tự động tải trong quá trình sản xuất sẽ dẫn đến thời gian phản hồi chậm, vì mỗi hằng số sẽ được yêu cầu nhanh chóng. Rails.config.eager_load_paths kiểm soát các đường dẫn cần tải.
  • Đang tải lại: Trình tải mã liên tục theo dõi các thay đổi đối với tệp trong autoload_path và tải lại các tệp khi nhận thấy bất kỳ thay đổi nào. Trong Rails, điều này có thể khá hữu ích trong quá trình phát triển, vì nó cho phép chúng tôi chạy rails s và đồng thời thực hiện các thay đổi mà không cần khởi động lại máy chủ rails. Quá trình tải lại đang hoạt động.

Chúng ta có thể dễ dàng nhận thấy rằng hầu hết các khái niệm này đã được phát triển và tồn tại trong Rails. Zeitwerk thay đổi điều này! Zeitwerk cho phép chúng tôi đưa tất cả hành động tải mã vào bất kỳ dự án Ruby nào.

Zeitwerk là gì?

Zeitwerk là một trình nạp mã hiệu quả và an toàn cho Ruby và có thể được sử dụng trong bất kỳ dự án Ruby nào, bao gồm các khung công tác Web (Rails, Hanami, Sinatra), các công cụ Cli và đá quý. Với nó, bạn có thể hợp lý hóa chương trình của mình khi biết rằng các lớp và mô-đun có sẵn ở mọi nơi. Theo truyền thống, Rails và một số các đá quý khác có bộ nạp mã tích hợp để kích hoạt chức năng này. Tuy nhiên, Zeitwerk trích xuất các khái niệm này thành một viên đá quý và cho phép các Rubyists áp dụng các khái niệm này vào các dự án của họ.

Cài đặt Zeitwerk

Điều đầu tiên, chúng ta cần cài đặt gem:

gem install zeitwerk

# OR in your Gemfile
gem 'zeitwerk', '~> 2.4.0'

Định cấu hình Zeitwerk

Vì vậy, hãy bắt đầu với những điều cơ bản:

require 'zeitwerk'
loader = Zeitwerk::Loader.new
...
loader.setup

Đoạn mã trên khởi tạo một phiên bản trình tải và gọi setup . Sau cuộc gọi đến setup , bộ nạp đã sẵn sàng để tải mã. Tuy nhiên, trước đó, tất cả các cấu hình cần thiết trên loader nên được bảo hiểm rồi. Trong bài viết này, tôi sẽ trình bày một vài cấu hình trên loader và các quy ước để cấu trúc mã của bạn.

  • Cấu trúc tệp:Để Zeitwerk hoạt động, các tệp và tên thư mục cần phải khớp với các mô-đun và tên lớp mà chúng xác định. Ví dụ,
  lib/my_gem.rb         -> MyGem
  lib/my_gem/foo.rb     -> MyGem::Foo
  lib/my_gem/bar_baz.rb -> MyGem::BarBaz
  lib/my_gem/woo/zoo.rb -> MyGem::Woo::Zoo
  • Không gian tên gốc:Không gian tên gốc là các thư mục chứa Zeitwerk có thể tìm thấy mã của bạn. Khi modules và các lớp classes được tham chiếu, Zeitwerk biết tìm kiếm không gian tên gốc với tên tệp phù hợp. Ví dụ,
  require 'zeitwerk'
  loader = Zeitwerk::Loader.new
  loader.push_dir("app/models")
  loader.push_dir("app/controllers")

  // matches as follows
  app/models/user.rb                        -> User
  app/controllers/admin/users_controller.rb -> Admin::UsersController

Có hai cách chính để xác định không gian tên gốc cho hai trường hợp sử dụng khác nhau. Cách mặc định được hiển thị bên dưới:

  // init.rb
  require 'zeitwerk'
  loader = Zeitwerk::Loader.new
  loader.push_dir("#{__dir__}/bar")
  ...
  loader.setup

  // bar/foo.rb
  class Foo; end

Điều này có nghĩa là lớp Foo có thể được tham chiếu mà không có Bar::Foo rõ ràng , vì thư mục thanh hoạt động như một không gian tên gốc. Cách thứ hai để xác định không gian tên là trình bày rõ ràng không gian tên trong lệnh gọi tới push_dir :

  // init.rb
  require 'zeitwerk'

  module Bar
  end
  loader = Zeitwerk::Loader.new
  loader.push_dir("#{__dir__}/src", namespace: Bar)
  loader.setup

  // src/foo.rb
  class Bar::Foo; end

Có một số điều cần lưu ý trong mã này:

  1. Mô-đun Bar đã được xác định trước khi được sử dụng bởi push_dir . Nếu mô-đun chúng ta muốn sử dụng được xác định bởi bên thứ ba, thì một yêu cầu đơn giản sẽ xác định nó trước khi chúng ta sử dụng nó trong lệnh gọi tới push_dir .
  2. push_dir chỉ định rõ ràng không gian tên Bar .
  3. Tệp src/foo.rb Bar::Foo được xác định , không phải Foo và không cần tạo thư mục, như src/bar/foo.rb .
  • Bộ tải mã độc lập:Theo thiết kế, Zeitwerk cho phép từng dự án hoặc ứng dụng phụ thuộc quản lý cây dự án riêng lẻ của nó. Điều này có nghĩa là cơ chế tải mã của mỗi phụ thuộc được quản lý bởi phụ thuộc đó. Ví dụ:trong Rails 6, Zeitwerk xử lý việc tải mã cho ứng dụng Rails và cho phép từng phụ thuộc đá quý quản lý cây dự án của riêng nó một cách riêng biệt. Đây là một tình trạng lỗi khi có các tệp chồng chéo giữa nhiều trình tải mã.

  • Tự động tải:Với thiết lập ở trên, một lần gọi đến setup được thực hiện, tất cả các lớp và mô-đun sẽ có sẵn theo yêu cầu.

  • Tải lại:Để cho phép tải lại, loader phải được định cấu hình rõ ràng cho nó. Ví dụ:

  loader = Zeitwerk::Loader.new
  ...
  loader.enable_reloading # you need to opt-in before setup
  loader.setup
  ...
  loader.reload

loader.reload lệnh gọi tải lại cây dự án một cách nhanh chóng và bất kỳ thay đổi mới nào sẽ hiển thị ngay lập tức. Tuy nhiên, chúng tôi vẫn cần một cơ chế xung quanh để phát hiện các thay đổi đối với hệ thống tệp và gọi loader.reload . Một phiên bản đơn giản được hiển thị bên dưới:

  require 'filewatcher'

  loader = Zeitwerk::Loader.new
  ...
  loader.enable_reloading
  loader.setup
  ...

  my_filewatcher = Filewatcher.new('lib/')
  Thread.new(my_filewatcher) {|fw| fw.watch {|filename| loader.reload } }

Sử dụng Zeitwerk trong Rails

Zeitwerk được bật theo mặc định trong Rails 6.0. Tuy nhiên, bạn có thể chọn không tham gia và sử dụng Rails classic trình tải mã.

# config/application.rb
config.load_defaults "6.0"
config.autoloader = :classic

Sử dụng Zeitwerk trong Đá quý

Zeitwerk cung cấp một phương pháp thuận tiện cho đá quý, miễn là chúng sử dụng cấu trúc đá quý chuẩn (lib/special_gem ). Phương pháp tiện lợi này có thể được sử dụng như sau:

# lib/special_gem.rb
require 'zeitwerk'

module SpecialGem
end

loader = Zeitwerk::Loader.for_gem
loader.setup

Với cấu trúc đá quý tiêu chuẩn, for_gem cuộc gọi thêm lib thư mục làm không gian tên gốc, cho phép mọi mã trong lib thư mục sẽ được tìm thấy tự động.

Để có thêm cảm hứng, bạn có thể xem đá quý bằng Zeitwerk:

  • Karafka
  • Máy bay phản lực

Tài liệu tham khảo

Rails autoloading - nó hoạt động như thế nào và khi nào nó không hoạt động

Zeitwerk