feat: Opal payload generator, boot file, and loader#69
Merged
Conversation
Under Opal, autoload declarations do not lazy-execute, so consumers (plurimath-js) need an explicit boot file that eager-requires every autoloaded entry point in dependency order. unitsml is unique among the moxml-dependent gems: it ships a large unitsdb YAML database that must be pre-serialized as a Ruby hash under Opal (no filesystem). This change adds the full Opal toolchain for unitsml: - lib/unitsml/opal.rb: boot file eager-requiring every autoloaded entry point. Requires upstream boot files (unitsdb/opal, mml/opal, omml/opal) and the payload file so Database.from_db can satisfy without a filesystem. - lib/unitsml/opal/payload_generator.rb: Unitsml::Opal::PayloadGenerator class that reads unitsdb-ruby YAML data on MRI and emits a Ruby source file defining Unitsml::Unitsdb::Database::DATABASE as a frozen hash. Invoked via rake unitsml:generate_opal_payload. - lib/unitsml/opal/database_payload.rb: AUTO-GENERATED output committed to the gem. Loaded by the boot file under Opal. - lib/unitsml/unitsdb/database.rb: adopts the loader mechanism from fix/opal-database-payload-loader (load_opal_payload, opal_payload, reset_opal_payload) so tests can inject small payloads and the committed DATABASE constant is found via const_defined?(:DATABASE, false). Supersedes PR #65. - lib/unitsml/unitsdb.rb, lib/unitsml/model.rb and the four nested model parent files: convert require_relative and __dir__-interpolated autoloads to plain load-path-relative autoload declarations, per the global rule. Removes a dangling autoload (Unitsml::Model:: Namespace) whose target file never existed; MRI never tripped on it because nothing referenced the constant, but Opal eager-loads every autoload and would have crashed. - Rakefile: adds the unitsml:generate_opal_payload task. - Gemfile: adds nokogiri and opal so the boot-file spec can compile the boot file end-to-end via Opal::Builder with native deps stubbed. - .rubocop.yml: excludes the generated payload file from lint. - spec/unitsml/opal_boot_spec.rb: verifies the boot file structure and that Opal::Builder compiles it end-to-end with stubs. - spec/unitsml/payload_sync_spec.rb: verifies the committed payload matches what the generator produces from the current unitsdb gem and that it round-trips through from_hash. - spec/unitsml/opal/payload_generator_spec.rb: verifies the generator produces evaluable Ruby that reproduces the source database. - spec/unitsml/unitsdb/database_spec.rb: extends coverage to the new loader mechanism (load_opal_payload, DATABASE fallback). - .github/workflows/opal.yml: GHA workflow running the opal specs on Ubuntu/Ruby 3.3/Node 18.
Hash#inspect changed between Ruby 3.3 and 3.4 to add spaces around "=>". The committed payload file is generated on whichever Ruby the maintainer runs, but the payload_sync_spec runs on every supported Ruby in CI -- so a 3.3 maintainer committing the file would fail CI on 3.4, and vice versa. Replace Hash#inspect with a recursive serializer that produces byte-identical output across Rubies. Strings still use inspect (which is stable for UTF-8 clean data).
5849040 to
87652e3
Compare
5 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 unitsml so consumers like plurimath-js can compile the gem with
-r unitsml/opal. unitsml is unique among the moxml-dependent gems: it bundles a large unitsdb YAML database that must be pre-serialized as a Ruby hash under Opal (no filesystem).lib/unitsml/opal/payload_generator.rb(Unitsml::Opal::PayloadGenerator) — a class that reads unitsdb-ruby's YAML data on MRI and emits a Ruby source file definingUnitsml::Unitsdb::Database::DATABASEas a frozen hash.lib/unitsml/opal/database_payload.rb— AUTO-GENERATED output (run viabundle exec rake unitsml:generate_opal_payload) committed to the gem so Opal consumers don't need a filesystem.lib/unitsml/opal.rbboot file eager-requiring every autoloaded entry point in dependency order, including upstream boot files (unitsdb/opal,mml/opal,omml/opal) and the payload.fix/opal-database-payload-loader(load_opal_payload/opal_payload/reset_opal_payload) so tests can inject small payloads and the committedDATABASEconstant is found viaconst_defined?(:DATABASE, false). Supersedes PR Add Opal database payload loader #65.lib/unitsml/unitsdb.rbfromrequire_relativeto Rubyautoloadand normalizes__dir__-interpolated autoloads in the four nested model parent files to plain load-path-relative autoload declarations, per the global rule.Unitsml::Model::Namespace) whose target file never existed; MRI never tripped on it because nothing referenced the constant, but Opal eager-loads every autoload and would have crashed..github/workflows/opal.yml) and three new specs covering boot file structure, payload sync, and PayloadGenerator output.Out of scope (future PR)
The moxml gem itself doesn't yet ship an Opal boot file (moxml issue/PR TBD). The unitsml boot file stubs
oxand friends when compiled byOpal::Builderfor verification purposes; the gem's Opal consumer (plurimath-js) provides these at runtime.Test plan
bundle exec rspec— 398 examples, 0 failures (was 380; +18 from opal specs)bundle exec rubocop— clean on all changed files (pre-existing gemspec sort offense on main unchanged)bundle exec rspec spec/unitsml/opal_boot_spec.rb— 5 examples, 0 failuresbundle exec rspec spec/unitsml/payload_sync_spec.rb— 4 examples, 0 failuresbundle exec rspec spec/unitsml/opal/payload_generator_spec.rb— 7 examples, 0 failuresbundle exec rake unitsml:generate_opal_payloadregenerates the committed payload byte-for-byteopalworkflow runs the opal specs on Ubuntu / Ruby 3.3 / Node 18