lutaml-model 0.8.11 → 0.8.13

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 (149) 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 +126 -104
  6. data/RELEASE_NOTES.adoc +3 -3
  7. data/benchmark/quick_benchmark.rb +2 -2
  8. data/benchmark/serialization_benchmark.rb +4 -4
  9. data/docs/_guides/advanced-mapping.adoc +1 -1
  10. data/docs/_guides/character-encoding.adoc +3 -3
  11. data/docs/_guides/index.adoc +4 -0
  12. data/docs/_guides/missing-values-handling.adoc +6 -6
  13. data/docs/_guides/ooxml-examples.adoc +7 -7
  14. data/docs/_guides/opal.adoc +221 -0
  15. data/docs/_guides/value-transformations.adoc +7 -7
  16. data/docs/_guides/xml/namespace-presentation.adoc +1 -1
  17. data/docs/_guides/xml/namespace-semantics.adoc +15 -15
  18. data/docs/_guides/xml/type-namespaces.adoc +9 -9
  19. data/docs/_guides/xml-mapping.adoc +32 -26
  20. data/docs/_guides/xml-namespace-qualification.adoc +4 -4
  21. data/docs/_guides/xml-namespaces.adoc +2 -2
  22. data/docs/_guides/xml_mappings/04_xml_namespace_class.adoc +18 -18
  23. data/docs/_guides/xml_mappings/05_common_patterns.adoc +16 -16
  24. data/docs/_guides/xml_mappings/06_migration_guide.adoc +5 -5
  25. data/docs/_guides/xml_mappings/07_best_practices.adoc +13 -12
  26. data/docs/_migrations/0-8-0-namespace-restructuring.adoc +2 -2
  27. data/docs/_pages/attributes.adoc +2 -2
  28. data/docs/_pages/collections.adoc +26 -20
  29. data/docs/_pages/configuration.adoc +9 -4
  30. data/docs/_pages/consolidation-mapping.adoc +4 -4
  31. data/docs/_pages/importable_models.adoc +14 -13
  32. data/docs/_pages/index.adoc +1 -0
  33. data/docs/_pages/quick-start.adoc +1 -1
  34. data/docs/_pages/serialization_adapters.adoc +3 -2
  35. data/docs/_pages/value_types.adoc +10 -10
  36. data/docs/_references/custom_registers.adoc +7 -7
  37. data/docs/_references/format-independent-features.adoc +4 -4
  38. data/docs/_references/instance-serialization.adoc +1 -1
  39. data/docs/_references/parent-root-context.adoc +3 -3
  40. data/docs/_tutorials/basic-model-definition.adoc +1 -1
  41. data/docs/_tutorials/first-xml-serialization.adoc +4 -4
  42. data/docs/_tutorials/lutaml-xml-architecture.adoc +4 -4
  43. data/docs/_tutorials/validation-basics.adoc +1 -1
  44. data/docs/_tutorials/working-with-collections.adoc +2 -2
  45. data/docs/_tutorials/xml-namespaces-basics.adoc +1 -1
  46. data/docs/_tutorials/xml-schema-primer-style-guide.adoc +29 -29
  47. data/docs/cli_compare.adoc +1 -1
  48. data/docs/index.adoc +2 -1
  49. data/docs/namespace-management.adoc +14 -14
  50. data/lib/lutaml/hash_format/adapter/mapping.rb +2 -4
  51. data/lib/lutaml/json/adapter/mapping.rb +2 -4
  52. data/lib/lutaml/jsonl/adapter/mapping.rb +2 -4
  53. data/lib/lutaml/key_value/adapter/hash/mapping.rb +2 -4
  54. data/lib/lutaml/key_value/adapter/json/mapping.rb +2 -4
  55. data/lib/lutaml/key_value/adapter/jsonl/mapping.rb +2 -4
  56. data/lib/lutaml/key_value/adapter/toml/mapping.rb +2 -4
  57. data/lib/lutaml/key_value/adapter/yaml/mapping.rb +2 -4
  58. data/lib/lutaml/key_value/adapter/yamls/mapping.rb +2 -4
  59. data/lib/lutaml/key_value/mapping.rb +35 -10
  60. data/lib/lutaml/model/adapter_resolver.rb +5 -8
  61. data/lib/lutaml/model/collection.rb +11 -11
  62. data/lib/lutaml/model/error/no_root_mapping_error.rb +6 -5
  63. data/lib/lutaml/model/error/no_root_namespace_error.rb +6 -5
  64. data/lib/lutaml/model/error/type_only_mapping_error.rb +13 -0
  65. data/lib/lutaml/model/error/type_only_namespace_error.rb +12 -0
  66. data/lib/lutaml/model/mapping/mapping.rb +12 -0
  67. data/lib/lutaml/model/version.rb +1 -1
  68. data/lib/lutaml/model.rb +3 -0
  69. data/lib/lutaml/toml/adapter/mapping.rb +2 -4
  70. data/lib/lutaml/xml/adapter/base_adapter.rb +0 -9
  71. data/lib/lutaml/xml/adapter/nokogiri_adapter.rb +0 -1
  72. data/lib/lutaml/xml/adapter/oga_adapter.rb +0 -1
  73. data/lib/lutaml/xml/adapter/ox_adapter.rb +0 -1
  74. data/lib/lutaml/xml/adapter/rexml_adapter.rb +0 -1
  75. data/lib/lutaml/xml/adapter/xml_serializer.rb +42 -22
  76. data/lib/lutaml/xml/adapter.rb +4 -0
  77. data/lib/lutaml/xml/builder/base.rb +64 -25
  78. data/lib/lutaml/xml/builder/nokogiri.rb +0 -2
  79. data/lib/lutaml/xml/builder/oga.rb +0 -2
  80. data/lib/lutaml/xml/builder/ox.rb +0 -2
  81. data/lib/lutaml/xml/builder/rexml.rb +0 -2
  82. data/lib/lutaml/xml/builder.rb +1 -0
  83. data/lib/lutaml/xml/configurable.rb +2 -2
  84. data/lib/lutaml/xml/declaration_handler.rb +3 -105
  85. data/lib/lutaml/xml/mapping.rb +3 -3
  86. data/lib/lutaml/xml/schema/xsd/documentation.rb +1 -1
  87. data/lib/lutaml/xml/schema/xsd.rb +5 -4
  88. data/lib/lutaml/xml/schema.rb +8 -5
  89. data/lib/lutaml/xml/serialization/collection_ext.rb +7 -7
  90. data/lib/lutaml/xml/serialization/format_conversion.rb +1 -1
  91. data/lib/lutaml/xml/serialization/instance_methods.rb +1 -1
  92. data/lib/lutaml/xml/xml_orderable.rb +17 -0
  93. data/lib/lutaml/xml.rb +9 -13
  94. data/lib/lutaml/yaml/adapter/mapping.rb +2 -4
  95. data/lib/lutaml/yamls/adapter/mapping.rb +7 -3
  96. data/lib/tasks/memory_profile.rb +2 -2
  97. data/lib/tasks/performance_benchmark.rb +5 -5
  98. data/lutaml-model.gemspec +1 -1
  99. data/spec/lutaml/key_value/transformation/rule_compiler_spec.rb +1 -1
  100. data/spec/lutaml/key_value/transformation/value_serializer_spec.rb +1 -1
  101. data/spec/lutaml/model/attribute_collection_spec.rb +1 -1
  102. data/spec/lutaml/model/cli_spec.rb +1 -1
  103. data/spec/lutaml/model/collection_spec.rb +1 -1
  104. data/spec/lutaml/model/collection_validation_spec.rb +6 -6
  105. data/spec/lutaml/model/consolidation_spec.rb +8 -8
  106. data/spec/lutaml/model/custom_collection_spec.rb +3 -3
  107. data/spec/lutaml/model/default_register_spec.rb +23 -23
  108. data/spec/lutaml/model/delegation_spec.rb +3 -10
  109. data/spec/lutaml/model/derived_attribute_serialization_spec.rb +1 -1
  110. data/spec/lutaml/model/dynamic_attribute_spec.rb +2 -2
  111. data/spec/lutaml/model/enum_spec.rb +1 -1
  112. data/spec/lutaml/model/group_spec.rb +12 -12
  113. data/spec/lutaml/model/lazy_collection_spec.rb +4 -4
  114. data/spec/lutaml/model/mixed_content_spec.rb +2 -2
  115. data/spec/lutaml/model/namespace_versioning_spec.rb +4 -4
  116. data/spec/lutaml/model/opal_smoke_spec.rb +117 -0
  117. data/spec/lutaml/model/processing_instruction_spec.rb +11 -11
  118. data/spec/lutaml/model/register_methods_spec.rb +2 -2
  119. data/spec/lutaml/model/render_empty_spec.rb +1 -1
  120. data/spec/lutaml/model/serialize_perf_guard_spec.rb +1 -1
  121. data/spec/lutaml/model/transform_dynamic_attributes_spec.rb +1 -1
  122. data/spec/lutaml/model/transformation_builder_spec.rb +2 -2
  123. data/spec/lutaml/model/xml_decoupling_spec.rb +3 -3
  124. data/spec/lutaml/model/xsd_patterns_spec.rb +2 -3
  125. data/spec/lutaml/xml/adapter/order_spec.rb +1 -1
  126. data/spec/lutaml/xml/clear_parse_state_spec.rb +1 -1
  127. data/spec/lutaml/xml/content_model_validation_spec.rb +4 -2
  128. data/spec/lutaml/xml/doubly_defined_namespace_spec.rb +5 -5
  129. data/spec/lutaml/xml/enhanced_mapping_spec.rb +2 -1
  130. data/spec/lutaml/xml/entity_fragmentation_spec.rb +5 -5
  131. data/spec/lutaml/xml/indent_spec.rb +109 -0
  132. data/spec/lutaml/xml/line_ending_spec.rb +66 -0
  133. data/spec/lutaml/xml/mapping_finalization_guard_spec.rb +2 -2
  134. data/spec/lutaml/xml/model_transform_guard_spec.rb +4 -4
  135. data/spec/lutaml/xml/namespace_alias_spec.rb +4 -4
  136. data/spec/lutaml/xml/namespace_aware_parsing_spec.rb +3 -3
  137. data/spec/lutaml/xml/namespace_bound_element_roundtrip_spec.rb +2 -2
  138. data/spec/lutaml/xml/namespace_format_preservation_spec.rb +1 -1
  139. data/spec/lutaml/xml/namespace_inheritance_spec.rb +3 -3
  140. data/spec/lutaml/xml/namespace_preservation_spec.rb +5 -5
  141. data/spec/lutaml/xml/opal_xml_spec.rb +145 -0
  142. data/spec/lutaml/xml/pipeline_integration_spec.rb +145 -0
  143. data/spec/lutaml/xml/schema_primer_spec.rb +5 -5
  144. data/spec/lutaml/xml/transformation_spec.rb +20 -20
  145. data/spec/lutaml/xml/type_namespace/collector_spec.rb +1 -1
  146. data/spec/lutaml/xml/type_namespace/planner_spec.rb +3 -3
  147. data/spec/lutaml/xml/xml_spec.rb +64 -13
  148. data/spec/support/opal.rb +6 -0
  149. metadata +16 -4
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "base"
4
-
5
3
  module Lutaml
6
4
  module Xml
7
5
  module Builder
@@ -4,6 +4,7 @@ module Lutaml
4
4
  module Xml
5
5
  # Builder module for XML generation
6
6
  module Builder
7
+ autoload :Base, "#{__dir__}/builder/base"
7
8
  autoload :Oga, "#{__dir__}/builder/oga"
8
9
  Lutaml::Model::RuntimeCompatibility.autoload_native(
9
10
  self,
@@ -13,7 +13,7 @@ module Lutaml
13
13
  # include Lutaml::Xml::Configurable
14
14
  #
15
15
  # xml do
16
- # root 'MyModel'
16
+ # element "MyModel"
17
17
  # namespace MyNamespace
18
18
  # end
19
19
  # end
@@ -51,7 +51,7 @@ module Lutaml
51
51
  #
52
52
  # @example Configuration with block
53
53
  # xml do
54
- # root 'MyModel'
54
+ # element "MyModel"
55
55
  # namespace MyNamespace
56
56
  # map_element 'name', to: :name
57
57
  # end
@@ -1,10 +1,9 @@
1
1
  module Lutaml
2
2
  module Xml
3
- # DeclarationHandler provides XML declaration and DOCTYPE handling
4
- # for all XML adapter implementations.
3
+ # DeclarationHandler provides XML declaration extraction from input XML.
5
4
  #
6
- # This module implements Issue #1: XML Declaration Preservation
7
- # across Nokogiri, Oga, and Ox adapters.
5
+ # Extraction methods detect and parse XML declarations from input strings.
6
+ # Generation is handled by moxml's document model — no manual string assembly.
8
7
  module DeclarationHandler
9
8
  # Extract XML declaration information from input string
10
9
  #
@@ -92,126 +91,25 @@ module Lutaml
92
91
  # @param xml_declaration [Hash] extracted declaration info from input
93
92
  # @return [Boolean] true if declaration should be included
94
93
  def should_include_declaration?(options, xml_declaration = nil)
95
- # Use instance variable if not provided (for adapter instance methods)
96
94
  xml_declaration ||= @xml_declaration
97
95
 
98
96
  if options.key?(:declaration)
99
97
  case options[:declaration]
100
98
  when false
101
- # Explicit false: omit declaration
102
99
  false
103
100
  when true
104
- # Explicit true: force include
105
101
  true
106
102
  when :preserve
107
- # Preserve mode: include if input had one
108
103
  xml_declaration&.dig(:had_declaration) || false
109
104
  when String
110
- # Custom version string: include
111
105
  true
112
106
  else
113
- # Default: preserve from input
114
107
  xml_declaration&.dig(:had_declaration) || false
115
108
  end
116
109
  else
117
- # No declaration option provided: default behavior is preserve from input
118
110
  xml_declaration&.dig(:had_declaration) || false
119
111
  end
120
112
  end
121
-
122
- # Generate XML declaration string
123
- #
124
- # Uses stored declaration info if available, otherwise uses defaults.
125
- # Supports custom version strings, encoding, and standalone options.
126
- #
127
- # @param options [Hash] serialization options
128
- # - :declaration => String for custom version, true for default
129
- # - :encoding => String or true for UTF-8
130
- # - :standalone => String ("yes"/"no"), true ("yes"), false ("no"), :preserve
131
- # @param xml_declaration [Hash] extracted declaration info from input
132
- # @return [String] the XML declaration (includes trailing newline)
133
- def generate_declaration(options, xml_declaration = nil)
134
- # Use instance variable if not provided (for adapter instance methods)
135
- xml_declaration ||= @xml_declaration
136
-
137
- # Determine version
138
- # When declaration: true (force), use default 1.0 not input version
139
- # When declaration: "1.x" (custom), use that string
140
- # When preserving (no option or :preserve), use input version or default
141
- version = if options[:declaration].is_a?(String)
142
- # Custom version string
143
- options[:declaration]
144
- elsif options[:declaration] == true
145
- # Force with default version
146
- "1.0"
147
- elsif xml_declaration&.dig(:version)
148
- # Preserve from input
149
- xml_declaration[:version]
150
- else
151
- # Default fallback
152
- "1.0"
153
- end
154
-
155
- # Determine encoding
156
- # Priority: explicit encoding option > input encoding > none
157
- encoding = if options[:encoding].is_a?(String)
158
- options[:encoding]
159
- elsif options[:encoding] == true
160
- "UTF-8"
161
- elsif xml_declaration&.dig(:encoding)
162
- xml_declaration[:encoding]
163
- end
164
-
165
- # Determine standalone
166
- # Priority: explicit standalone option > input standalone > none
167
- # Supported values: "yes", "no", true ("yes"), false ("no"), :preserve
168
- standalone = if options.key?(:standalone)
169
- case options[:standalone]
170
- when String
171
- options[:standalone]
172
- when true
173
- "yes"
174
- when false
175
- "no"
176
- when :preserve
177
- xml_declaration&.dig(:standalone)
178
- end
179
- elsif xml_declaration&.dig(:standalone)
180
- xml_declaration[:standalone]
181
- end
182
-
183
- declaration = "<?xml version=\"#{version}\""
184
- declaration += " encoding=\"#{encoding}\"" if encoding
185
- declaration += " standalone=\"#{standalone}\"" if standalone
186
- declaration += "?>\n"
187
- declaration
188
- end
189
-
190
- # Generate DOCTYPE declaration from doctype hash
191
- #
192
- # Supports both PUBLIC and SYSTEM DTDs.
193
- # Format: <!DOCTYPE name PUBLIC "public_id" "system_id">
194
- # <!DOCTYPE name SYSTEM "system_id">
195
- #
196
- # @param doctype [Hash] the doctype information
197
- # - :name => root element name
198
- # - :public_id => public identifier (optional)
199
- # - :system_id => system identifier (optional)
200
- # @return [String, nil] the DOCTYPE declaration or nil if no doctype
201
- def generate_doctype_declaration(doctype)
202
- return nil unless doctype
203
-
204
- parts = ["<!DOCTYPE #{doctype[:name]}"]
205
-
206
- if doctype[:public_id]
207
- parts << %(PUBLIC "#{doctype[:public_id]}")
208
- parts << %("#{doctype[:system_id]}") if doctype[:system_id]
209
- elsif doctype[:system_id]
210
- parts << %(SYSTEM "#{doctype[:system_id]}")
211
- end
212
-
213
- "#{parts.join(' ')}>\n"
214
- end
215
113
  end
216
114
  end
217
115
  end
@@ -350,11 +350,11 @@ module Lutaml
350
350
  # namespace :blank
351
351
  #
352
352
  # @raise [ArgumentError] if invalid arguments provided
353
- # @raise [Lutaml::Model::NoRootNamespaceError] if explicitly marked as no_root
353
+ # @raise [Lutaml::Model::TypeOnlyNamespaceError] if explicitly marked as no_root
354
354
  def namespace(ns_class_or_symbol, _deprecated_prefix = nil)
355
355
  # Only raise error for explicitly marked no_root (using deprecated method)
356
356
  # Type-only models (no element declared) CAN have namespaces
357
- raise Lutaml::Model::NoRootNamespaceError if @no_root
357
+ raise Lutaml::Model::TypeOnlyNamespaceError if @no_root
358
358
 
359
359
  # Warn if prefix parameter is provided
360
360
  if _deprecated_prefix
@@ -784,7 +784,7 @@ module Lutaml
784
784
  #
785
785
  # @example
786
786
  # xml do
787
- # root "rfc"
787
+ # element "rfc"
788
788
  # map_processing_instruction "rfc", to: :pi_settings
789
789
  # end
790
790
  #
@@ -10,7 +10,7 @@ module Lutaml
10
10
  attribute :content, :string
11
11
 
12
12
  xml do
13
- root "documentation"
13
+ element "documentation"
14
14
  namespace Lutaml::Xml::Schema::XsdNamespace
15
15
 
16
16
  map_all to: :content
@@ -2,11 +2,12 @@
2
2
 
3
3
  # NOTE: Do NOT require lutaml/model here. This file is autoloaded via
4
4
  # Lutaml::Xml::Schema::Xsd, and requiring lutaml/model creates a circular
5
- # dependency since lutaml/xml.rb requires lutaml/model. The adapter type
6
- # is already set by lutaml/xml.rb at the end.
5
+ # dependency since lutaml/xml.rb requires lutaml/model. This file only sets
6
+ # a fallback XML adapter when no adapter has been selected yet.
7
7
 
8
- adapter = RUBY_ENGINE == "opal" ? :oga : :nokogiri
9
- Lutaml::Model::Config.xml_adapter_type = adapter unless defined?(Lutaml::Model::Config.xml_adapter_type)
8
+ unless defined?(Lutaml::Model::Config.xml_adapter_type)
9
+ Lutaml::Model::Config.xml_adapter_type = Lutaml::Model::AdapterResolver.detect_xml_adapter
10
+ end
10
11
 
11
12
  # Require the XsdNamespace class for XSD schema support
12
13
  require_relative "xsd_namespace"
@@ -3,11 +3,14 @@
3
3
  module Lutaml
4
4
  module Xml
5
5
  module Schema
6
- autoload :Xsd, "#{__dir__}/schema/xsd"
7
- autoload :XsdSchema, "#{__dir__}/schema/xsd_schema"
8
- autoload :RelaxngSchema, "#{__dir__}/schema/relaxng_schema"
9
- autoload :Builder, "#{__dir__}/schema/builder"
10
- autoload :BuiltinTypes, "#{__dir__}/schema/builtin_types"
6
+ Lutaml::Model::RuntimeCompatibility.autoload_native(
7
+ self,
8
+ Xsd: "#{__dir__}/schema/xsd",
9
+ XsdSchema: "#{__dir__}/schema/xsd_schema",
10
+ RelaxngSchema: "#{__dir__}/schema/relaxng_schema",
11
+ Builder: "#{__dir__}/schema/builder",
12
+ BuiltinTypes: "#{__dir__}/schema/builtin_types",
13
+ )
11
14
  end
12
15
  end
13
16
  end
@@ -6,7 +6,7 @@ module Lutaml
6
6
  # XML-specific overrides for Collection class methods.
7
7
  #
8
8
  # Prepended into Collection's singleton class when XML is loaded.
9
- # Provides XML-specific no_root handling for collections.
9
+ # Provides XML-specific unwrapped collection handling.
10
10
  module CollectionExt
11
11
  # XML is a structured (tree-based) format
12
12
  def collection_structured_format?(format)
@@ -15,15 +15,15 @@ module Lutaml
15
15
  true
16
16
  end
17
17
 
18
- # XML handles no_root serialization specially
19
- def collection_no_root_to?(format)
18
+ # XML handles unwrapped serialization specially
19
+ def collection_unwrapped_to?(format)
20
20
  return super unless format == :xml
21
21
 
22
22
  true
23
23
  end
24
24
 
25
- # XML no_root serialization: serialize each mapping separately
26
- def collection_no_root_to(format, mappings, instance, options)
25
+ # XML unwrapped serialization: serialize each mapping separately
26
+ def collection_unwrapped_to(format, mappings, instance, options)
27
27
  return super unless format == :xml
28
28
 
29
29
  mappings.mappings.map do |mapping|
@@ -31,8 +31,8 @@ module Lutaml
31
31
  end.join("\n")
32
32
  end
33
33
 
34
- # XML no_root: wrap raw XML in a fake root tag before parsing
35
- def wrap_no_root_input(format, mappings, data)
34
+ # XML unwrapped: wrap raw XML in a fake root tag before parsing
35
+ def wrap_unwrapped_input(format, mappings, data)
36
36
  return super unless format == :xml
37
37
 
38
38
  tag_name = mappings.find_by_to!(instance_name).name
@@ -94,7 +94,7 @@ module Lutaml
94
94
  return super unless format == :xml
95
95
 
96
96
  valid = root?(register) || options[:from_collection]
97
- raise Lutaml::Model::NoRootMappingError.new(self) unless valid
97
+ raise Lutaml::Model::TypeOnlyMappingError.new(self) unless valid
98
98
 
99
99
  options[:encoding] = doc.encoding
100
100
  if doc.is_a?(Lutaml::Xml::Document) && doc.doctype
@@ -204,7 +204,7 @@ module Lutaml
204
204
  return super unless format == :xml
205
205
  return if options[:collection] || self.class.root?(lutaml_register)
206
206
 
207
- raise Lutaml::Model::NoRootMappingError.new(self.class)
207
+ raise Lutaml::Model::TypeOnlyMappingError.new(self.class)
208
208
  end
209
209
 
210
210
  # XML-specific instance options preparation
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Xml
5
+ # Mixin for XML element/attribute ordering state.
6
+ #
7
+ # Included by:
8
+ # - Lutaml::Xml::Serialization::InstanceMethods (Serialize instances)
9
+ # - Plain model classes via add_format_specific_model_methods
10
+ #
11
+ # Enables Lutaml::Model to check ordering capability with is_a? instead
12
+ # of respond_to?, following proper OOP type-checking.
13
+ module XmlOrderable
14
+ attr_accessor :element_order, :attribute_order, :ordered, :mixed
15
+ end
16
+ end
17
+ end
data/lib/lutaml/xml.rb CHANGED
@@ -42,16 +42,13 @@ module Lutaml
42
42
  # XML Schema modules
43
43
  autoload :Schema, "#{__dir__}/xml/schema"
44
44
 
45
- # Detect available XML adapter
46
- # @return [Symbol, nil] :nokogiri, :ox, :oga, :rexml, or nil
45
+ # Detect available XML adapter.
46
+ # Delegates to moxml, which is the authority on XML adapter
47
+ # availability and platform constraints.
48
+ #
49
+ # @return [Symbol] adapter type name
47
50
  def self.detect_xml_adapter
48
- return :oga if Lutaml::Model::RuntimeCompatibility.opal?
49
- return :nokogiri if Lutaml::Model::Utils.safe_load("nokogiri", :Nokogiri)
50
- return :ox if Lutaml::Model::Utils.safe_load("ox", :Ox)
51
- return :oga if Lutaml::Model::Utils.safe_load("oga", :Oga)
52
- return :rexml if Lutaml::Model::Utils.safe_load("rexml", :REXML)
53
-
54
- nil
51
+ Moxml::Config.runtime_default_adapter
55
52
  end
56
53
 
57
54
  # Get the current XML adapter
@@ -137,7 +134,6 @@ module Lutaml
137
134
  autoload :ElementPrefixResolver, "#{__dir__}/xml/element_prefix_resolver"
138
135
  autoload :FormatChooser, "#{__dir__}/xml/format_chooser"
139
136
  autoload :HoistingAlgorithm, "#{__dir__}/xml/hoisting_algorithm"
140
- autoload :HoistingAlgorithm, "#{__dir__}/xml/hoisting_algorithm"
141
137
  autoload :NamespaceInheritanceResolver,
142
138
  "#{__dir__}/xml/namespace_inheritance_resolver"
143
139
  autoload :NamespaceScopeConfig, "#{__dir__}/xml/namespace_scope_config"
@@ -174,8 +170,8 @@ Lutaml::Model::FormatRegistry.register(
174
170
  ],
175
171
  adapter_options: if Lutaml::Model::RuntimeCompatibility.opal?
176
172
  {
177
- available: %i[oga],
178
- default: :oga,
173
+ available: %i[rexml],
174
+ default: :rexml,
179
175
  }
180
176
  else
181
177
  {
@@ -232,7 +228,7 @@ end
232
228
  Lutaml::Model::Attribute.format_specific_warn_names.push(:element_order,
233
229
  :schema_location, :encoding, :doctype, :ordered?, :mixed?)
234
230
 
235
- # Prepend XML-specific Collection overrides (no_root handling for XML)
231
+ # Prepend XML-specific Collection overrides (unwrapped collection handling for XML)
236
232
  require_relative "xml/serialization/collection_ext"
237
233
  Lutaml::Model::Collection.singleton_class.prepend(
238
234
  Lutaml::Xml::Serialization::CollectionExt,
@@ -8,10 +8,8 @@ module Lutaml
8
8
  super(:yaml)
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
@@ -4,7 +4,7 @@ module Lutaml
4
4
  module Yamls
5
5
  module Adapter
6
6
  class Mapping < Lutaml::KeyValue::Mapping
7
- attr_reader :yamls_sequence
7
+ attr_accessor :yamls_sequence
8
8
 
9
9
  def initialize
10
10
  super(:yaml)
@@ -15,9 +15,13 @@ module Lutaml
15
15
  @yamls_sequence.instance_eval(&)
16
16
  end
17
17
 
18
+ def dup_instance
19
+ self.class.new
20
+ end
21
+
18
22
  def deep_dup
19
- self.class.new.tap do |new_mapping|
20
- new_mapping.mappings = duplicate_mappings
23
+ super.tap do |new_mapping|
24
+ new_mapping.yamls_sequence = @yamls_sequence&.dup
21
25
  end
22
26
  end
23
27
  end
@@ -18,7 +18,7 @@ class Address < Lutaml::Model::Serializable
18
18
  attribute :country, :string
19
19
 
20
20
  xml do
21
- root "address"
21
+ element "address"
22
22
  map_element "street", to: :street
23
23
  map_element "city", to: :city
24
24
  map_element "zip", to: :zip
@@ -37,7 +37,7 @@ class Person < Lutaml::Model::Serializable
37
37
  attribute :tags, :string, collection: true
38
38
 
39
39
  xml do
40
- root "person"
40
+ element "person"
41
41
  map_attribute "id", to: :id
42
42
  map_element "first_name", to: :first_name
43
43
  map_element "last_name", to: :last_name
@@ -21,7 +21,7 @@ module Lutaml
21
21
  attribute :created_at, :date_time
22
22
 
23
23
  xml do
24
- root "simple"
24
+ element "simple"
25
25
  map_attribute "id", to: :id
26
26
  map_element "name", to: :name
27
27
  map_element "active", to: :active
@@ -46,7 +46,7 @@ module Lutaml
46
46
  attribute :country, :string
47
47
 
48
48
  xml do
49
- root "address"
49
+ element "address"
50
50
  map_element "street", to: :street
51
51
  map_element "city", to: :city
52
52
  map_element "zip", to: :zip
@@ -73,7 +73,7 @@ module Lutaml
73
73
  attribute :tags, :string, collection: true
74
74
 
75
75
  xml do
76
- root "person"
76
+ element "person"
77
77
  map_attribute "id", to: :id
78
78
  map_element "first_name", to: :first_name
79
79
  map_element "last_name", to: :last_name
@@ -103,7 +103,7 @@ module Lutaml
103
103
  attribute :price, :float
104
104
 
105
105
  xml do
106
- root "item"
106
+ element "item"
107
107
  map_attribute "product_id", to: :product_id
108
108
  map_element "quantity", to: :quantity
109
109
  map_element "price", to: :price
@@ -118,7 +118,7 @@ module Lutaml
118
118
  attribute :status, :string
119
119
 
120
120
  xml do
121
- root "order"
121
+ element "order"
122
122
  map_attribute "id", to: :id
123
123
  map_element "customer", to: :customer
124
124
  map_element "item", to: :items
data/lutaml-model.gemspec CHANGED
@@ -36,7 +36,7 @@ Gem::Specification.new do |spec|
36
36
  spec.add_dependency "canon"
37
37
  spec.add_dependency "concurrent-ruby"
38
38
  spec.add_dependency "liquid", ">= 4.0", "< 6.0"
39
- spec.add_dependency "moxml", ">= 0.1.20"
39
+ spec.add_dependency "moxml", ">= 0.1.22"
40
40
  spec.add_dependency "ostruct"
41
41
  spec.add_dependency "rubyzip", "~> 2.3"
42
42
  spec.add_dependency "thor"
@@ -14,7 +14,7 @@ RSpec.describe Lutaml::KeyValue::Transformation::RuleCompiler do
14
14
  attribute :active, :boolean
15
15
 
16
16
  json do
17
- root "person"
17
+ key "person"
18
18
  map "name", to: :name
19
19
  map "age", to: :age
20
20
  map "active", to: :active
@@ -91,7 +91,7 @@ RSpec.describe Lutaml::KeyValue::Transformation::ValueSerializer do
91
91
  Class.new(Lutaml::Model::Serializable) do
92
92
  attribute :name, :string
93
93
  json do
94
- root "nested"
94
+ key "nested"
95
95
  map "name", to: :name
96
96
  end
97
97
  end
@@ -19,7 +19,7 @@ module AttributeCollection
19
19
  end
20
20
 
21
21
  key_value do
22
- root "titles"
22
+ key "titles"
23
23
  map_instances to: :title_parts
24
24
  end
25
25
 
@@ -33,7 +33,7 @@ RSpec.describe Lutaml::Model::Cli do
33
33
  attribute :extract_language, ExtractLanguage, collection: true
34
34
 
35
35
  xml do
36
- root "termium_extract"
36
+ element "termium_extract"
37
37
  namespace TermiumNamespace
38
38
 
39
39
  map_attribute "language", to: :language, namespace: nil
@@ -156,7 +156,7 @@ class PolyAnimalCollectionAny < Lutaml::Model::Collection
156
156
  end
157
157
 
158
158
  key_value do
159
- root "zoo"
159
+ key "zoo"
160
160
  map_instances to: :animals, polymorphic: {
161
161
  attribute: "type",
162
162
  class_map: {
@@ -10,7 +10,7 @@ module CollectionValidationTests
10
10
  attribute :category, :string
11
11
 
12
12
  xml do
13
- root "publication"
13
+ element "publication"
14
14
  map_attribute "id", to: :id
15
15
  map_element "title", to: :title
16
16
  map_element "year", to: :year
@@ -33,7 +33,7 @@ module CollectionValidationTests
33
33
  validates_uniqueness_of :id, message: "Publication IDs must be unique"
34
34
 
35
35
  xml do
36
- root "publications"
36
+ element "publications"
37
37
  map_element "publication", to: :publications
38
38
  end
39
39
 
@@ -49,7 +49,7 @@ module CollectionValidationTests
49
49
  validates_max_count 5, message: "Cannot have more than 5 publications"
50
50
 
51
51
  xml do
52
- root "publications"
52
+ element "publications"
53
53
  map_element "publication", to: :publications
54
54
  end
55
55
 
@@ -66,7 +66,7 @@ module CollectionValidationTests
66
66
  validates_all_present :year, message: "All publications must have a year"
67
67
 
68
68
  xml do
69
- root "publications"
69
+ element "publications"
70
70
  map_element "publication", to: :publications
71
71
  end
72
72
 
@@ -102,7 +102,7 @@ module CollectionValidationTests
102
102
  end
103
103
 
104
104
  xml do
105
- root "publications"
105
+ element "publications"
106
106
  map_element "publication", to: :publications
107
107
  end
108
108
 
@@ -122,7 +122,7 @@ module CollectionValidationTests
122
122
  validates_min_count 1 # Collection-level validation
123
123
 
124
124
  xml do
125
- root "publications"
125
+ element "publications"
126
126
  map_element "publication", to: :publications
127
127
  end
128
128
 
@@ -18,7 +18,7 @@ RSpec.describe "Consolidation Mapping" do
18
18
  attribute :content, :string
19
19
 
20
20
  xml do
21
- root "title"
21
+ element "title"
22
22
  map_attribute "lang", to: :lang
23
23
  map_attribute "type", to: :type_of_title
24
24
  map_content to: :content
@@ -40,7 +40,7 @@ RSpec.describe "Consolidation Mapping" do
40
40
  organizes :per_lang, ConPerLangGroup
41
41
 
42
42
  xml do
43
- root "titles"
43
+ element "titles"
44
44
  map_instances to: :items
45
45
  consolidate_map by: :lang, to: :per_lang do
46
46
  gather :lang, to: :lang
@@ -59,7 +59,7 @@ RSpec.describe "Consolidation Mapping" do
59
59
  attribute :titles, ConTitle, collection: ConTitleCollection
60
60
 
61
61
  xml do
62
- root "bibdata"
62
+ element "bibdata"
63
63
  map_element "title", to: :titles
64
64
  end
65
65
  end)
@@ -141,7 +141,7 @@ RSpec.describe "Consolidation Mapping" do
141
141
  attribute :content, :string
142
142
 
143
143
  xml do
144
- root "title"
144
+ element "title"
145
145
  map_attribute "lang", to: :lang
146
146
  map_attribute "type", to: :type_of_title
147
147
  map_content to: :content
@@ -159,7 +159,7 @@ RSpec.describe "Consolidation Mapping" do
159
159
  organizes :per_type, ConPerTypeGroup
160
160
 
161
161
  xml do
162
- root "titles"
162
+ element "titles"
163
163
  map_instances to: :items
164
164
  consolidate_map by: :type_of_title, to: :per_type do
165
165
  gather :type_of_title, to: :type_of_title
@@ -175,7 +175,7 @@ RSpec.describe "Consolidation Mapping" do
175
175
  attribute :titles, ConTitle2, collection: ConTitleCollection2
176
176
 
177
177
  xml do
178
- root "bibdata"
178
+ element "bibdata"
179
179
  map_element "title", to: :titles
180
180
  end
181
181
  end)
@@ -247,7 +247,7 @@ RSpec.describe "Consolidation Mapping" do
247
247
  organizes :entries, group_class
248
248
 
249
249
  xml do
250
- root "test"
250
+ element "test"
251
251
  consolidate_map by: :lang, to: :entries do
252
252
  gather :lang, to: :lang
253
253
  dispatch_by :type do
@@ -276,7 +276,7 @@ RSpec.describe "Consolidation Mapping" do
276
276
  organizes :entries, entry_class
277
277
 
278
278
  xml do
279
- root "test"
279
+ element "test"
280
280
  consolidate_map by: :pattern, to: :entries do
281
281
  map_element "member", to: :name
282
282
  map_element "member_key", to: :key