Skip to content

fix: remove global xml_adapter_type override#66

Merged
ronaldtse merged 2 commits into
mainfrom
fix/remove-global-xml-adapter-override
Apr 29, 2026
Merged

fix: remove global xml_adapter_type override#66
ronaldtse merged 2 commits into
mainfrom
fix/remove-global-xml-adapter-override

Conversation

@ronaldtse
Copy link
Copy Markdown
Contributor

@ronaldtse ronaldtse commented Apr 29, 2026

Problem

lib/unitsml.rb unconditionally sets the global Lutaml::Model::Config.xml_adapter_type = :ox at require time:

Lutaml::Model::Config.configure do |config|
  config.xml_adapter_type = RUBY_ENGINE == "opal" ? :oga : :ox
end

This runs when require "unitsml" is called (e.g. via plurimathunitsml), silently overwriting the global adapter for every other gem in the same Ruby process.

Impact

  • Gems like rfcxml that explicitly set :nokogiri have their configuration overridden.
  • In metanorma-ietf, this caused to_xml to hang on repeated calls because the adapter was switched mid-process from :nokogiri to :ox.
  • The :ox adapter has known reentrancy issues that manifest as hangs when used in a process that was initialized with a different adapter.

Reproduction

require "lutaml/model"
Lutaml::Model::Config.xml_adapter_type = :nokogiri
puts Lutaml::Model::Config.xml_adapter_type  # => :nokogiri

require "unitsml"
puts Lutaml::Model::Config.xml_adapter_type  # => :ox  (silently changed!)

Fix

Two changes:

  1. Delete the global configure block from lib/unitsml.rb.
  2. Add ox as a runtime dependency in the gemspec.

Why this works — the adapter convention for lutaml-model gems

Lutaml::Model::Config.xml_adapter_type is a global singleton — one per process. When multiple gems set it, the last require wins, which is fragile and order-dependent. The correct convention is:

Only the application boundary sets the adapter. Libraries never do.

Stack:  metanorma-ietf (app)  →  rfcxml (lib)  →  lutaml-model
              ✅ sets adapter     ❌ must NOT       auto-detects
                                   set adapter

Stack:  unitsml CLI (app)   →  unitsml (lib)  →  lutaml-model
              ✅ sets adapter     ❌ must NOT       auto-detects
                                   set adapter

How auto-detection handles the default case

When require "lutaml/model" runs, it auto-detects the best available adapter (nokogiri > ox > oga):

# lutaml-model lib/lutaml/model/xml.rb:29-31
if (adapter = Lutaml::Model::Xml.detect_xml_adapter)
  Lutaml::Model::Config.xml_adapter_type = adapter
end

This is already the right default. The problem is libraries overriding it afterward.

What each gem must do

Gem type Responsibility
Library gems (unitsml, rfcxml, etc.) Declare adapter gem in gemspec (e.g. spec.add_dependency "ox"). Do NOT call Config.xml_adapter_type =. Auto-detection finds the installed adapter.
Application gems (metanorma-ietf) Set Config.xml_adapter_type in application init, before loading libraries. This sticks because libraries no longer override it.
CLI entry points Set Config.xml_adapter_type in exe/xxx before require "unitsml".
Tests Already correct — spec_helper.rb sets the adapter. Tests are an application boundary.

Why this is seamless

Scenario What happens
gem install unitsml standalone gemspec pulls in ox → auto-detection finds ox → works
metanorma-ietf sets :nokogiri then loads unitsml unitsml does not override → :nokogiri sticks → works
Auto-detection only picks best available adapter → works
Multiple adapters installed application/CLI picks one → works

Other gems that should adopt this convention

  • rfcxml: same fix — remove Config.xml_adapter_type = :nokogiri from lib/rfcxml.rb, add nokogiri as gemspec dependency.
  • Any other library using lutaml-model: same pattern — never call Config.xml_adapter_type = in library code, declare adapter gem in gemspec.

Setting Lutaml::Model::Config.xml_adapter_type globally at require
time is a side-effect that affects every other gem sharing the
process. This caused hangs in metanorma-ietf where rfcxml sets
:nokogiri but unitsml silently switches to :ox, breaking subsequent
to_xml calls.

unitsml uses standard Lutaml::Model::Serializable models and calls
to_xml/from_xml on them -- none of this requires a specific adapter.
The host application should control the adapter configuration.
@ronaldtse ronaldtse requested a review from suleman-uzair April 29, 2026 08:10
@ronaldtse ronaldtse added the bug Something isn't working label Apr 29, 2026
Ensures an XML adapter is always available for lutaml-model's
auto-detection, without needing to set the global adapter type.
@ronaldtse ronaldtse merged commit 920dfbb into main Apr 29, 2026
15 of 18 checks passed
@ronaldtse ronaldtse deleted the fix/remove-global-xml-adapter-override branch April 29, 2026 11:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants