Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

Code Loaders ใน Ruby:ทำความเข้าใจ Zeitwerk

ตัวโหลดโค้ดใน Ruby - ทำความเข้าใจ Zeitwerk

ด้วย Zeitwerk คุณสามารถปรับปรุงการเขียนโปรแกรมของคุณโดยรู้ว่าคลาสและโมดูลพร้อมใช้งานได้ทุกที่

โค้ดโหลดเดอร์คืออะไร

ตัวโหลดโค้ดช่วยให้นักพัฒนากำหนด classes และ modules ข้ามไฟล์และโฟลเดอร์ต่าง ๆ และใช้ทั่วทั้ง codebase โดยไม่ต้องระบุอย่างชัดเจน Rails เป็นตัวอย่างที่ดีของซอฟต์แวร์ที่ใช้ตัวโหลดโค้ด การเขียนโปรแกรมใน Rails ไม่ต้องการ require . อย่างชัดเจน เรียกให้โหลดโมเดลก่อนใช้ในคอนโทรลเลอร์ อันที่จริงใน Rails 6 ทุกอย่างใน app ไดเร็กทอรีโหลดอัตโนมัติในการบูตแอป โดยมีข้อยกเว้นบางประการ

แม้ว่าการโหลดโค้ดจะเป็นเรื่องง่ายๆ ในการโทรหา require มันไม่ง่ายอย่างนั้น การโหลดโค้ดสามารถแบ่งออกเป็นสามส่วนเพิ่มเติมได้ดังนี้

  • โหลดอัตโนมัติ: ซึ่งหมายความว่าโค้ดจะโหลดได้ทันทีตามต้องการ ตัวอย่างเช่น ใน Rails ให้เรียกใช้ rails s ไม่โหลดโมเดล คอนโทรลเลอร์ ฯลฯ ทั้งหมด แต่ในการโจมตีครั้งแรกของโมเดล User มันรันกลไกการโหลดอัตโนมัติเพื่อค้นหาและใช้โมเดล นี่คือการโหลดอัตโนมัติในการดำเนินการ มีข้อดีบางประการสำหรับสภาพแวดล้อมการพัฒนาของเรา เนื่องจากเรามีแอปที่เร็วกว่าและrails console เวลาเริ่มต้น Rails.config.autoload_path ควบคุมเส้นทางที่จะโหลดอัตโนมัติ
  • กระตือรือร้นในการโหลด: ซึ่งหมายความว่ามีการโหลดโค้ดลงในหน่วยความจำเมื่อเริ่มต้นแอปและไม่รอให้เรียกค่าคงที่ก่อนที่จะต้องใช้ ใน Rails โค้ดมีความกระตือรือร้นในการผลิต จากคำอธิบายข้างต้น โค้ดการโหลดอัตโนมัติในการผลิตจะส่งผลให้เวลาตอบสนองช้า เนื่องจากแต่ละค่าคงที่จะต้องใช้ทันที Rails.config.eager_load_paths ควบคุมเส้นทางที่จะโหลดอย่างกระตือรือร้น
  • กำลังโหลด: ตัวโหลดโค้ดคอยเฝ้าดูการเปลี่ยนแปลงของไฟล์ใน autoload_path และโหลดไฟล์ใหม่เมื่อสังเกตเห็นการเปลี่ยนแปลงใดๆ ใน Rails สิ่งนี้มีประโยชน์มากในการพัฒนา เนื่องจากช่วยให้เราสามารถเรียกใช้ rails s และทำการเปลี่ยนแปลงพร้อมกันโดยไม่จำเป็นต้องรีสตาร์ทเซิร์ฟเวอร์ Rails กำลังโหลดซ้ำในการดำเนินการ

เราจะเห็นได้ง่าย ๆ ว่าแนวคิดเหล่านี้ส่วนใหญ่ได้รับการพัฒนาและใช้งานจริงใน Rails Zeitwerk เปลี่ยนแปลงสิ่งนี้! Zeitwerk ช่วยให้เราสามารถโหลดโค้ดทั้งหมดไปยังโปรเจ็กต์ Ruby ได้

Zeitwerk คืออะไร

Zeitwerk เป็นตัวโหลดโค้ดที่มีประสิทธิภาพและปลอดภัยต่อเธรดสำหรับ Ruby และสามารถใช้ได้ในโปรเจ็กต์ Ruby ใดๆ รวมถึงเว็บเฟรมเวิร์ก (Rails, Hanami, Sinatra), เครื่องมือ Cli และ gems ด้วยสิ่งนี้ คุณสามารถปรับปรุงการเขียนโปรแกรมของคุณโดยรู้ว่าคลาสและโมดูลพร้อมใช้งานทุกที่ ตามเนื้อผ้า Rails และ บางส่วน อัญมณีอื่น ๆ มีตัวโหลดโค้ดในตัวเพื่อเปิดใช้งานฟังก์ชันนี้ อย่างไรก็ตาม Zeitwerk แยกแนวคิดเหล่านี้ออกเป็นอัญมณีและอนุญาตให้ Rubyists นำแนวคิดเหล่านี้ไปใช้กับโครงการของพวกเขาได้

กำลังติดตั้ง Zeitwerk

ก่อนอื่นเราต้องติดตั้งอัญมณี:

gem install zeitwerk

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

การกำหนดค่า Zeitwerk

เริ่มจากพื้นฐานกันก่อน:

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

โค้ดด้านบนสร้างอินสแตนซ์ตัวโหลดและเรียกใช้ setup . หลังจากโทรไป setup , รถตักพร้อมที่จะโหลดรหัส แต่ก่อนหน้านั้น การกำหนดค่าที่จำเป็นทั้งหมดใน loader ควรจะครอบคลุมอยู่แล้ว ในบทความนี้ ผมจะกล่าวถึงการกำหนดค่าบางส่วนใน loader และข้อตกลงสำหรับการจัดโครงสร้างโค้ดของคุณ

  • โครงสร้างไฟล์:เพื่อให้ Zeitwerk ทำงานได้ ชื่อไฟล์และไดเร็กทอรีต้องตรงกับโมดูลและชื่อคลาสที่พวกเขากำหนด ตัวอย่างเช่น
  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
  • Root Namespaces:Root Namespaces เป็นไดเร็กทอรีที่ Zeitwerk สามารถค้นหารหัสของคุณ เมื่อ modules และ classes มีการอ้างอิง Zeitwerk รู้ในการค้นหาเนมสเปซรูทด้วยชื่อไฟล์ที่ตรงกัน ตัวอย่างเช่น
  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

มีสองวิธีหลักในการกำหนดเนมสเปซรูทสำหรับกรณีการใช้งานที่แตกต่างกันสองกรณี วิธีเริ่มต้นแสดงอยู่ด้านล่าง:

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

  // bar/foo.rb
  class Foo; end

หมายถึงคลาส Foo สามารถอ้างอิงได้โดยไม่มี Bar::Foo . ที่ชัดเจน เนื่องจากไดเร็กทอรี bar ทำหน้าที่เป็นเนมสเปซรูท วิธีที่สองในการกำหนดเนมสเปซคือการระบุเนมสเปซอย่างชัดเจนในการเรียกไปยัง 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

มีบางสิ่งที่ควรทราบในรหัสนี้:

  1. โมดูล Bar ถูกกำหนดไว้แล้วก่อนที่จะถูกใช้โดย push_dir . หากโมดูลที่เราต้องการใช้ถูกกำหนดโดยบุคคลที่สาม ความต้องการธรรมดาจะกำหนดมันก่อนที่เราจะใช้ในการเรียก push_dir .
  2. The push_dir ระบุเนมสเปซ Bar . อย่างชัดเจน .
  3. ไฟล์ src/foo.rb กำหนด Bar::Foo ไม่ใช่ Foo และไม่จำเป็นต้องสร้างไดเร็กทอรี เช่น src/bar/foo.rb .
  • ตัวโหลดโค้ดอิสระ:จากการออกแบบ Zeitwerk อนุญาตให้แต่ละโปรเจ็กต์หรือแอพพึ่งพาเพื่อจัดการแผนผังโปรเจ็กต์แต่ละรายการ ซึ่งหมายความว่ากลไกการโหลดโค้ดของการขึ้นต่อกันแต่ละรายการได้รับการจัดการโดยสิ่งที่ขึ้นต่อกันนั้น ตัวอย่างเช่น ใน Rails 6 Zeitwerk จะจัดการการโหลดโค้ดสำหรับแอป Rails และอนุญาตให้การขึ้นต่อกันของอัญมณีแต่ละรายการสามารถจัดการแผนผังโครงการของตนเองแยกกันได้ เป็นเงื่อนไขข้อผิดพลาดที่จะมีไฟล์ทับซ้อนกันระหว่างตัวโหลดโค้ดหลายตัว

  • โหลดอัตโนมัติ:ด้วยการตั้งค่าข้างต้น เมื่อเรียกไปที่ setup ถูกสร้างขึ้น ทุกคลาสและโมดูลจะพร้อมใช้งานตามต้องการ

  • การโหลดซ้ำ:หากต้องการเปิดใช้งานการโหลดซ้ำ loader ต้องมีการกำหนดค่าไว้อย่างชัดเจน ตัวอย่างเช่น

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

loader.reload การเรียกจะโหลดโครงสร้างโครงการใหม่ทันที และการเปลี่ยนแปลงใหม่จะปรากฏทันที อย่างไรก็ตาม เรายังคงต้องการกลไกรอบข้างเพื่อตรวจจับการเปลี่ยนแปลงของระบบไฟล์และเรียก loader.reload . เวอร์ชันง่าย ๆ แสดงอยู่ด้านล่าง:

  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 } }

การใช้ Zeitwerk ใน Rails

Zeitwerk เปิดใช้งานโดยค่าเริ่มต้นใน Rails 6.0 อย่างไรก็ตาม คุณสามารถเลือกไม่ใช้และใช้ Rails classic ตัวโหลดโค้ด

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

การใช้ Zeitwerk ในอัญมณี

Zeitwerk มอบวิธีที่สะดวกสำหรับอัญมณี ตราบใดที่พวกเขาใช้โครงสร้างอัญมณีมาตรฐาน (lib/special_gem ). วิธีอำนวยความสะดวกนี้สามารถใช้ได้ดังนี้:

# lib/special_gem.rb
require 'zeitwerk'

module SpecialGem
end

loader = Zeitwerk::Loader.for_gem
loader.setup

ด้วยโครงสร้างอัญมณีมาตรฐาน for_gem โทรเพิ่ม lib ไดเร็กทอรีเป็นเนมสเปซรูท เปิดใช้งานทุกโค้ดใน lib ให้ค้นหาไดเร็กทอรีโดยอัตโนมัติ

สำหรับแรงบันดาลใจเพิ่มเติม คุณสามารถตรวจสอบอัญมณีโดยใช้ Zeitwerk:

  • คาราฟคา
  • เครื่องบินเจ็ตส์

ข้อมูลอ้างอิง

การโหลดอัตโนมัติของ Rails — วิธีการทำงานและเมื่อไม่ทำงาน

ไซท์เวิร์ค