lutaml-model 0.8.11 → 0.8.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/opal.yml +31 -0
  3. data/.rspec-opal +5 -0
  4. data/.rubocop_todo.yml +45 -34
  5. data/README.adoc +10 -1
  6. data/docs/_guides/index.adoc +4 -0
  7. data/docs/_guides/opal.adoc +221 -0
  8. data/docs/_guides/xml_mappings/07_best_practices.adoc +2 -1
  9. data/docs/_pages/configuration.adoc +9 -4
  10. data/docs/_pages/index.adoc +1 -0
  11. data/docs/_pages/serialization_adapters.adoc +3 -2
  12. data/docs/index.adoc +1 -0
  13. data/lib/lutaml/hash_format/adapter/mapping.rb +2 -4
  14. data/lib/lutaml/json/adapter/mapping.rb +2 -4
  15. data/lib/lutaml/jsonl/adapter/mapping.rb +2 -4
  16. data/lib/lutaml/key_value/adapter/hash/mapping.rb +2 -4
  17. data/lib/lutaml/key_value/adapter/json/mapping.rb +2 -4
  18. data/lib/lutaml/key_value/adapter/jsonl/mapping.rb +2 -4
  19. data/lib/lutaml/key_value/adapter/toml/mapping.rb +2 -4
  20. data/lib/lutaml/key_value/adapter/yaml/mapping.rb +2 -4
  21. data/lib/lutaml/key_value/adapter/yamls/mapping.rb +2 -4
  22. data/lib/lutaml/key_value/mapping.rb +4 -4
  23. data/lib/lutaml/model/adapter_resolver.rb +5 -8
  24. data/lib/lutaml/model/mapping/mapping.rb +12 -0
  25. data/lib/lutaml/model/version.rb +1 -1
  26. data/lib/lutaml/toml/adapter/mapping.rb +2 -4
  27. data/lib/lutaml/xml/schema/xsd.rb +5 -4
  28. data/lib/lutaml/xml/schema.rb +8 -5
  29. data/lib/lutaml/xml/xml_orderable.rb +17 -0
  30. data/lib/lutaml/xml.rb +8 -11
  31. data/lib/lutaml/yaml/adapter/mapping.rb +2 -4
  32. data/lib/lutaml/yamls/adapter/mapping.rb +7 -3
  33. data/lutaml-model.gemspec +1 -1
  34. data/spec/lutaml/model/opal_smoke_spec.rb +117 -0
  35. data/spec/lutaml/xml/opal_xml_spec.rb +145 -0
  36. data/spec/lutaml/xml/xml_spec.rb +64 -13
  37. data/spec/support/opal.rb +6 -0
  38. metadata +11 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 992b8e51bee9c168f1dbb4cac0fcfd75f593f1c40cc29abce7e2163088e6fc48
4
- data.tar.gz: 8e3524b5e4336e8cb289c3f31b513727bb2bbb23d3429fcd770425b6f24de489
3
+ metadata.gz: 86f1ceda6e01c3d47e303f092a24062a0e051faaf8a859bb47d2723670088d61
4
+ data.tar.gz: 92b43d69b6d49244c4187859e497fdbbce11d913f11425e8dfdfed1493f97e5a
5
5
  SHA512:
6
- metadata.gz: 61c349cf6a1476a0c8668ea19b45e2989275a00d97ab718613eb80cfdc86a2e71ba0cb344c69a6877c5447a57d715f080470c3b28dce0c046652502182b29408
7
- data.tar.gz: b85e8858876efa7b98acec6df1ff36e2ebbbf772c8b8cf035a459374159d2c5d704c13cbcecc99a69561438884d05bc4f52d13e12d6cd1b3f63611761344bd04
6
+ metadata.gz: 33612bb8b97cc3667b88a5638288155319281de507ca4b8ca6386ea6b9e3a79b747d3b0441d92b4083441310a7962449c511e1445eb3779c2bf872b1d2ebdca1
7
+ data.tar.gz: f51445ae0f41d649c89e21c43f8cb1738a146457a35fac1fb5f927f6829d7360e3d115b55d7ea24549c33b03074c381028b89fc10e4ef87e703cd7f51bd36bf6
@@ -0,0 +1,31 @@
1
+ name: opal
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ with:
14
+ submodules: "recursive"
15
+
16
+ - name: Set up Ruby
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: "3.3"
20
+ bundler-cache: true
21
+
22
+ - name: Set up Node.js
23
+ uses: actions/setup-node@v4
24
+ with:
25
+ node-version: "18"
26
+
27
+ - name: Run Opal tests
28
+ # TODO: Remove continue-on-error once REXML adapter is verified
29
+ # under actual Opal runtime (REXML compiles to JS via Opal's stdlib)
30
+ run: bundle exec rake spec:opal
31
+ continue-on-error: true
data/.rspec-opal ADDED
@@ -0,0 +1,5 @@
1
+ --default-path=spec
2
+ --pattern='spec/lutaml/model/opal_smoke_spec.rb,spec/lutaml/xml/opal_xml_spec.rb'
3
+ -I lib
4
+ --require=spec_helper
5
+ --require=support/opal
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-05-20 09:01:31 UTC using RuboCop version 1.86.0.
3
+ # on 2026-05-27 05:02:01 UTC using RuboCop version 1.86.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -17,45 +17,53 @@ Gemspec/RequiredRubyVersion:
17
17
  # SupportedStyles: with_first_argument, with_fixed_indentation
18
18
  Layout/ArgumentAlignment:
19
19
  Exclude:
20
- - 'lib/lutaml/turtle/transform.rb'
21
- - 'spec/lutaml/model/store_spec.rb'
20
+ - 'spec/lutaml/model/opal_smoke_spec.rb'
22
21
 
23
- # Offense count: 3
22
+ # Offense count: 1
24
23
  # This cop supports safe autocorrection (--autocorrect).
25
- # Configuration parameters: EnforcedStyleAlignWith.
26
- # SupportedStylesAlignWith: either, start_of_block, start_of_line
27
- Layout/BlockAlignment:
24
+ Layout/ClosingParenthesisIndentation:
28
25
  Exclude:
29
- - 'spec/lutaml/model/store_spec.rb'
26
+ - 'spec/lutaml/model/opal_smoke_spec.rb'
30
27
 
31
- # Offense count: 3
28
+ # Offense count: 1
32
29
  # This cop supports safe autocorrection (--autocorrect).
33
- Layout/BlockEndNewline:
30
+ # Configuration parameters: EnforcedStyle, IndentationWidth.
31
+ # SupportedStyles: consistent, consistent_relative_to_receiver, special_for_inner_method_call, special_for_inner_method_call_in_parentheses
32
+ Layout/FirstArgumentIndentation:
34
33
  Exclude:
35
- - 'spec/lutaml/model/store_spec.rb'
34
+ - 'spec/lutaml/model/opal_smoke_spec.rb'
36
35
 
37
- # Offense count: 6
36
+ # Offense count: 2
38
37
  # This cop supports safe autocorrection (--autocorrect).
39
- # Configuration parameters: Width, EnforcedStyleAlignWith, AllowedPatterns.
40
- # SupportedStylesAlignWith: start_of_line, relative_to_receiver
41
- Layout/IndentationWidth:
38
+ # Configuration parameters: AllowMultipleStyles, EnforcedHashRocketStyle, EnforcedColonStyle, EnforcedLastArgumentHashStyle.
39
+ # SupportedHashRocketStyles: key, separator, table
40
+ # SupportedColonStyles: key, separator, table
41
+ # SupportedLastArgumentHashStyles: always_inspect, always_ignore, ignore_implicit, ignore_explicit
42
+ Layout/HashAlignment:
42
43
  Exclude:
43
- - 'spec/lutaml/model/store_spec.rb'
44
+ - 'spec/lutaml/model/opal_smoke_spec.rb'
44
45
 
45
- # Offense count: 3024
46
+ # Offense count: 3022
46
47
  # This cop supports safe autocorrection (--autocorrect).
47
48
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
48
49
  # URISchemes: http, https
49
50
  Layout/LineLength:
50
51
  Enabled: false
51
52
 
52
- # Offense count: 2
53
+ # Offense count: 1
54
+ # This cop supports safe autocorrection (--autocorrect).
55
+ # Configuration parameters: EnforcedStyle.
56
+ # SupportedStyles: symmetrical, new_line, same_line
57
+ Layout/MultilineMethodCallBraceLayout:
58
+ Exclude:
59
+ - 'spec/lutaml/model/opal_smoke_spec.rb'
60
+
61
+ # Offense count: 1
53
62
  # This cop supports safe autocorrection (--autocorrect).
54
63
  # Configuration parameters: AllowInHeredoc.
55
64
  Layout/TrailingWhitespace:
56
65
  Exclude:
57
- - 'lib/lutaml/turtle/transform.rb'
58
- - 'spec/lutaml/model/store_spec.rb'
66
+ - 'spec/lutaml/model/opal_smoke_spec.rb'
59
67
 
60
68
  # Offense count: 21
61
69
  # Configuration parameters: AllowedMethods.
@@ -148,6 +156,12 @@ Lint/UnusedMethodArgument:
148
156
  - 'lib/lutaml/xml/unqualified_inheritance_strategy.rb'
149
157
  - 'spec/support/xml/xsd/code_example_validator.rb'
150
158
 
159
+ # Offense count: 1
160
+ # This cop supports safe autocorrection (--autocorrect).
161
+ Lint/UselessAssignment:
162
+ Exclude:
163
+ - 'spec/lutaml/xml/opal_xml_spec.rb'
164
+
151
165
  # Offense count: 1
152
166
  Lint/UselessConstantScoping:
153
167
  Exclude:
@@ -277,7 +291,7 @@ RSpec/BeforeAfterAll:
277
291
  RSpec/ContextWording:
278
292
  Enabled: false
279
293
 
280
- # Offense count: 96
294
+ # Offense count: 98
281
295
  # Configuration parameters: IgnoredMetadata.
282
296
  RSpec/DescribeClass:
283
297
  Enabled: false
@@ -288,7 +302,7 @@ RSpec/DescribeMethod:
288
302
  - 'spec/lutaml/xml/schema/xsd/schema_helper_methods_spec.rb'
289
303
  - 'spec/lutaml/xml/serializable_namespace_spec.rb'
290
304
 
291
- # Offense count: 1285
305
+ # Offense count: 1301
292
306
  # Configuration parameters: CountAsOne.
293
307
  RSpec/ExampleLength:
294
308
  Max: 68
@@ -363,7 +377,7 @@ RSpec/MultipleDescribes:
363
377
  - 'spec/lutaml/xml/namespace_resolution_strategy_spec.rb'
364
378
  - 'spec/lutaml/xml/xml_space_type_spec.rb'
365
379
 
366
- # Offense count: 1507
380
+ # Offense count: 1515
367
381
  RSpec/MultipleExpectations:
368
382
  Max: 21
369
383
 
@@ -437,17 +451,6 @@ Security/MarshalLoad:
437
451
  Exclude:
438
452
  - 'scripts-xmi-profile/profile_xmi.rb'
439
453
 
440
- # Offense count: 5
441
- # This cop supports safe autocorrection (--autocorrect).
442
- # Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
443
- # SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
444
- # ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
445
- # FunctionalMethods: let, let!, subject, watch
446
- # AllowedMethods: lambda, proc, it
447
- Style/BlockDelimiters:
448
- Exclude:
449
- - 'spec/lutaml/model/store_spec.rb'
450
-
451
454
  # Offense count: 2
452
455
  # This cop supports unsafe autocorrection (--autocorrect-all).
453
456
  # Configuration parameters: AllowedMethods, AllowedPatterns.
@@ -540,3 +543,11 @@ Style/StringConcatenation:
540
543
  - 'lib/lutaml/model/schema/xml_compiler/complex_type.rb'
541
544
  - 'lib/lutaml/model/schema/xml_compiler/simple_type.rb'
542
545
  - 'lib/lutaml/model/schema/xml_compiler/xml_namespace_class.rb'
546
+
547
+ # Offense count: 1
548
+ # This cop supports safe autocorrection (--autocorrect).
549
+ # Configuration parameters: EnforcedStyleForMultiline.
550
+ # SupportedStylesForMultiline: comma, consistent_comma, diff_comma, no_comma
551
+ Style/TrailingCommaInArguments:
552
+ Exclude:
553
+ - 'spec/lutaml/model/opal_smoke_spec.rb'
data/README.adoc CHANGED
@@ -16195,11 +16195,20 @@ Lutaml::Model supports running under https://opalrb.com[Opal] (Ruby compiled to
16195
16195
  JavaScript). The runtime is detected automatically and adapter selection is
16196
16196
  adjusted accordingly.
16197
16197
 
16198
- * *XML*: Only the `:oga` adapter is available (auto-selected).
16198
+ * *XML*: Only the `:rexml` adapter is available (auto-selected). Opal
16199
+ reimplements `strscan` and `stringio` in its stdlib, enabling REXML (pure
16200
+ Ruby) to compile cleanly to JavaScript.
16199
16201
  * *JSON*: Only the `:standard` adapter is available.
16202
+ * *YAML*: Only the `:standard` adapter is available.
16200
16203
  * *TOML*: Not available on Opal.
16201
16204
  * *Schema generation*: `to_xsd`, `to_relaxng`, and `from_xml` (XML schema
16202
16205
  compilation) raise `NotImplementedError` on Opal.
16206
+ * *Liquid templating*: Not available on Opal (Phase 1 — skipped).
16207
+ * *XPath*: Not available on Opal (REXML XPath requires features not yet
16208
+ supported by Opal's stdlib).
16209
+
16210
+ See the link:docs/_guides/opal.adoc[Opal Usage Guide] for setup instructions
16211
+ and limitations.
16203
16212
 
16204
16213
 
16205
16214
  === Error handling
@@ -46,6 +46,10 @@ See link:../references/rdf-namespaces[RDF Namespaces] for namespace classes,
46
46
  * link:../consolidation-mapping[Consolidation Mapping] - Group sibling elements into structured models
47
47
  * link:../document-validation[Document Validation] - Document-level validation with rules, profiles, and remediation
48
48
 
49
+ == Runtime environments
50
+
51
+ * link:../opal[Opal Usage Guide] - Run Lutaml::Model in the browser via Opal (Ruby to JavaScript)
52
+
49
53
  == By task
50
54
 
51
55
  === I want to serialize to XML
@@ -0,0 +1,221 @@
1
+ ---
2
+ title: Opal Usage Guide
3
+ parent: Guides
4
+ nav_order: 99
5
+ ---
6
+
7
+ = Opal Usage Guide
8
+
9
+ :toc:
10
+ :toclevels: 3
11
+
12
+ == Overview
13
+
14
+ https://opalrb.com[Opal] is a Ruby-to-JavaScript compiler that allows Ruby code to run in the browser. Lutaml::Model supports running under Opal, enabling XML/JSON/YAML serialization in client-side applications.
15
+
16
+ The XML parsing layer is provided by the https://github.com/lutaml/moxml[moxml] gem (v0.2+), which detects the Opal runtime and uses the REXML adapter automatically.
17
+
18
+ == How it works
19
+
20
+ Opal compiles Ruby source code to JavaScript. Under Opal:
21
+
22
+ . `RUBY_ENGINE` equals `"opal"`
23
+ . `Lutaml::Model::RuntimeCompatibility.opal?` returns `true`
24
+ . Adapter selection is adjusted automatically
25
+ . Gems with C extensions (Nokogiri, Ox, Oj, tomlib) are not available
26
+ . REXML is used for XML because Opal reimplements `strscan` and `stringio` in its stdlib, enabling REXML (pure Ruby) to compile cleanly to JavaScript
27
+
28
+ No configuration is needed -- the runtime is detected and adapters are selected automatically.
29
+
30
+ == Supported features
31
+
32
+ === Fully supported
33
+
34
+ * Model definition with `attribute`, types, collections, defaults
35
+ * XML serialization/deserialization (via REXML adapter)
36
+ ** Element and attribute mapping
37
+ ** Nested elements and collections
38
+ ** Mixed content
39
+ ** Namespaces (parsing and serialization)
40
+ ** CDATA sections
41
+ ** Processing instructions
42
+ ** Comments
43
+ ** Entity references
44
+ ** XML declarations and doctypes
45
+ * JSON serialization/deserialization (via standard adapter)
46
+ * YAML serialization/deserialization (via standard adapter)
47
+ * Hash transformation
48
+ * Custom types
49
+ * Model import (`import_model`)
50
+ * Value transformations
51
+
52
+ === Not available
53
+
54
+ [cols="1,3",options="header"]
55
+ |===
56
+ | Feature | Reason
57
+ | XSD schema generation | Requires Nokogiri
58
+ | RELAX NG generation | Requires Nokogiri
59
+ | XML schema compilation | Requires Nokogiri + native parsing
60
+ | TOML serialization | Both tomlib and toml-rb require native extensions
61
+ | Oj / MultiJson adapters | Require native extensions
62
+ | Ox / Nokogiri / Oga adapters | Require native extensions or C extensions
63
+ | XPath queries | REXML XPath requires features not yet in Opal's stdlib
64
+ | Liquid templating | Uses file-system-based template loading (Phase 1: skipped)
65
+ | Canon XML equivalence | Uses Nokogiri for XML parsing
66
+ |===
67
+
68
+ == Setup
69
+
70
+ === Gemfile
71
+
72
+ Add Opal gems to your Gemfile:
73
+
74
+ [source,ruby]
75
+ ----
76
+ gem "lutaml-model"
77
+
78
+ group :opal do
79
+ gem "opal", "~> 1.8"
80
+ gem "opal-rspec", "~> 1.0"
81
+ gem "opal-sprockets"
82
+ end
83
+ ----
84
+
85
+ === Rake task
86
+
87
+ Add an Opal RSpec task to your Rakefile:
88
+
89
+ [source,ruby]
90
+ ----
91
+ begin
92
+ require "opal/rspec/rake_task"
93
+ rescue LoadError
94
+ # Opal not available
95
+ end
96
+
97
+ namespace :spec do
98
+ if defined?(Opal::RSpec::RakeTask)
99
+ desc "Run Opal (JavaScript) tests"
100
+ Opal::RSpec::RakeTask.new(:opal) do |server, runner|
101
+ server.append_path "lib"
102
+ runner.default_path = "spec"
103
+ runner.pattern = "spec/**/*_spec.{rb,opal}"
104
+ end
105
+ end
106
+ end
107
+ ----
108
+
109
+ === Test configuration
110
+
111
+ Create `spec/support/opal.rb` for Opal-specific test patches:
112
+
113
+ [source,ruby]
114
+ ----
115
+ # frozen_string_literal: true
116
+
117
+ if RUBY_ENGINE == "opal"
118
+ Lutaml::Model::Config.xml_adapter_type = :rexml
119
+ end
120
+ ----
121
+
122
+ Create `.rspec-opal`:
123
+
124
+ ----
125
+ --default-path=spec
126
+ --pattern='spec/**/*_spec.{rb,opal}'
127
+ -I lib
128
+ --opal-opt=-g,lutaml-model
129
+ -I spec
130
+ --require=spec_helper
131
+ --require=support/opal
132
+ ----
133
+
134
+ === CI workflow
135
+
136
+ Add `.github/workflows/opal.yml`:
137
+
138
+ [source,yaml]
139
+ ----
140
+ name: opal
141
+ on:
142
+ push:
143
+ branches: [main]
144
+ pull_request:
145
+
146
+ jobs:
147
+ test:
148
+ runs-on: ubuntu-latest
149
+ steps:
150
+ - uses: actions/checkout@v4
151
+ with:
152
+ submodules: "recursive"
153
+ - uses: ruby/setup-ruby@v1
154
+ with:
155
+ ruby-version: "3.3"
156
+ bundler-cache: true
157
+ - uses: actions/setup-node@v4
158
+ with:
159
+ node-version: "18"
160
+ - name: Run Opal tests
161
+ run: bundle exec rake spec:opal
162
+ ----
163
+
164
+ == Example: XML round-trip in the browser
165
+
166
+ [source,ruby]
167
+ ----
168
+ class Person
169
+ include Lutaml::Model::Serialize
170
+
171
+ attribute :name, :string
172
+ attribute :age, :integer
173
+
174
+ xml do
175
+ root "person"
176
+ map_element "name", to: :name
177
+ map_element "age", to: :age
178
+ end
179
+ end
180
+
181
+ # Parse XML
182
+ person = Person.from_xml('<person><name>Alice</name><age>30</age></person>')
183
+ person.name # => "Alice"
184
+ person.age # => 30
185
+
186
+ # Serialize to XML
187
+ person.to_xml # => "<person><name>Alice</name><age>30</age></person>"
188
+
189
+ # JSON and YAML also work
190
+ person.to_json # => '{"name":"Alice","age":30}'
191
+ person.to_yaml # => "---\nname: Alice\nage: 30\n"
192
+ ----
193
+
194
+ == Architecture
195
+
196
+ Under Opal, the library uses a JRuby-like pattern for dependency management:
197
+
198
+ . *Dependencies stay in the gemspec.* Gems like Nokogiri, Ox, and Oga remain listed as dependencies -- they are simply not loadable under Opal.
199
+ . *Requires are guarded with `RUBY_ENGINE`.* Code that depends on native gems uses `RUBY_ENGINE == "opal"` checks instead of silent `rescue LoadError`.
200
+ . *No gem splitting.* The same gem works on both MRI and Opal.
201
+
202
+ Key components:
203
+ * `Lutaml::Model::RuntimeCompatibility` -- detects the runtime (opal, windows, native)
204
+ * `Lutaml::Model::AdapterResolver` -- selects adapters based on runtime capabilities
205
+ * `Moxml::Config::OPAL_DEFAULT_ADAPTER` -- set to `:rexml`
206
+ * `Moxml::Adapter::OPAL_AVAILABLE_ADAPTERS` -- set to `%i[rexml]`
207
+
208
+ == Dependencies
209
+
210
+ The following gems in the lutaml ecosystem support Opal:
211
+
212
+ * **lutaml-model** -- Core model library (this gem)
213
+ * **moxml** (v0.2+) -- XML parsing abstraction with REXML adapter for Opal
214
+ * **canon** -- XML comparison (uses moxml under Opal; comparison features work but Nokogiri-specific features do not)
215
+
216
+ == Limitations
217
+
218
+ * **No XPath** -- REXML's XPath module has dependencies not yet reimplemented in Opal's stdlib.
219
+ * **No schema generation** -- XSD, RELAX NG generation, and schema compilation require Nokogiri.
220
+ * **No TOML** -- Both TOML adapters (tomlib, toml-rb) require native extensions.
221
+ * **No Liquid** -- Template rendering via Liquid is skipped in Opal (file-system dependency). May be addressed in a future phase using liquidjs via Opal's JavaScript bridge.
@@ -723,7 +723,8 @@ end
723
723
 
724
724
  * **Ox**: Fastest, use for performance-critical applications
725
725
  * **Nokogiri**: Most compatible, good balance
726
- * **Oga**: Pure Ruby, works with Opal, use when no native extensions allowed
726
+ * **Oga**: Pure Ruby, use when no native extensions allowed
727
+ * **REXML**: Pure Ruby (bundled with Ruby), Opal-compatible
727
728
 
728
729
  **Configure once:**
729
730
 
@@ -74,7 +74,7 @@ When an adapter is needed for a format, `AdapterResolver` follows this chain:
74
74
  | Pure Ruby. No compilation needed. Opal-compatible.
75
75
 
76
76
  | `:rexml`
77
- | Pure Ruby. Bundled with Ruby (default gem).
77
+ | Pure Ruby. Bundled with Ruby (default gem). Opal-compatible.
78
78
  |===
79
79
 
80
80
  === JSON adapters
@@ -261,8 +261,8 @@ end
261
261
 
262
262
  * **Nokogiri**: Most projects (default, best compatibility)
263
263
  * **Ox**: Performance-critical applications
264
- * **Oga**: Pure Ruby environments, Opal/JavaScript compilation
265
- * **REXML**: No extra gems, pure Ruby (bundled with Ruby)
264
+ * **Oga**: Pure Ruby environments
265
+ * **REXML**: No extra gems, pure Ruby (bundled with Ruby). Also used under Opal.
266
266
 
267
267
  === Choose JSON adapter based on
268
268
 
@@ -279,12 +279,14 @@ end
279
279
 
280
280
  Lutaml::Model supports running under https://opalrb.com[Opal] (Ruby compiled to JavaScript) with some limitations. The library detects the runtime automatically via `Lutaml::Model::RuntimeCompatibility` and adapts its behavior accordingly.
281
281
 
282
+ The XML parsing layer is provided by the https://github.com/lutaml/moxml[moxml] gem, which has been updated to support Opal. Under Opal, moxml uses the REXML adapter because Opal reimplements `strscan` and `stringio` in its stdlib, enabling REXML (pure Ruby) to compile cleanly to JavaScript.
283
+
282
284
  === Adapter defaults on Opal
283
285
 
284
286
  [cols="1,2",options="header"]
285
287
  |===
286
288
  | Format | Behavior
287
- | XML | Only `:oga` is available (auto-selected). Nokogiri, Ox, and REXML require native extensions.
289
+ | XML | Only `:rexml` is available (auto-selected). Opal reimplements strscan/stringio in its stdlib, enabling REXML to compile to JavaScript.
288
290
  | JSON | Only `:standard` is available. Oj and MultiJson require native extensions.
289
291
  | YAML | `:standard` (Psych ships with Opal's stdlib).
290
292
  | TOML | **Not available.** Both tomlib and toml-rb depend on native extensions.
@@ -299,6 +301,9 @@ The following features raise `NotImplementedError` when called under Opal:
299
301
  * `Lutaml::Model::Schema.to_relaxng` -- RELAX NG generation requires Nokogiri
300
302
  * `Lutaml::Model::Schema.from_xml` -- XML schema compilation is not supported
301
303
  * `Lutaml::Xml::Schema::Xsd::Base#to_formatted_xml` -- XSD formatted output requires the Canon gem
304
+ * XPath queries -- REXML XPath requires features not yet supported by Opal's stdlib
305
+
306
+ See the link:../guides/opal[Opal Usage Guide] for complete setup instructions and limitations.
302
307
 
303
308
  == See also
304
309
 
@@ -22,6 +22,7 @@ Fundamental concepts, configuration, and essential features of Lutaml::Model.
22
22
  * link:breaking-changes[Breaking Changes] - Version compatibility
23
23
  * link:comparison-with-shale[Comparison with Shale] - Migration guide
24
24
  * link:xml-conformance[XML Standards Conformance] - W3C spec compliance status
25
+ * link:../guides/opal[Opal Usage] - Run in the browser via Opal
25
26
  * link:troubleshooting[Troubleshooting] - Common issues and solutions
26
27
 
27
28
  == Getting started
@@ -192,8 +192,7 @@ Requires the `nokogiri` gem.
192
192
  Oga::
193
193
  (optional)
194
194
  Pure Ruby XML parser.
195
- Does not require native extensions and is suitable for
196
- https://opalrb.com[Opal] (Ruby on JavaScript).
195
+ Does not require native extensions.
197
196
  Requires the `oga` gem.
198
197
 
199
198
  Ox::
@@ -206,6 +205,8 @@ REXML::
206
205
  (optional)
207
206
  Pure Ruby XML parser, bundled as a default gem with Ruby.
208
207
  Moved from standard library to a default gem in Ruby 3.0.
208
+ Opal-compatible: Opal reimplements `strscan` and `stringio` in its stdlib,
209
+ enabling REXML to compile cleanly to JavaScript.
209
210
  Requires the `rexml` gem (bundled with Ruby by default).
210
211
 
211
212
 
data/docs/index.adoc CHANGED
@@ -19,6 +19,7 @@ Lutaml::Model is a Ruby library for creating information models with attributes
19
19
  * **Multi-format serialization** - XML, JSON, YAML, TOML, JSON-LD, Turtle, Hash, YAML Stream
20
20
  * **XML namespace support** - Full W3C namespace implementation
21
21
  * **Linked Data support** - RDF namespaces, JSON-LD, and Turtle serialization
22
+ * **Opal support** - Run in the browser via Opal (Ruby to JavaScript) with REXML adapter
22
23
  * **Validation** - Built-in validation with custom rules
23
24
  * **Schema generation** - Generate XSD, JSON Schema, YAML Schema
24
25
  * **Polymorphism** - Handle multiple types elegantly
@@ -8,10 +8,8 @@ module Lutaml
8
8
  super(:hash)
9
9
  end
10
10
 
11
- def deep_dup
12
- self.class.new.tap do |new_mapping|
13
- new_mapping.mappings = duplicate_mappings
14
- end
11
+ def dup_instance
12
+ self.class.new
15
13
  end
16
14
  end
17
15
  end
@@ -8,10 +8,8 @@ module Lutaml
8
8
  super(:json)
9
9
  end
10
10
 
11
- def deep_dup
12
- self.class.new.tap do |new_mapping|
13
- new_mapping.mappings = duplicate_mappings
14
- end
11
+ def dup_instance
12
+ self.class.new
15
13
  end
16
14
  end
17
15
  end
@@ -8,10 +8,8 @@ module Lutaml
8
8
  super(:jsonl)
9
9
  end
10
10
 
11
- def deep_dup
12
- self.class.new.tap do |new_mapping|
13
- new_mapping.mappings = duplicate_mappings
14
- end
11
+ def dup_instance
12
+ self.class.new
15
13
  end
16
14
  end
17
15
  end
@@ -7,10 +7,8 @@ module Lutaml
7
7
  super(:hash)
8
8
  end
9
9
 
10
- def deep_dup
11
- self.class.new.tap do |new_mapping|
12
- new_mapping.mappings = duplicate_mappings
13
- end
10
+ def dup_instance
11
+ self.class.new
14
12
  end
15
13
  end
16
14
  end
@@ -12,10 +12,8 @@ module Lutaml
12
12
  super(:json)
13
13
  end
14
14
 
15
- def deep_dup
16
- self.class.new.tap do |new_mapping|
17
- new_mapping.mappings = duplicate_mappings
18
- end
15
+ def dup_instance
16
+ self.class.new
19
17
  end
20
18
  end
21
19
  end
@@ -7,10 +7,8 @@ module Lutaml
7
7
  super(:jsonl)
8
8
  end
9
9
 
10
- def deep_dup
11
- self.class.new.tap do |new_mapping|
12
- new_mapping.mappings = duplicate_mappings
13
- end
10
+ def dup_instance
11
+ self.class.new
14
12
  end
15
13
  end
16
14
  end
@@ -7,10 +7,8 @@ module Lutaml
7
7
  super(:toml)
8
8
  end
9
9
 
10
- def deep_dup
11
- self.class.new.tap do |new_mapping|
12
- new_mapping.mappings = duplicate_mappings
13
- end
10
+ def dup_instance
11
+ self.class.new
14
12
  end
15
13
 
16
14
  def validate!(key, to, with, render_nil, render_empty)
@@ -7,10 +7,8 @@ module Lutaml
7
7
  super(:yaml)
8
8
  end
9
9
 
10
- def deep_dup
11
- self.class.new.tap do |new_mapping|
12
- new_mapping.mappings = duplicate_mappings
13
- end
10
+ def dup_instance
11
+ self.class.new
14
12
  end
15
13
  end
16
14
  end
@@ -7,10 +7,8 @@ module Lutaml
7
7
  super(:yaml)
8
8
  end
9
9
 
10
- def deep_dup
11
- self.class.new.tap do |new_mapping|
12
- new_mapping.mappings = duplicate_mappings
13
- end
10
+ def dup_instance
11
+ self.class.new
14
12
  end
15
13
  end
16
14
  end