feat: Opal boot file + lazy registration for v2/v3/v4 - #31
Open
ronaldtse wants to merge 1 commit into
Open
Conversation
Under Opal, autoload declarations do not lazy-execute, so consumers
(plurimath-js) need an explicit boot file that eager-requires every
entry point in dependency order. This adds lib/mml/opal.rb plus a GHA
workflow + spec that verifies the boot file stays in sync with the
autoload declarations.
To support the boot file cleanly:
- Convert lib/mml/v{2,3,4}.rb from `require_relative` to `autoload`.
Per global rule (no require_relative for internal library code),
autoloads are declared inside the immediate parent namespace file.
- Replace v2/v4 module-body registration side-effects with a lazy
`register_models!` class method. The version module body now only
declares autoloads and defines methods, so the Opal boot file can
eager-load element files in any order without hitting a NameError
from a registration block firing too early.
- Add `VersionedParser#ensure_registered!` as the lazy trigger. The
first call to `parse` (or any path that needs registered types)
populates the version's context and memoizes the result.
- Add `ContextConfiguration#ensure_version_registered` and call it
from `create_context` and `populate_context!`. Without this, a user
who creates a derived context before calling `parse` would get an
empty fallback chain — TypeContext snapshots fallback_contexts at
creation time, so the built-in context must already be populated
for fallback resolution to see version types.
- Remove the `require_relative "../context_configuration"` line from
each version's Configuration module; the parent autoload handles it.
The boot file spec verifies:
- every autoload has a matching eager require,
- all referenced files exist on disk,
- version module files load after their per-version elements,
- Opal::Builder compiles the boot file end-to-end (native deps
stubbed).
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds Opal compatibility to mml so consumers like plurimath-js can compile the gem with
-r mml/opal. Also fixes a fallback-resolution bug that affected any caller creating a derived context before the firstparse.lib/mml/opal.rbboot file that eager-requires every autoload entry point in dependency order (Opal autoloads do not lazy-execute).lib/mml/v{2,3,4}.rbfromrequire_relativeto Rubyautoload(per the global rule: norequire_relativefor internal library code).register_models!class method, so the version module body stays side-effect-free at load time and the Opal boot file can eager-load element files in any order without hitting NameError.VersionedParser#ensure_registered!(memoized lazy trigger) andContextConfiguration#ensure_version_registered, which is called fromcreate_context/populate_context!to guarantee the built-in context is populated before any derived context snapshots its fallback chain..github/workflows/opal.yml) and a boot-file spec (spec/mml/opal_boot_spec.rb) covering both static structure and a realOpal::Buildercompile.Why lazy registration
Lutaml::Model::TypeContext.derivedresolves fallback context IDs at creation time (GlobalContext.registry.lookup(:mml_v4)). If a caller invokesMml::V4::Configuration.create_context(id: :custom, ...)before anyparse, the:mml_v4context doesn't exist yet — the resulting derived context snapshots an empty fallback chain andMml.parse(..., context: :custom)later fails withUnknown type "math" in context "custom".The fix:
Configuration.create_context(andpopulate_context!) now trigger the parent version module'sensure_registered!first. The parent is derived fromConfiguration.name(e.g."Mml::V4::Configuration"→Mml::V4) so each version doesn't need an explicit back-reference.Test plan
bundle exec rspec— 2878 examples, 0 failures (36 pre-existing pending)bundle exec rubocop— cleanbundle exec rspec spec/mml/opal_boot_spec.rb— 6 examples, 0 failuresbundle exec ruby -e "require 'mml/opal'; ..."parses V2/V3/V4 MathML successfullyopalworkflow runs the boot-file spec on Ubuntu / Ruby 3.3