lutaml-model 0.8.34 → 0.8.36
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/.rspec +1 -0
- data/lib/lutaml/model/attribute.rb +48 -22
- data/lib/lutaml/model/register.rb +12 -5
- data/lib/lutaml/model/transformation_registry.rb +13 -7
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/xml/adapter_element.rb +17 -4
- data/lib/lutaml/xml/model_transform.rb +1 -1
- data/spec/benchmarks/xml_parsing_benchmark_spec.rb +70 -0
- data/spec/lutaml/model/absent_value_contracts_spec.rb +65 -0
- data/spec/lutaml/model/parsed_model_mutation_spec.rb +11 -5
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 13023a5add888c4affa15d1e7c025548e329b0aad8112582550be7cff794524a
|
|
4
|
+
data.tar.gz: 7393786a16da4f06d7962f7395edab78b5985ab1820c98da8b95f66f669be99d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 03be6773d23935e26c6593d2c966f5063af4840142f988c6db534517b26b7889adc15c11c5d5280b181b9b19e35a971bbbc889ce673d63a750385e5b392d60b7
|
|
7
|
+
data.tar.gz: 656f73aab6fe55e9dbe8337a8c6ec76fae5c2cadfade74bdd30500d3ea16105cdf3de1ebce9d837b4ddd3c6851e84ac7b5b7a7f40f2729d79827014e9d0a0b9e
|
data/.rspec
CHANGED
|
@@ -52,11 +52,13 @@ module Lutaml
|
|
|
52
52
|
# Public reader for compiled rule plans: does this type class carry a
|
|
53
53
|
# custom from_xml/from_json (answer static, probed once)?
|
|
54
54
|
def custom_from_probe?(type)
|
|
55
|
-
TypeProbeCache.cache
|
|
56
|
-
|
|
55
|
+
cache = TypeProbeCache.cache
|
|
56
|
+
return cache[type] if cache.key?(type)
|
|
57
|
+
|
|
58
|
+
base = Lutaml::Model::Type::Value.singleton_class
|
|
59
|
+
cache[type] =
|
|
57
60
|
type.method(:from_xml).owner != base ||
|
|
58
|
-
|
|
59
|
-
end
|
|
61
|
+
type.method(:from_json).owner != base
|
|
60
62
|
end
|
|
61
63
|
end
|
|
62
64
|
|
|
@@ -434,18 +436,31 @@ module Lutaml
|
|
|
434
436
|
end
|
|
435
437
|
|
|
436
438
|
def cast_element(value, register)
|
|
437
|
-
# Resolve first: an undeclared type has to raise UnknownTypeError
|
|
438
|
-
#
|
|
439
|
-
|
|
440
|
-
resolved_type = type(register)
|
|
439
|
+
# Resolve first: an undeclared type has to raise UnknownTypeError
|
|
440
|
+
# even for a nil value (the 0.8.33 behavior).
|
|
441
|
+
type(register)
|
|
441
442
|
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
#
|
|
445
|
-
#
|
|
446
|
-
#
|
|
447
|
-
#
|
|
448
|
-
|
|
443
|
+
return value if Utils.uninitialized?(value)
|
|
444
|
+
|
|
445
|
+
# nil reaches the type's cast — the long-shipped contract
|
|
446
|
+
# ST_OnOff-style types depend on (absent attribute -> cast(nil)
|
|
447
|
+
# -> false; lutaml-model#795). What nil must NOT do is
|
|
448
|
+
# manufacture a typed INSTANCE from nothing: that is the
|
|
449
|
+
# phantom #793 removed, suppressed by the post-check below.
|
|
450
|
+
if value.nil?
|
|
451
|
+
result = cast_element_present(value, register)
|
|
452
|
+
return result if result.nil?
|
|
453
|
+
return nil if result.is_a?(Lutaml::Model::Type::Value) ||
|
|
454
|
+
result.is_a?(Lutaml::Model::Serialize)
|
|
455
|
+
|
|
456
|
+
return result
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
cast_element_present(value, register)
|
|
460
|
+
end
|
|
461
|
+
|
|
462
|
+
def cast_element_present(value, register)
|
|
463
|
+
resolved_type = type(register)
|
|
449
464
|
|
|
450
465
|
return cast_union(value, nil, register) if union?
|
|
451
466
|
return resolved_type.new(value) if value.is_a?(::Hash) && !hash_type?
|
|
@@ -783,14 +798,25 @@ instance_object = nil)
|
|
|
783
798
|
end
|
|
784
799
|
|
|
785
800
|
def cast(value, format, register, options = {})
|
|
786
|
-
#
|
|
787
|
-
#
|
|
788
|
-
#
|
|
789
|
-
#
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
801
|
+
# Sentinel: never a cast input. nil flows on — absent values
|
|
802
|
+
# reach the type's cast (ST_OnOff booleans, #795); a cast that
|
|
803
|
+
# manufactures a typed instance from nothing is the phantom
|
|
804
|
+
# #793 removed, suppressed here as in cast_element.
|
|
805
|
+
return value if Utils.uninitialized?(value)
|
|
806
|
+
|
|
807
|
+
if value.nil?
|
|
808
|
+
result = cast_present(value, format, register, options)
|
|
809
|
+
return result if result.nil?
|
|
810
|
+
return nil if result.is_a?(Lutaml::Model::Type::Value) ||
|
|
811
|
+
result.is_a?(Lutaml::Model::Serialize)
|
|
812
|
+
|
|
813
|
+
return result
|
|
814
|
+
end
|
|
815
|
+
|
|
816
|
+
cast_present(value, format, register, options)
|
|
817
|
+
end
|
|
793
818
|
|
|
819
|
+
def cast_present(value, format, register, options = {})
|
|
794
820
|
# Namespace-aware type resolution: use type_with_namespace if namespace_uri provided
|
|
795
821
|
namespace_uri = options[:namespace_uri]
|
|
796
822
|
resolved_type = if options[:resolved_type]
|
|
@@ -80,15 +80,22 @@ module Lutaml
|
|
|
80
80
|
# @param parent_register [Symbol, String, nil] The parent's register/context ID
|
|
81
81
|
# @return [Symbol, nil] The register ID to use for the child
|
|
82
82
|
def self.resolve_for_child(child_class, parent_register)
|
|
83
|
-
cache_key = [child_class.object_id, parent_register]
|
|
84
|
-
|
|
85
83
|
if Lutaml::Model.opal?
|
|
86
|
-
|
|
84
|
+
per_class = RESOLVE_CACHE[child_class] # rubocop:todo Style/IdenticalConditionalBranches
|
|
85
|
+
return per_class[parent_register] if per_class&.key?(parent_register)
|
|
87
86
|
|
|
88
|
-
RESOLVE_CACHE[
|
|
87
|
+
(RESOLVE_CACHE[child_class] ||= {})[parent_register] =
|
|
89
88
|
_resolve_for_child_uncached(child_class, parent_register)
|
|
90
89
|
else
|
|
91
|
-
|
|
90
|
+
# Nested maps: class → register → result. Every hop keys on a
|
|
91
|
+
# stable object (Class / Symbol), so the hot lookup allocates
|
|
92
|
+
# nothing — the flat [object_id, register] array key cost one
|
|
93
|
+
# Array per call, six per parsed element.
|
|
94
|
+
per_class = RESOLVE_CACHE[child_class] # rubocop:todo Style/IdenticalConditionalBranches
|
|
95
|
+
per_class ||= RESOLVE_CACHE.compute_if_absent(child_class) do
|
|
96
|
+
Concurrent::Map.new
|
|
97
|
+
end
|
|
98
|
+
per_class.compute_if_absent(parent_register) do
|
|
92
99
|
_resolve_for_child_uncached(child_class, parent_register)
|
|
93
100
|
end
|
|
94
101
|
end
|
|
@@ -174,25 +174,31 @@ module Lutaml
|
|
|
174
174
|
# @param register [Symbol, Register, nil] The register
|
|
175
175
|
# @return [Mapping] The resolved mapping
|
|
176
176
|
def get_or_build_mapping(model_class, format, register)
|
|
177
|
-
# Performance:
|
|
177
|
+
# Performance: nested class → format → register maps keyed on
|
|
178
|
+
# stable objects; the flat array key allocated per call.
|
|
178
179
|
register_id = extract_register_id(register)
|
|
179
|
-
key = [model_class.object_id, format, register_id]
|
|
180
180
|
|
|
181
|
-
|
|
182
|
-
|
|
181
|
+
per_class = @mappings[model_class]
|
|
182
|
+
per_format = per_class&.[](format)
|
|
183
|
+
cached = per_format&.[](register_id)
|
|
183
184
|
return cached if cached
|
|
184
185
|
|
|
185
|
-
# Build mapping OUTSIDE any lock to avoid deadlock
|
|
186
|
-
# (ensure_mappings_imported! may recursively call get_or_build_mapping)
|
|
187
186
|
mapping = model_class.mappings[format]
|
|
188
187
|
mapping = mapping || model_class.default_mappings(format)
|
|
189
188
|
|
|
190
189
|
mapping.ensure_mappings_imported!(register_id)
|
|
191
190
|
|
|
192
|
-
@mappings[
|
|
191
|
+
per_class = (@mappings[model_class] ||= new_inner_map)
|
|
192
|
+
(per_class[format] ||= new_inner_map)[register_id] = mapping
|
|
193
193
|
mapping
|
|
194
194
|
end
|
|
195
195
|
|
|
196
|
+
# Inner cache level container matching the outer map's engine
|
|
197
|
+
# (Concurrent::Map under GVL-threaded MRI, plain Hash under Opal).
|
|
198
|
+
def new_inner_map
|
|
199
|
+
Lutaml::Model.opal? ? {} : ::Concurrent::Map.new
|
|
200
|
+
end
|
|
201
|
+
|
|
196
202
|
# Clear all cached data (transformations and mappings).
|
|
197
203
|
#
|
|
198
204
|
# This is useful for testing or when configuration changes dynamically.
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -64,8 +64,8 @@ module Lutaml
|
|
|
64
64
|
name = adapter_class.name_of(node)
|
|
65
65
|
super(
|
|
66
66
|
node,
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
attributes || NO_ATTRIBUTES,
|
|
68
|
+
children || NO_CHILDREN,
|
|
69
69
|
text,
|
|
70
70
|
name: name,
|
|
71
71
|
parent_document: parent,
|
|
@@ -146,8 +146,19 @@ module Lutaml
|
|
|
146
146
|
end
|
|
147
147
|
end
|
|
148
148
|
|
|
149
|
+
# Shared frozen empties: the parse path hands these straight into
|
|
150
|
+
# XmlElement (which never mutates the containers it is given), so
|
|
151
|
+
# attribute-less elements — the majority in real documents — build
|
|
152
|
+
# nothing here.
|
|
153
|
+
NO_ATTRIBUTES = {}.freeze # rubocop:todo Lint/UselessConstantScoping
|
|
154
|
+
NO_CHILDREN = [].freeze # rubocop:todo Lint/UselessConstantScoping
|
|
155
|
+
EMPTY_ATTRIBUTES = [{}, nil].freeze # rubocop:todo Lint/UselessConstantScoping
|
|
156
|
+
|
|
149
157
|
def node_attributes_with_order(node)
|
|
150
|
-
return
|
|
158
|
+
return EMPTY_ATTRIBUTES unless node.is_a?(Moxml::Element)
|
|
159
|
+
|
|
160
|
+
attrs = node.attributes
|
|
161
|
+
return EMPTY_ATTRIBUTES if attrs.respond_to?(:empty?) && attrs.empty?
|
|
151
162
|
|
|
152
163
|
order = []
|
|
153
164
|
hash = node.attributes.each_with_object({}) do |attr, h|
|
|
@@ -174,7 +185,7 @@ module Lutaml
|
|
|
174
185
|
end
|
|
175
186
|
|
|
176
187
|
def parse_children(node, default_namespace: nil)
|
|
177
|
-
return
|
|
188
|
+
return NO_CHILDREN unless node.children
|
|
178
189
|
|
|
179
190
|
# Non-element children (text/cdata/comment/PI) stay RAW moxml
|
|
180
191
|
# nodes in the list — the hot scalar parse path reads text off
|
|
@@ -197,6 +208,8 @@ module Lutaml
|
|
|
197
208
|
public
|
|
198
209
|
|
|
199
210
|
def children
|
|
211
|
+
return @children if @children.empty?
|
|
212
|
+
|
|
200
213
|
unless @non_element_children_wrapped
|
|
201
214
|
@children.map! do |child|
|
|
202
215
|
if child.is_a?(Moxml::Node) && !child.is_a?(Moxml::Element)
|
|
@@ -402,7 +402,7 @@ instance_is_serialize = nil)
|
|
|
402
402
|
# dup: XmlElement#order hands back a frozen cache shared with the
|
|
403
403
|
# DOM. The model's copy has to stay mutable so callers can maintain
|
|
404
404
|
# element_order themselves.
|
|
405
|
-
instance.element_order = doc.root.order
|
|
405
|
+
instance.element_order = doc.root.order
|
|
406
406
|
if instance_is_serialize && doc.root.is_a?(::Lutaml::Xml::XmlElement)
|
|
407
407
|
instance.attribute_order = doc.root.attribute_order
|
|
408
408
|
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require "benchmark/ips"
|
|
5
|
+
|
|
6
|
+
# Adapter-comparison benchmark, runnable on demand:
|
|
7
|
+
# bundle exec rspec --tag benchmark spec/benchmarks/
|
|
8
|
+
# Tagged out of the default suite (.rsex --tag ~benchmark); asserts
|
|
9
|
+
# nothing about absolute speed — machines differ — but prints i/s and
|
|
10
|
+
# allocations/op so regressions are visible when run deliberately.
|
|
11
|
+
RSpec.describe "XML adapter benchmark", :benchmark do
|
|
12
|
+
Item = Class.new(Lutaml::Model::Serializable) do # rubocop:todo Lint/ConstantDefinitionInBlock, RSpec/LeakyConstantDeclaration
|
|
13
|
+
attribute :id, :integer
|
|
14
|
+
attribute :name, :string
|
|
15
|
+
attribute :tags, :string, collection: true
|
|
16
|
+
|
|
17
|
+
xml do
|
|
18
|
+
element "item"
|
|
19
|
+
map_attribute "id", to: :id
|
|
20
|
+
map_element "name", to: :name
|
|
21
|
+
map_element "tag", to: :tags
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
Root = Class.new(Lutaml::Model::Serializable) do # rubocop:todo Lint/ConstantDefinitionInBlock, RSpec/LeakyConstantDeclaration
|
|
26
|
+
attribute :item, Item, collection: true
|
|
27
|
+
|
|
28
|
+
xml do
|
|
29
|
+
element "root"
|
|
30
|
+
map_element "item", to: :item
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
XML = +"<root>" # rubocop:todo Lint/ConstantDefinitionInBlock, RSpec/LeakyConstantDeclaration
|
|
35
|
+
1_000.times { |i| XML << %(<item id="#{i}"><name>Item #{i}</name><tag>a</tag><tag>b</tag></item>) }
|
|
36
|
+
XML << "</root>"
|
|
37
|
+
|
|
38
|
+
def allocations_of
|
|
39
|
+
GC.start
|
|
40
|
+
before = GC.stat(:total_allocated_objects)
|
|
41
|
+
yield
|
|
42
|
+
GC.stat(:total_allocated_objects) - before
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
%i[nokogiri ox oga rexml leptris].each do |adapter|
|
|
46
|
+
it "#{adapter}: from_xml/to_xml i/s and allocations" do
|
|
47
|
+
model = nil
|
|
48
|
+
Lutaml::Model::Config.with_adapter(xml: adapter) do
|
|
49
|
+
begin
|
|
50
|
+
Lutaml::Model::Config.adapter_for(:xml)
|
|
51
|
+
rescue Lutaml::Model::UnknownAdapterTypeError
|
|
52
|
+
skip "#{adapter} adapter unavailable on this platform"
|
|
53
|
+
end
|
|
54
|
+
report = Benchmark.ips(time: 2, warmup: 1, quiet: true) do |x|
|
|
55
|
+
x.report("parse") { model = Root.from_xml(XML) }
|
|
56
|
+
x.report("serialize") { model.to_xml }
|
|
57
|
+
end
|
|
58
|
+
parse_ips = report.entries.first.ips
|
|
59
|
+
serialize_ips = report.entries.last.ips
|
|
60
|
+
|
|
61
|
+
allocs = allocations_of { Root.from_xml(XML) }
|
|
62
|
+
puts format( # rubocop:todo RSpec/Output
|
|
63
|
+
"%<a>-9s parse %<p>7.1f i/s serialize %<s>7.1f i/s %<al>8d allocs/op",
|
|
64
|
+
a: adapter, p: parse_ips, s: serialize_ips, al: allocs,
|
|
65
|
+
)
|
|
66
|
+
expect(model.item.size).to eq(1_000)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
# The 0.8.33 parse contracts restored after #795: a custom type's cast
|
|
6
|
+
# sees an absent attribute's nil (ST_OnOff booleans — an absent flag is
|
|
7
|
+
# semantically false), and the parsed element_order array is frozen
|
|
8
|
+
# (consumers build thaw-on-demand helpers on that).
|
|
9
|
+
RSpec.describe "absent-value and order contracts" do
|
|
10
|
+
before do
|
|
11
|
+
stub_const("OnOff", Class.new(Lutaml::Model::Type::Boolean) do
|
|
12
|
+
def self.cast(value, _options = {})
|
|
13
|
+
return false if value.nil?
|
|
14
|
+
|
|
15
|
+
super
|
|
16
|
+
end
|
|
17
|
+
end)
|
|
18
|
+
|
|
19
|
+
stub_const("Doc", Class.new(Lutaml::Model::Serializable) do
|
|
20
|
+
attribute :flag, OnOff
|
|
21
|
+
xml do
|
|
22
|
+
element "doc"
|
|
23
|
+
map_attribute "flag", to: :flag
|
|
24
|
+
end
|
|
25
|
+
end)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "casts an absent attribute through the type (nil -> false)" do
|
|
29
|
+
expect(Doc.from_xml("<doc/>").flag).to be(false)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "still casts a present attribute" do
|
|
33
|
+
expect(Doc.from_xml('<doc flag="0"/>').flag).to be(false)
|
|
34
|
+
expect(Doc.from_xml('<doc flag="1"/>').flag).to be(true)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "hands the parsed element_order back frozen" do
|
|
38
|
+
expect(Doc.from_xml('<doc flag="1"/>').element_order).to be_frozen
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "does not manufacture typed instances from nothing" do
|
|
42
|
+
stub_const("PhantomType", Class.new(Lutaml::Model::Type::String) do
|
|
43
|
+
# Value#initialize casts what it is given, so a cast that
|
|
44
|
+
# constructs has to bypass it (see phantom_value_spec's Eager).
|
|
45
|
+
def initialize(value) # rubocop:disable Lint/MissingSuper
|
|
46
|
+
@value = value
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.cast(value, _options = {})
|
|
50
|
+
return value if value.is_a?(PhantomType)
|
|
51
|
+
|
|
52
|
+
new("phantom(#{value.inspect})")
|
|
53
|
+
end
|
|
54
|
+
end)
|
|
55
|
+
stub_const("PhantomDoc", Class.new(Lutaml::Model::Serializable) do
|
|
56
|
+
attribute :phantom, PhantomType
|
|
57
|
+
xml do
|
|
58
|
+
element "k"
|
|
59
|
+
map_attribute "p", to: :phantom
|
|
60
|
+
end
|
|
61
|
+
end)
|
|
62
|
+
|
|
63
|
+
expect(PhantomDoc.from_xml("<k/>").phantom).to be_nil
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -294,12 +294,18 @@ RSpec.describe "parsed model mutation" do
|
|
|
294
294
|
end
|
|
295
295
|
end
|
|
296
296
|
|
|
297
|
-
#
|
|
297
|
+
# element_order on a parsed model: the parsed order array is frozen
|
|
298
|
+
# (the 0.8.33 contract consumers build thaw-on-demand helpers on,
|
|
299
|
+
# lutaml-model#795). Mutation goes through reassignment — the
|
|
300
|
+
# accessor is a public writer.
|
|
298
301
|
describe "element_order on a parsed model" do
|
|
299
|
-
it "is
|
|
302
|
+
it "is reassignable" do
|
|
300
303
|
model = ParsedModelMutationSpec::Mixed.from_xml('<p><a v="1"/></p>')
|
|
301
304
|
|
|
302
|
-
expect
|
|
305
|
+
expect(model.element_order).to be_frozen
|
|
306
|
+
expect do
|
|
307
|
+
model.element_order = model.element_order.dup << "x"
|
|
308
|
+
end.not_to raise_error
|
|
303
309
|
end
|
|
304
310
|
end
|
|
305
311
|
|
|
@@ -467,7 +473,7 @@ RSpec.describe "parsed model mutation" do
|
|
|
467
473
|
it "serializes without raising when element_order holds an Integer" do
|
|
468
474
|
model = ParsedModelMutationSpec::NilColl
|
|
469
475
|
.from_xml("<s><lead>L</lead><item>a</item></s>")
|
|
470
|
-
model.element_order << 42
|
|
476
|
+
model.element_order = model.element_order.dup << 42
|
|
471
477
|
|
|
472
478
|
expect { model.to_xml }.not_to raise_error
|
|
473
479
|
end
|
|
@@ -475,7 +481,7 @@ RSpec.describe "parsed model mutation" do
|
|
|
475
481
|
it "still reconciles the well-formed entries around a foreign one" do
|
|
476
482
|
model = ParsedModelMutationSpec::NilColl
|
|
477
483
|
.from_xml("<s><lead>L</lead><item>a</item></s>")
|
|
478
|
-
model.element_order.insert(1, 42)
|
|
484
|
+
model.element_order = model.element_order.dup.insert(1, 42)
|
|
479
485
|
model.items << "b"
|
|
480
486
|
|
|
481
487
|
xml = model.to_xml
|
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.36
|
|
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-09-
|
|
11
|
+
date: 2026-09-18 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -971,6 +971,7 @@ files:
|
|
|
971
971
|
- sig/lutaml/model.rbs
|
|
972
972
|
- spec/address_person_spec.rb
|
|
973
973
|
- spec/address_spec.rb
|
|
974
|
+
- spec/benchmarks/xml_parsing_benchmark_spec.rb
|
|
974
975
|
- spec/ceramic_spec.rb
|
|
975
976
|
- spec/fixtures/address.rb
|
|
976
977
|
- spec/fixtures/ceramic.rb
|
|
@@ -1684,6 +1685,7 @@ files:
|
|
|
1684
1685
|
- spec/lutaml/key_value/transformation/rule_compiler_spec.rb
|
|
1685
1686
|
- spec/lutaml/key_value/transformation/value_serializer_spec.rb
|
|
1686
1687
|
- spec/lutaml/key_value/transformation_spec.rb
|
|
1688
|
+
- spec/lutaml/model/absent_value_contracts_spec.rb
|
|
1687
1689
|
- spec/lutaml/model/attribute_apply_value_map_spec.rb
|
|
1688
1690
|
- spec/lutaml/model/attribute_collection_spec.rb
|
|
1689
1691
|
- spec/lutaml/model/attribute_default_cache_spec.rb
|