lutaml-model 0.8.87 → 0.8.88
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.
- checksums.yaml +4 -4
- data/bench/bench_common.rb +1 -1
- data/lib/lutaml/model/mapping/mapping.rb +1 -1
- data/lib/lutaml/model/serializable.rb +2 -1
- data/lib/lutaml/model/serialize/format_conversion.rb +26 -33
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/xml/leptris/plan_compiler.rb +1 -1
- data/lib/lutaml/xml/mapping.rb +1 -17
- data/lib/lutaml/xml/model_transform.rb +14 -4
- data/lib/lutaml/xml/schema/xsd/schema.rb +2 -1
- data/lib/lutaml/xml/serialization/format_conversion.rb +1 -1
- data/spec/lutaml/xml/clear_parse_state_spec.rb +1 -1
- data/spec/lutaml/xml/doubly_defined_namespace_spec.rb +16 -8
- data/spec/lutaml/xml/parse_dom_retention_spec.rb +34 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: edd074b78dadf665677a6c6e7d738b7d409aa63e4bbef51c9a6b0a61d36a6454
|
|
4
|
+
data.tar.gz: 9b88edc42b0b865cc2ea3523a9d923f1b988980255508e31da22fb66c06e87fe
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e90cbcc5a0046c0bd3b6d5e687fb6a9e137f3e9a8d63149296082cd468a747bec1690e5720b6a423b1a17bbe8706ce2773687671388aa303b68f3e2d37805e90
|
|
7
|
+
data.tar.gz: 163d5e386a27f6e6f4806096866de4f3005191acba9183929017c9292ecfae68fb066e6d19054102effb9eb8ed0118bc8e322d613f0cb5345183f16f328c6c02
|
data/bench/bench_common.rb
CHANGED
|
@@ -26,7 +26,8 @@ module Lutaml
|
|
|
26
26
|
parts = (instance_variables - INSPECT_EXCLUDED_IVARS).map do |iv|
|
|
27
27
|
"#{iv}=#{self.class.inspect_value(instance_variable_get(iv))}"
|
|
28
28
|
end
|
|
29
|
-
"
|
|
29
|
+
attrs = " #{parts.join(', ')}" unless parts.empty?
|
|
30
|
+
"#<#{self.class.name}#{attrs}>"
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
class << self
|
|
@@ -150,48 +150,41 @@ module Lutaml
|
|
|
150
150
|
#
|
|
151
151
|
# @return [Array<Class>] List of error classes
|
|
152
152
|
def format_error_types
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
153
|
+
# Resolved per call, not memoized: adapter engines load lazily,
|
|
154
|
+
# and a cache built before an engine loads permanently drops
|
|
155
|
+
# that engine's parse errors from the rescue list (an
|
|
156
|
+
# REXML::ParseException leaked un-wrapped when any earlier
|
|
157
|
+
# parse ran before rexml was required). The constantize pass
|
|
158
|
+
# is a handful of lookups — negligible against a parse.
|
|
159
|
+
compatibility = Lutaml::Model::RuntimeCompatibility
|
|
160
|
+
errors = [
|
|
161
|
+
compatibility.safe_constantize("Psych::SyntaxError"),
|
|
162
|
+
compatibility.safe_constantize("JSON::ParserError"),
|
|
163
|
+
NoMethodError,
|
|
164
|
+
TypeError,
|
|
165
|
+
ArgumentError,
|
|
166
|
+
]
|
|
167
|
+
|
|
168
|
+
FormatRegistry.all.each_value do |info|
|
|
169
|
+
next unless info[:error_types]
|
|
170
|
+
|
|
171
|
+
info[:error_types].each do |error_class|
|
|
172
|
+
errors << if error_class.is_a?(String)
|
|
173
|
+
compatibility.safe_constantize(error_class)
|
|
174
|
+
else
|
|
175
|
+
error_class
|
|
176
|
+
end
|
|
175
177
|
end
|
|
176
|
-
|
|
177
|
-
errors.compact.freeze
|
|
178
178
|
end
|
|
179
179
|
|
|
180
180
|
# Legacy TOML error types are lazy, so check them on each call.
|
|
181
|
-
|
|
182
|
-
toml_errors = compatibility.safe_constantize("TomlRB::ParseError")
|
|
183
|
-
toml_errors = Array(toml_errors)
|
|
181
|
+
toml_errors = Array(compatibility.safe_constantize("TomlRB::ParseError"))
|
|
184
182
|
tomllib_err = compatibility.safe_constantize("Tomlib::ParseError")
|
|
185
183
|
toml_errors << tomllib_err if tomllib_err
|
|
186
184
|
teptris_err = compatibility.safe_constantize("Teptris::ParseError")
|
|
187
185
|
toml_errors << teptris_err if teptris_err
|
|
188
186
|
|
|
189
|
-
|
|
190
|
-
end
|
|
191
|
-
|
|
192
|
-
# Reset cached error types (for test isolation)
|
|
193
|
-
def reset_format_error_types_cache!
|
|
194
|
-
@format_error_types_base = nil
|
|
187
|
+
(errors + toml_errors).compact
|
|
195
188
|
end
|
|
196
189
|
|
|
197
190
|
# Create a model instance from a parsed document
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -285,7 +285,7 @@ module Lutaml
|
|
|
285
285
|
# plan learns the catch-all row.
|
|
286
286
|
return false if mapping.any_element_rule
|
|
287
287
|
|
|
288
|
-
mapping.root_element && !mapping.root_mappings
|
|
288
|
+
mapping.root_element && !mapping.root_mappings?
|
|
289
289
|
end
|
|
290
290
|
|
|
291
291
|
# Partition bookkeeping for when_attribute rows (#88, TODO
|
data/lib/lutaml/xml/mapping.rb
CHANGED
|
@@ -38,21 +38,7 @@ module Lutaml
|
|
|
38
38
|
@xml_instance
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
attr_reader :root_element,
|
|
42
|
-
:namespace_uri,
|
|
43
|
-
:namespace_prefix,
|
|
44
|
-
:element_sequence,
|
|
45
|
-
:mappings_imported,
|
|
46
|
-
:namespace_class,
|
|
47
|
-
:namespace_param,
|
|
48
|
-
:element_name,
|
|
49
|
-
:documentation_text,
|
|
50
|
-
:type_name_value,
|
|
51
|
-
:namespace_scope,
|
|
52
|
-
:mapper_class,
|
|
53
|
-
:xml_space,
|
|
54
|
-
:consolidation_maps,
|
|
55
|
-
:processing_instruction_mappings
|
|
41
|
+
attr_reader :root_element, :namespace_uri, :namespace_prefix, :element_sequence, :mappings_imported, :namespace_class, :namespace_param, :element_name, :documentation_text, :type_name_value, :namespace_scope, :mapper_class, :xml_space, :consolidation_maps, :processing_instruction_mappings, :any_element_rule
|
|
56
42
|
|
|
57
43
|
def initialize
|
|
58
44
|
super
|
|
@@ -523,8 +509,6 @@ module Lutaml
|
|
|
523
509
|
@any_element_rule
|
|
524
510
|
end
|
|
525
511
|
|
|
526
|
-
attr_reader :any_element_rule
|
|
527
|
-
|
|
528
512
|
def map_instances(to:, polymorphic: {})
|
|
529
513
|
map_element(to, to: to, polymorphic: polymorphic)
|
|
530
514
|
end
|
|
@@ -114,7 +114,14 @@ module Lutaml
|
|
|
114
114
|
# Only needed for root elements (no lutaml_parent in options).
|
|
115
115
|
# Three modes: :lazy (default), :eager, :skip.
|
|
116
116
|
if !options.key?(:lutaml_parent)
|
|
117
|
-
|
|
117
|
+
# Default :eager — the plan data is tiny, but :lazy pins the
|
|
118
|
+
# adapter root element on every parsed instance, which keeps the
|
|
119
|
+
# entire native DOM (moxml wrappers + engine nodes) alive until
|
|
120
|
+
# first serialization. Models that are never serialized retain
|
|
121
|
+
# the DOM forever: a 10.5MB XMI held 578MB of wrappers this
|
|
122
|
+
# way. :lazy remains available for parse-serialize-immediately
|
|
123
|
+
# workflows that want to skip the namespace walk.
|
|
124
|
+
plan_mode = options.fetch(:import_declaration_plan, :eager)
|
|
118
125
|
case plan_mode
|
|
119
126
|
when :skip
|
|
120
127
|
# Skip plan building entirely (fastest)
|
|
@@ -205,7 +212,9 @@ module Lutaml
|
|
|
205
212
|
}
|
|
206
213
|
end
|
|
207
214
|
|
|
208
|
-
|
|
215
|
+
# The path array is shared and mutated during the descent;
|
|
216
|
+
# snapshot it as a result key only where a declaration lives.
|
|
217
|
+
result[path.dup] = input_namespaces unless input_namespaces.empty?
|
|
209
218
|
end
|
|
210
219
|
|
|
211
220
|
# Recurse into children with path extended by child local name
|
|
@@ -223,8 +232,9 @@ module Lutaml
|
|
|
223
232
|
else
|
|
224
233
|
full_name
|
|
225
234
|
end
|
|
226
|
-
|
|
227
|
-
collect_element_namespaces(child,
|
|
235
|
+
path.push(child_local_name)
|
|
236
|
+
collect_element_namespaces(child, path, result, visited)
|
|
237
|
+
path.pop
|
|
228
238
|
end
|
|
229
239
|
|
|
230
240
|
result
|
|
@@ -148,7 +148,8 @@ module Lutaml
|
|
|
148
148
|
def target_namespace_from(model, value)
|
|
149
149
|
model.target_namespace = value
|
|
150
150
|
model.target_namespace_prefix =
|
|
151
|
-
|
|
151
|
+
model.import_declaration_plan
|
|
152
|
+
&.global_prefix_registry&.[](value)
|
|
152
153
|
end
|
|
153
154
|
|
|
154
155
|
# Find a type definition by local name
|
|
@@ -67,7 +67,7 @@ module Lutaml
|
|
|
67
67
|
# class method; a plain (non-Serializable) superclass ends
|
|
68
68
|
# the chain.
|
|
69
69
|
inherited = if superclass.is_a?(Class) &&
|
|
70
|
-
|
|
70
|
+
superclass.include?(Lutaml::Model::Serialize)
|
|
71
71
|
superclass.xml_schema_paths
|
|
72
72
|
else
|
|
73
73
|
[]
|
|
@@ -48,7 +48,7 @@ RSpec.describe "#clear_xml_parse_state!" do
|
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
it "clears pending_plan_root_element set by :lazy mode" do
|
|
51
|
-
model = model_class.from_xml(xml_with_ns)
|
|
51
|
+
model = model_class.from_xml(xml_with_ns, import_declaration_plan: :lazy)
|
|
52
52
|
expect(model.pending_plan_root_element).not_to be_nil
|
|
53
53
|
model.clear_xml_parse_state!
|
|
54
54
|
expect(model.pending_plan_root_element).to be_nil
|
|
@@ -343,26 +343,30 @@ RSpec.describe "Doubly-defined namespace prefixes" do
|
|
|
343
343
|
XML
|
|
344
344
|
end
|
|
345
345
|
|
|
346
|
-
describe ":lazy
|
|
346
|
+
describe ":lazy" do
|
|
347
347
|
it "stores element reference for lazy plan building during parsing" do
|
|
348
|
-
model = model_class.from_xml(prefixed_xml
|
|
348
|
+
model = model_class.from_xml(prefixed_xml,
|
|
349
|
+
import_declaration_plan: :lazy)
|
|
349
350
|
expect(model.pending_plan_root_element).not_to be_nil
|
|
350
351
|
end
|
|
351
352
|
|
|
352
353
|
it "builds plan via import_declaration_plan method" do
|
|
353
|
-
model = model_class.from_xml(prefixed_xml
|
|
354
|
+
model = model_class.from_xml(prefixed_xml,
|
|
355
|
+
import_declaration_plan: :lazy)
|
|
354
356
|
expect(model.import_declaration_plan).to be_a(Lutaml::Xml::DeclarationPlan)
|
|
355
357
|
end
|
|
356
358
|
|
|
357
359
|
it "clears element reference after plan is built" do
|
|
358
|
-
model = model_class.from_xml(prefixed_xml
|
|
360
|
+
model = model_class.from_xml(prefixed_xml,
|
|
361
|
+
import_declaration_plan: :lazy)
|
|
359
362
|
expect(model.pending_plan_root_element).not_to be_nil
|
|
360
363
|
_ = model.import_declaration_plan
|
|
361
364
|
expect(model.pending_plan_root_element).to be_nil
|
|
362
365
|
end
|
|
363
366
|
|
|
364
367
|
it "imports plan automatically on to_xml" do
|
|
365
|
-
model = model_class.from_xml(prefixed_xml
|
|
368
|
+
model = model_class.from_xml(prefixed_xml,
|
|
369
|
+
import_declaration_plan: :lazy)
|
|
366
370
|
# Plan not yet built (instance variable is nil)
|
|
367
371
|
expect(model.instance_variable_get(:@xml_declaration_plan)).to be_nil
|
|
368
372
|
model.to_xml
|
|
@@ -371,12 +375,16 @@ RSpec.describe "Doubly-defined namespace prefixes" do
|
|
|
371
375
|
end
|
|
372
376
|
end
|
|
373
377
|
|
|
374
|
-
describe ":eager" do
|
|
378
|
+
describe ":eager (default)" do
|
|
375
379
|
it "builds plan immediately during parsing" do
|
|
376
|
-
model = model_class.from_xml(prefixed_xml
|
|
377
|
-
import_declaration_plan: :eager)
|
|
380
|
+
model = model_class.from_xml(prefixed_xml)
|
|
378
381
|
expect(model.import_declaration_plan).to be_a(Lutaml::Xml::DeclarationPlan)
|
|
379
382
|
end
|
|
383
|
+
|
|
384
|
+
it "does not retain the adapter root element" do
|
|
385
|
+
model = model_class.from_xml(prefixed_xml)
|
|
386
|
+
expect(model.pending_plan_root_element).to be_nil
|
|
387
|
+
end
|
|
380
388
|
end
|
|
381
389
|
|
|
382
390
|
describe ":skip" do
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "XML parse DOM retention" do
|
|
6
|
+
let(:model_class) do
|
|
7
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
8
|
+
attribute :item, :string
|
|
9
|
+
|
|
10
|
+
xml do
|
|
11
|
+
element "root"
|
|
12
|
+
map_element "item", to: :item
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
let(:xml) do
|
|
18
|
+
<<~XML
|
|
19
|
+
<root xmlns:xyz="http://example.com/items">
|
|
20
|
+
<xyz:item>hello</xyz:item>
|
|
21
|
+
</root>
|
|
22
|
+
XML
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "does not retain the adapter root element after parsing" do
|
|
26
|
+
model = model_class.from_xml(xml)
|
|
27
|
+
expect(model.pending_plan_root_element).to be_nil
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "still captures the input namespace declarations" do
|
|
31
|
+
model = model_class.from_xml(xml)
|
|
32
|
+
expect(model.import_declaration_plan).to be_a(Lutaml::Xml::DeclarationPlan)
|
|
33
|
+
end
|
|
34
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: lutaml-model
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.8.
|
|
4
|
+
version: 0.8.88
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -1977,6 +1977,7 @@ files:
|
|
|
1977
1977
|
- spec/lutaml/xml/opal_xml_spec.rb
|
|
1978
1978
|
- spec/lutaml/xml/ordered_method_spec.rb
|
|
1979
1979
|
- spec/lutaml/xml/out_of_namespace_parsing_spec.rb
|
|
1980
|
+
- spec/lutaml/xml/parse_dom_retention_spec.rb
|
|
1980
1981
|
- spec/lutaml/xml/pipeline_integration_spec.rb
|
|
1981
1982
|
- spec/lutaml/xml/plain_model_accessors_spec.rb
|
|
1982
1983
|
- spec/lutaml/xml/plan_fast_path_spec.rb
|