Încărcarea automată a fișierelor Ruby cu Zeitwerk

  • 3 minute de citit
  • 6 exemple de cod în Ruby

Disponibil și în English

Pe această pagină

Introducere

Salut tuturor!

Pe când experimentam cu limbajul de programare Ruby în timp ce construiam o aplicație Rails, am dat peste Zeitwerk, o bibliotecă ce încarcă automat toate fișierele tale Ruby, și am vrut să scriu despre ea.

Ideea principală din spatele bibliotecii este că proiectul tău trebuie să respecte o anumită structură de fișiere, iar biblioteca va încărca apoi toate fișierele Ruby, eliminând nevoia de a scrie require_relative 'x'. Acest lucru este util deoarece păstrează codul structurat într-un mod opinionat și economisește câteva apăsări de taste la importul fișierelor.

Am fost nedumerit la început când am răsfoit codul sursă al Gitlab și nu am văzut nicio instrucțiune de import, iar explicația este că ei folosesc Rails și Zeitwerk.

Utilizare

Pentru a folosi biblioteca, proiectul tău trebuie să respecte următoarea structură de directoare:

lib/my_gem.rb         -> MyGemlib/my_gem/foo.rb     -> MyGem::Foolib/my_gem/bar_baz.rb -> MyGem::BarBazlib/my_gem/woo/zoo.rb -> MyGem::Woo::Zoo

Poți, de asemenea, să o ajustezi fin prin colapsarea directoarelor, ignorarea unor directoare sau adăugarea de inflexiuni. (ex: unicredit.rb devine UniCredit; fără inflexiuni ar fi C cu literă mică)

Odată ce ai această structură, o poți instala scriind bundle add zeitwerk, apoi tot ce trebuie să faci este să scrii niște cod standard (boilerplate) pentru a o configura.

Aplicație

Dacă scrii o aplicație, atunci poți apela biblioteca în fișierul principal, specificând directoarele pe care Zeitwerk ar trebui să le încarce.

require "zeitwerk"# Notă: nu există require_relative "huffman" deoarece Zeitwerk l-a încărcat automat.def main  huffman = Huffman.new("huffman.md")  content = huffman.encode  print content.leftendif __FILE__ == $0  # Sunt necesare doar trei linii de cod  loader = Zeitwerk::Loader.new  loader.push_dir(File.expand_path("./lib"))  loader.setup  mainend

Structura acestui proiect de aplicație arată astfel:

├── Gemfile├── Gemfile.lock├── huffman.md├── lib│   ├── huffman│   │   └── base_exception.rb│   ├── huffman.rb│   └── tree│       ├── base_node.rb│       ├── internal_node.rb│       └── leaf_node.rb├── main.rb # Fișierul principal, punctul de intrare├── Rakefile.rb└── test    └── huffman_test.rb

Atât este tot.

Gem (bibliotecă)

Când scrii o gem de bibliotecă, poți folosi Zeitwerk::Loader.for_gem. În gem-ul meu ExtrasDeCont am următorul punct de intrare:

# frozen_string_literal: truerequire 'zeitwerk'loader = Zeitwerk::Loader.for_gemloader.inflector.inflect(  "unicredit" => "UniCredit")loader.setup# Modulul ExtrasDeCont conține utilitare pentru analizarea extraselor de cont bancare.module ExtrasDeCont  # Harta băncilor suportate (simbol → clasa de reguli)  BANK_RULES = {    brd: ExtrasDeCont::Rules::Brd,    ing: ExtrasDeCont::Rules::Ing,    revolut: ExtrasDeCont::Rules::Revolut,    unicredit: ExtrasDeCont::Rules::UniCredit  }.freeze  class << self    # Analizează un extras de cont bancar în format PDF și returnează tranzacțiile structurate.    #    # @param file [String, Pathname, IO] calea către fișierul PDF sau un obiect de tip IO    # @param bank [Symbol] identificatorul băncii (:unicredit, :revolut, etc.)    # @return [Array<ExtrasDeCont::Transaction>]    # @raise [ArgumentError] dacă banca nu este suportată    def parse(file, bank:)      rule_class = BANK_RULES[bank]      raise ArgumentError, "Unsupported bank: #{bank}. Supported banks: #{BANK_RULES.keys.join(", ")}" unless rule_class      p = ExtrasDeCont::Parser.new(file)      p.parse_with(rule_class.new)    end  endendloader.eager_load

Observă că am adăugat această inflexiune pentru ca unicredit.rb să se refere la UniCredit.

loader.inflector.inflect(  "unicredit" => "UniCredit")

În plus, structura de fișiere a gem-ului arată astfel:

.├── AGENTS.md├── bin│   └── example.rb├── changelog.md├── diagram.md├── entities.json├── extras_de_cont.gemspec├── Gemfile├── Gemfile.lock├── lib│   ├── extras_de_cont│   │   ├── parser.rb│   │   ├── rules│   │   │   ├── base.rb│   │   │   ├── brd.rb│   │   │   ├── ing.rb│   │   │   ├── revolut.rb│   │   │   └── unicredit.rb│   │   └── transaction.rb│   └── extras_de_cont.rb├── LICENSE├── mempalace.yaml├── opencode.json├── pkg│   ├── extras_de_cont-1.0.2.gem│   ├── extras_de_cont-1.1.0.gem│   ├── extras_de_cont-1.2.0.gem│   ├── extras_de_cont-1.3.0.gem│   └── extras_de_cont-1.4.0.gem├── Rakefile├── README.md├── sig│   └── extras_de_cont│       ├── extras_de_cont.rbs│       ├── parser.rbs│       ├── rules│       │   ├── base.rbs│       │   └── brd.rbs│       └── transaction.rbs└── test    └── extras_de_cont        └── rules            ├── brd_rule_test.rb            ├── ing_rule_test.rb            ├── revolut_rule_test.rb            └── unicredit_rule_test.rb12 directories, 35 files

Concluzie

Zeitwerk este un gem Ruby util care elimină nevoia de a require manual fișierele. Dacă răsfoiești niște cod Ruby și toate require_relative lipsesc, atunci proiectul folosește probabil Zeitwerk.

Pentru ca Zeitwerk să funcționeze, va trebui să ai o anumită structură de directoare, dar Zeitwerk este foarte personalizabil.

Mulțumesc pentru lectură!