Skip to content

Replace internal requires with Ruby autoload (#120) - #121

Merged
andrew2net merged 3 commits into
lutaml-integrationfrom
fix/issue-120-autoload-requires
Jul 20, 2026
Merged

Replace internal requires with Ruby autoload (#120)#121
andrew2net merged 3 commits into
lutaml-integrationfrom
fix/issue-120-autoload-requires

Conversation

@andrew2net

Copy link
Copy Markdown
Contributor

Summary

Fixes #120 — the circular require between OrganizationType and Subdivision reported by downstream gems (metanorma-taste) under Ruby 4.0 with warnings:

lib/relaton/bib/model/organization_type.rb:16: circular require considered harmful - .../subdivision.rb

OrganizationType.included did require_relative "subdivision" inside the hook, while Subdivision opens with include OrganizationType — so loading subdivision.rb re-entered the hook and re-required the in-progress file.

Per @ronaldtse's direction on the issue, this replaces the internal require_relative chains with Ruby autoload via a central manifest, which makes load order irrelevant and removes this whole class of ordering bugs.

Changes

  • New lib/relaton/bib/model_autoload.rb — central autoload manifest for every Relaton::Bib model + Converter constant. Also eagerly requires lutaml/model/lutaml/xml and runs the Lutaml::Model::Config.configure { xml_adapter_type = :nokogiri } block (moved out of item.rb) so serialization works regardless of which class is referenced first.
  • item.rb — dropped the ~39-line require_relative block and the class Relation < Serializable; end forward stub.
  • relation.rb — now self-contained (class Relation < Lutaml::Model::Serializable), autoloaded.
  • organization_type.rb — deleted the in-hook require_relative "subdivision" (the core fix).
  • Dropped sibling require_relative from contact, ext, organization, date, series, bibitem, bibdata, bibitem_shared, bibdata_shared.
  • Kept require_relative for converter method-partials (reopens, which autoload cannot express).
  • Documented the new convention in CLAUDE.md.

Why it resolves the cycle

In both include orders, class Subdivision < Serializable / class Organization < Serializable opens its own constant before the include OrganizationType that fires the hook referencing Subdivision — so the self-reference resolves to an already-open constant instead of re-triggering the load.

Tests

New spec/relaton/bib/autoload_spec.rb:

  • structural (no in-hook require), self-contained Relation superclass, and nokogiri-adapter guards;
  • functional round-trips (organization with nested subdivision; standalone subdivision);
  • load-order-independence subprocesses (Subdivision-first and Organization-first);
  • a -W2 subprocess guard asserting no relaton-bib circular require warning (scoped so unrelated third-party warnings don't false-fail).

Full suite: 229 examples, 0 failures. RuboCop clean on new files.

Fixes the circular require between OrganizationType and Subdivision reported
under Ruby 4.0 with warnings enabled:

  organization_type.rb:16: circular require considered harmful - subdivision.rb

OrganizationType.included did `require_relative "subdivision"` inside the hook
while Subdivision opens with `include OrganizationType`, so loading subdivision
re-entered the hook and re-required the in-progress file.

Wire the model + converter layer via a central autoload manifest
(lib/relaton/bib/model_autoload.rb) instead of require_relative chains, making
load order irrelevant. Both include orders now resolve because each class opens
its own constant before the include fires the hook that references it.

- Move `require "lutaml/model"/"lutaml/xml"` and the Lutaml::Model::Config XML
  adapter block out of item.rb into the manifest (eager), so serialization works
  regardless of which model class is referenced first.
- Drop the `class Relation < Serializable` forward stub from item.rb; make
  relation.rb self-contained and autoloaded.
- Keep require_relative only for converter method-partials (reopens, which
  autoload cannot express).
- Add spec/relaton/bib/autoload_spec.rb covering structural, functional,
  load-order-independence, and a -W2 circular-require guard.
relaton-render now requires Ruby >= 3.3.0; the integration job pinned 3.2,
so bundler version-resolution failed before any test ran.
Passing multi-line Ruby with embedded quotes via `ruby -e` is mangled during
Windows command-line reconstruction (newlines/quotes lost), so the load-order
subprocess tests produced empty stdout and failed only on windows-latest. Write
the snippet to a Tempfile and run `ruby <file>` instead, which behaves
identically across platforms; strip stdout to tolerate CRLF.
@andrew2net
andrew2net merged commit 3dbbd24 into lutaml-integration Jul 20, 2026
12 checks passed
@andrew2net
andrew2net deleted the fix/issue-120-autoload-requires branch July 20, 2026 20:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant