lutaml-model 0.8.84 → 0.8.85
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/lib/compat/opal/lutaml_model_boot.rb +6 -5
- data/lib/lutaml/key_value/transform.rb +3 -1
- data/lib/lutaml/model/mapping/mapping.rb +13 -0
- data/lib/lutaml/model/serialize/format_conversion.rb +5 -5
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/xml/format.rb +3 -5
- data/lib/lutaml/xml/leptris/plan_compiler.rb +372 -0
- data/lib/lutaml/xml/leptris/plan_hydrator.rb +441 -0
- data/lib/lutaml/xml/leptris/plan_order.rb +55 -0
- data/lib/lutaml/xml/leptris/plan_serializer.rb +273 -0
- data/lib/lutaml/xml/leptris/plan_walk.rb +32 -0
- data/lib/lutaml/xml/leptris.rb +33 -0
- data/lib/lutaml/xml/serialization/format_conversion.rb +5 -1
- data/lib/lutaml/xml/transformation/ordered_applier.rb +1 -1
- data/lib/tasks/performance_probe_plan_walk.rb +1 -1
- data/spec/lutaml/model/store_spec.rb +6 -2
- data/spec/lutaml/xml/plan_fast_path_spec.rb +8 -8
- data/spec/lutaml/xml/plan_partition_spec.rb +1 -1
- data/spec/lutaml/xml/plan_walk_spec.rb +6 -6
- metadata +7 -6
- data/lib/lutaml/xml/plan_compiler.rb +0 -362
- data/lib/lutaml/xml/plan_hydrator.rb +0 -464
- data/lib/lutaml/xml/plan_order.rb +0 -53
- data/lib/lutaml/xml/plan_serializer.rb +0 -271
- data/lib/lutaml/xml/plan_walk.rb +0 -30
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lutaml
|
|
4
|
+
module Xml
|
|
5
|
+
module Leptris
|
|
6
|
+
# Serialize-side mirror of the plan fast path: builds the output
|
|
7
|
+
# tree directly through leptris's fused create_child chain — no
|
|
8
|
+
# XmlElement tree, no DeclarationPlanner pass, no builder context
|
|
9
|
+
# stack, no moxml wrapper minting. Serialized shapes must be the
|
|
10
|
+
# plain ones (attributes, scalars, collections, nested models,
|
|
11
|
+
# raw fragments, content runs); custom-method, polymorphic,
|
|
12
|
+
# union, and multi-spelling rows keep the interpretive serializer
|
|
13
|
+
# (their output flows through hash-shaped custom APIs).
|
|
14
|
+
#
|
|
15
|
+
# Ordered/mixed models serialize from element_order when the
|
|
16
|
+
# instance carries one (parsed models): text runs, comments, and
|
|
17
|
+
# element entries in document order, mirroring the interpretive
|
|
18
|
+
# order applier — including its content-attr-first text reads
|
|
19
|
+
# (mutations to the model show up) and CDATA flattening. Models
|
|
20
|
+
# without element_order fall back interpretively (return nil).
|
|
21
|
+
module PlanSerializer
|
|
22
|
+
SERIALIZABLE_KINDS = %i[scalar collection_native collection_cb
|
|
23
|
+
nested ordered_deferred raw content
|
|
24
|
+
content_deferred].freeze
|
|
25
|
+
CONTENT_KINDS = %i[content content_deferred].freeze
|
|
26
|
+
|
|
27
|
+
class << self
|
|
28
|
+
# plan: the compiler's entry for instance's class
|
|
29
|
+
def call(instance, plan, register = nil)
|
|
30
|
+
# The child model's declared lutaml_default_register takes
|
|
31
|
+
# precedence over the ambient register — the resolve_for_child
|
|
32
|
+
# contract (#876); without it, child plans and attribute
|
|
33
|
+
# serialization resolve in the parent context.
|
|
34
|
+
register = Lutaml::Model::Register.resolve_for_child(
|
|
35
|
+
instance.class,
|
|
36
|
+
register || Lutaml::Model::Config.default_register,
|
|
37
|
+
)
|
|
38
|
+
return nil if plan[:ordered] && instance.element_order.nil?
|
|
39
|
+
|
|
40
|
+
doc = ::Leptris::XML::Document.create
|
|
41
|
+
root = doc.create_element(plan[:tree][:name])
|
|
42
|
+
doc.root = root
|
|
43
|
+
if plan[:ordered]
|
|
44
|
+
build_ordered(root, instance, plan, doc, register)
|
|
45
|
+
else
|
|
46
|
+
build(root, instance, plan, doc, register)
|
|
47
|
+
end
|
|
48
|
+
doc.to_xml(indent: 2, no_decl: true)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Whether the compiled plan is serialize-shaped. Ordered/mixed
|
|
52
|
+
# models serialize through build_ordered from element_order;
|
|
53
|
+
# plain models through plan rows.
|
|
54
|
+
def serializable?(plan)
|
|
55
|
+
plan[:rows].all? do |_rule, _attr, kind, _sp, _del|
|
|
56
|
+
SERIALIZABLE_KINDS.include?(kind)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def register
|
|
63
|
+
Lutaml::Model::Config.default_register
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def build(element, instance, plan, doc, reg = nil)
|
|
67
|
+
reg ||= register
|
|
68
|
+
write_attributes(element, instance, plan, reg)
|
|
69
|
+
plan[:rows].each do |rule, attr, kind, spelling, delegate|
|
|
70
|
+
value = value_of(instance, attr, delegate)
|
|
71
|
+
next unless rule.render?(value, instance)
|
|
72
|
+
|
|
73
|
+
case kind
|
|
74
|
+
when :scalar
|
|
75
|
+
# Multi-capture parity: an attribute that collected
|
|
76
|
+
# several occurrences serializes one element per item,
|
|
77
|
+
# as the interpretive writer does. A plain scalar skips
|
|
78
|
+
# the Array() wrap — the common case.
|
|
79
|
+
if value.is_a?(::Array)
|
|
80
|
+
value.each do |item|
|
|
81
|
+
add_leaf(element, row_name(rule, spelling),
|
|
82
|
+
attr.serialize(item, :xml, reg), doc,
|
|
83
|
+
attrs: rule.when_attribute)
|
|
84
|
+
end
|
|
85
|
+
else
|
|
86
|
+
add_leaf(element, row_name(rule, spelling),
|
|
87
|
+
attr.serialize(value, :xml, reg), doc,
|
|
88
|
+
attrs: rule.when_attribute)
|
|
89
|
+
end
|
|
90
|
+
when :collection_native, :collection_cb
|
|
91
|
+
Array(value).each do |item|
|
|
92
|
+
add_leaf(element, rule.name.to_s,
|
|
93
|
+
attr.serialize(item, :xml, reg), doc,
|
|
94
|
+
attrs: rule.when_attribute)
|
|
95
|
+
end
|
|
96
|
+
when :nested, :ordered_deferred
|
|
97
|
+
Array(value).each do |item|
|
|
98
|
+
child_plan = PlanCompiler.compile(item.class, reg)
|
|
99
|
+
child = element.create_child(child_plan[:tree][:name])
|
|
100
|
+
if child_plan[:ordered]
|
|
101
|
+
return nil unless build_ordered(child, item, child_plan,
|
|
102
|
+
doc, reg)
|
|
103
|
+
|
|
104
|
+
else
|
|
105
|
+
build(child, item, child_plan, doc, reg)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
when :raw
|
|
109
|
+
Array(value).each { |raw| element.add_child(raw.to_s) }
|
|
110
|
+
when :content, :content_deferred
|
|
111
|
+
Array(value).each { |run| element.add_child(doc.create_text_node(run.to_s)) }
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Element_order-driven emission (the interpretive order
|
|
117
|
+
# applier's contract): text runs and comments verbatim, each
|
|
118
|
+
# element entry consuming the next item of its collection
|
|
119
|
+
# (document order). Text reads prefer the content attribute
|
|
120
|
+
# when it lines up with the text-node count, so mutations to
|
|
121
|
+
# the model are reflected; element_order text is the fallback.
|
|
122
|
+
# PIs drop (interpretive parity). Returns nil when a nested
|
|
123
|
+
# ordered child lacks element_order (caller falls back).
|
|
124
|
+
def build_ordered(element, instance, plan, doc, reg = nil)
|
|
125
|
+
reg ||= register
|
|
126
|
+
write_attributes(element, instance, plan, reg)
|
|
127
|
+
rows_by_name = {}
|
|
128
|
+
plan[:rows].each do |rule, attr, kind, spelling, delegate|
|
|
129
|
+
next unless rule.name
|
|
130
|
+
|
|
131
|
+
rows_by_name[rule.name.to_s] ||= [rule, attr, kind, spelling,
|
|
132
|
+
delegate]
|
|
133
|
+
end
|
|
134
|
+
content_entry = plan[:rows].find do |rule, _attr, kind, _sp, _del|
|
|
135
|
+
CONTENT_KINDS.include?(kind) && rule.name.nil?
|
|
136
|
+
end
|
|
137
|
+
order = instance.element_order
|
|
138
|
+
element_indices = ::Hash.new(0)
|
|
139
|
+
content_attr = content_entry && content_entry[1]
|
|
140
|
+
content_value = content_attr &&
|
|
141
|
+
value_of(instance, content_attr, content_entry[4])
|
|
142
|
+
text_node_count = order.count { |o| o.type == "Text" }
|
|
143
|
+
use_content_index = content_value.is_a?(Array) &&
|
|
144
|
+
content_value.length == text_node_count
|
|
145
|
+
content_cdata = content_entry && content_entry[0].cdata
|
|
146
|
+
text_node_index = 0
|
|
147
|
+
|
|
148
|
+
order.each do |object|
|
|
149
|
+
case object.type
|
|
150
|
+
when "Text"
|
|
151
|
+
text = if content_attr && !content_value.nil?
|
|
152
|
+
if use_content_index
|
|
153
|
+
content_value[text_node_index].to_s
|
|
154
|
+
elsif !content_value.is_a?(Array) && text_node_count <= 1
|
|
155
|
+
content_value.to_s
|
|
156
|
+
else
|
|
157
|
+
object.text_content || object.name
|
|
158
|
+
end
|
|
159
|
+
else
|
|
160
|
+
object.text_content || object.name
|
|
161
|
+
end
|
|
162
|
+
text_node_index += 1
|
|
163
|
+
next if text.nil?
|
|
164
|
+
# Mixed content keeps whitespace; ordered-only skips it
|
|
165
|
+
next if content_attr.nil? && text.strip.empty?
|
|
166
|
+
|
|
167
|
+
element.add_child(content_cdata ? doc.create_cdata(text) : doc.create_text_node(text))
|
|
168
|
+
when "Comment"
|
|
169
|
+
element.add_child(doc.create_comment(object.text_content))
|
|
170
|
+
when "Element"
|
|
171
|
+
entry = rows_by_name[object.name]
|
|
172
|
+
next unless entry
|
|
173
|
+
|
|
174
|
+
_, attr, kind, _spelling, delegate = entry
|
|
175
|
+
value = value_of(instance, attr, delegate)
|
|
176
|
+
case kind
|
|
177
|
+
when :collection_native, :collection_cb
|
|
178
|
+
index = element_indices[object.name]
|
|
179
|
+
items = Array(value)
|
|
180
|
+
next unless index < items.length
|
|
181
|
+
|
|
182
|
+
element_indices[object.name] += 1
|
|
183
|
+
add_leaf(element, object.name,
|
|
184
|
+
attr.serialize(items[index], :xml, reg), doc)
|
|
185
|
+
when :nested, :ordered_deferred
|
|
186
|
+
item = if attr.collection?
|
|
187
|
+
index = element_indices[object.name]
|
|
188
|
+
element_indices[object.name] += 1
|
|
189
|
+
Array(value)[index]
|
|
190
|
+
else
|
|
191
|
+
value
|
|
192
|
+
end
|
|
193
|
+
next unless item
|
|
194
|
+
|
|
195
|
+
child_plan = PlanCompiler.compile(item.class, reg)
|
|
196
|
+
child = element.create_child(child_plan[:tree][:name])
|
|
197
|
+
if child_plan[:ordered]
|
|
198
|
+
return nil unless build_ordered(child, item, child_plan,
|
|
199
|
+
doc, reg)
|
|
200
|
+
else
|
|
201
|
+
build(child, item, child_plan, doc, reg)
|
|
202
|
+
end
|
|
203
|
+
when :raw
|
|
204
|
+
element.add_child(value.to_s) unless value.nil?
|
|
205
|
+
when :scalar
|
|
206
|
+
add_leaf(element, object.name,
|
|
207
|
+
attr.serialize(value, :xml, reg), doc)
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
true
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
# Attributes in document order when the instance recorded it
|
|
215
|
+
# (parsed models), else plan row order.
|
|
216
|
+
def write_attributes(element, instance, plan, _reg = nil)
|
|
217
|
+
recorded = instance.attribute_order
|
|
218
|
+
if recorded && !recorded.empty?
|
|
219
|
+
by_name = {}
|
|
220
|
+
plan[:attr_rows].each do |rule, attr, _sp, delegate|
|
|
221
|
+
by_name[rule.name.to_s] = [rule, attr, delegate]
|
|
222
|
+
end
|
|
223
|
+
names = recorded |
|
|
224
|
+
plan[:attr_rows].map { |rule, _a, _s, _d| rule.name.to_s }
|
|
225
|
+
names.each do |name|
|
|
226
|
+
write_attribute(element, instance, name, by_name[name])
|
|
227
|
+
end
|
|
228
|
+
else
|
|
229
|
+
plan[:attr_rows].each do |rule, attr, _sp, delegate|
|
|
230
|
+
write_attribute(element, instance, rule.name.to_s,
|
|
231
|
+
[rule, attr, delegate])
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def write_attribute(element, instance, name, entry, reg = nil)
|
|
237
|
+
return unless entry
|
|
238
|
+
|
|
239
|
+
_rule, attr, delegate = entry
|
|
240
|
+
value = value_of(instance, attr, delegate)
|
|
241
|
+
return if value.nil?
|
|
242
|
+
|
|
243
|
+
element.set_attribute(name,
|
|
244
|
+
attr.serialize(value, :xml, reg || register).to_s)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Partition rows (#88) re-emit their discriminator: the wire
|
|
248
|
+
# element carries the when_attribute pairs so the round trip
|
|
249
|
+
# re-routes to the same attribute on reparse.
|
|
250
|
+
def add_leaf(element, name, value, doc, attrs: nil)
|
|
251
|
+
child = element.create_child(name)
|
|
252
|
+
attrs&.each { |k, v| child[k.to_s] = v.to_s }
|
|
253
|
+
child.add_child(doc.create_text_node(value.to_s)) unless value.nil?
|
|
254
|
+
child
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
def value_of(instance, attr, delegate)
|
|
258
|
+
if delegate
|
|
259
|
+
target = instance.public_send(delegate)
|
|
260
|
+
target&.public_send(attr.name)
|
|
261
|
+
else
|
|
262
|
+
instance.public_send(attr.name)
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def row_name(rule, spelling)
|
|
267
|
+
(spelling || rule.name).to_s
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end
|
|
273
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lutaml
|
|
4
|
+
module Xml
|
|
5
|
+
module Leptris
|
|
6
|
+
# Public consumer surface for the plan fast path: one engine
|
|
7
|
+
# parse + descriptor walk and direct model hydration, bypassing
|
|
8
|
+
# the wrapper-tree construction that dominates large-document
|
|
9
|
+
# consumer paths. The returned object is the mapped model root;
|
|
10
|
+
# collection attributes remain collections on that model.
|
|
11
|
+
module PlanWalk
|
|
12
|
+
class << self
|
|
13
|
+
# Build the plan, walk the document, and hydrate the mapped
|
|
14
|
+
# root. Returns nil when the model is not plan-compilable.
|
|
15
|
+
def call(model_class, xml, _options = {})
|
|
16
|
+
register = Lutaml::Model::Config.default_register
|
|
17
|
+
plan = PlanCompiler.compile(model_class, register)
|
|
18
|
+
return nil unless plan
|
|
19
|
+
|
|
20
|
+
document = ::Leptris::XML.parse(xml)
|
|
21
|
+
root = document.root
|
|
22
|
+
return nil unless root && root.name == plan[:tree][:name]
|
|
23
|
+
|
|
24
|
+
PlanHydrator.call(model_class, plan,
|
|
25
|
+
plan[:descriptor].walk(root),
|
|
26
|
+
node: root)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lutaml
|
|
4
|
+
module Xml
|
|
5
|
+
# The leptris plan fast path: model mapping to libleptris descriptor
|
|
6
|
+
# plan, native walk, direct hydration. Everything under this
|
|
7
|
+
# namespace is bound to the leptris gem; nothing above it may
|
|
8
|
+
# reference leptris types directly (the moxml adapters and the
|
|
9
|
+
# interpretive path never enter here).
|
|
10
|
+
module Leptris
|
|
11
|
+
# The plan path requires the one-crossing child snapshot
|
|
12
|
+
# (leptris_plan_value_children_snapshot with child handles,
|
|
13
|
+
# PlanValue#children_snapshot), which shipped in leptris
|
|
14
|
+
# 1.9.273.0. Bundles resolving an older gem keep the
|
|
15
|
+
# interpretive path — PlanCompiler.compile answers nil — the
|
|
16
|
+
# existing opt-out protocol.
|
|
17
|
+
MIN_LEPTRIS_VERSION = "1.9.273.0"
|
|
18
|
+
|
|
19
|
+
def self.plan_path_compatible?
|
|
20
|
+
return false unless defined?(Gem)
|
|
21
|
+
|
|
22
|
+
spec = Gem.loaded_specs["leptris"]
|
|
23
|
+
spec && spec.version >= Gem::Version.new(MIN_LEPTRIS_VERSION)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
autoload :PlanCompiler, "lutaml/xml/leptris/plan_compiler"
|
|
27
|
+
autoload :PlanHydrator, "lutaml/xml/leptris/plan_hydrator"
|
|
28
|
+
autoload :PlanOrder, "lutaml/xml/leptris/plan_order"
|
|
29
|
+
autoload :PlanSerializer, "lutaml/xml/leptris/plan_serializer"
|
|
30
|
+
autoload :PlanWalk, "lutaml/xml/leptris/plan_walk"
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -63,7 +63,11 @@ module Lutaml
|
|
|
63
63
|
#
|
|
64
64
|
# @return [Array<String>]
|
|
65
65
|
def xml_schema_paths
|
|
66
|
-
|
|
66
|
+
# Type check, not a probe: every Serializable carries the
|
|
67
|
+
# class method; a plain (non-Serializable) superclass ends
|
|
68
|
+
# the chain.
|
|
69
|
+
inherited = if superclass.is_a?(Class) &&
|
|
70
|
+
superclass.include?(Lutaml::Model::Serialize)
|
|
67
71
|
superclass.xml_schema_paths
|
|
68
72
|
else
|
|
69
73
|
[]
|
|
@@ -428,7 +428,7 @@ text_node_count = 0, use_content_index = false)
|
|
|
428
428
|
# reconciliation could not place
|
|
429
429
|
def apply_remaining_rules(model_instance, options, compiled_rules,
|
|
430
430
|
mapping, processed_text_nodes, fallback_rules)
|
|
431
|
-
attr_order = model_instance.
|
|
431
|
+
attr_order = model_instance.is_a?(Lutaml::Model::Serialize) &&
|
|
432
432
|
model_instance.attribute_order
|
|
433
433
|
|
|
434
434
|
rules_to_apply = if attr_order
|
|
@@ -47,7 +47,7 @@ end
|
|
|
47
47
|
|
|
48
48
|
Lutaml::Model::Config.instance.xml_plan_fast_path = true
|
|
49
49
|
measure.call("PlanWalk parse + 5000 model.new") do
|
|
50
|
-
result = Lutaml::Xml::PlanWalk.call(PlanWalkProbe::BulkRoot, xml)
|
|
50
|
+
result = Lutaml::Xml::Leptris::PlanWalk.call(PlanWalkProbe::BulkRoot, xml)
|
|
51
51
|
raise "PlanWalk returned nil" unless result&.item&.size == 5000
|
|
52
52
|
end
|
|
53
53
|
|
|
@@ -86,14 +86,18 @@ RSpec.describe Lutaml::Model::Store do
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
it "does not mix indices across different classes" do
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
# Hold strong references: Store keeps WeakRefs, so unreferenced
|
|
90
|
+
# instances can be collected between registration and resolve,
|
|
91
|
+
# making this example fail only under in-suite GC pressure.
|
|
92
|
+
a = model_class.new(id: "a")
|
|
93
|
+
b = other_class.new(id: "a")
|
|
91
94
|
|
|
92
95
|
result = described_class.resolve(model_class, :id, "a")
|
|
93
96
|
expect(result).to be_a(model_class)
|
|
94
97
|
|
|
95
98
|
result2 = described_class.resolve(other_class, :id, "a")
|
|
96
99
|
expect(result2).to be_a(other_class)
|
|
100
|
+
expect([a, b]).to all(be_a(Lutaml::Model::Serializable))
|
|
97
101
|
end
|
|
98
102
|
|
|
99
103
|
it "registering class B does not iterate class A's indices" do
|
|
@@ -57,7 +57,7 @@ RSpec.describe "XML plan fast path" do
|
|
|
57
57
|
end
|
|
58
58
|
stub_const("PlanFastPath::SelfRef", node)
|
|
59
59
|
|
|
60
|
-
expect(Lutaml::Xml::PlanCompiler.compile(node, :default)).to be_nil
|
|
60
|
+
expect(Lutaml::Xml::Leptris::PlanCompiler.compile(node, :default)).to be_nil
|
|
61
61
|
|
|
62
62
|
xml = "<n>#{'<n>t</n>' * 200}</n>"
|
|
63
63
|
parsed = node.from_xml(xml)
|
|
@@ -94,7 +94,7 @@ RSpec.describe "XML plan fast path" do
|
|
|
94
94
|
|
|
95
95
|
expect(parsed.xmi_type).to eq("uml:Parameter")
|
|
96
96
|
expect(parsed.classifier_type).to eq("EAnone_void")
|
|
97
|
-
expect(Lutaml::Xml::PlanCompiler.compile(parameter, :default)).to be_nil
|
|
97
|
+
expect(Lutaml::Xml::Leptris::PlanCompiler.compile(parameter, :default)).to be_nil
|
|
98
98
|
end
|
|
99
99
|
|
|
100
100
|
it "is on by default and can be disabled" do
|
|
@@ -156,7 +156,7 @@ RSpec.describe "XML plan fast path" do
|
|
|
156
156
|
end
|
|
157
157
|
end
|
|
158
158
|
|
|
159
|
-
expect(Lutaml::Xml::PlanCompiler.compile(klass,
|
|
159
|
+
expect(Lutaml::Xml::Leptris::PlanCompiler.compile(klass,
|
|
160
160
|
Lutaml::Model::Config.default_register)).not_to be_nil
|
|
161
161
|
expect(klass.from_xml("<doc><note>hi</note></doc>").note).to eq("HI")
|
|
162
162
|
end
|
|
@@ -223,14 +223,14 @@ RSpec.describe "XML plan fast path" do
|
|
|
223
223
|
end
|
|
224
224
|
end
|
|
225
225
|
|
|
226
|
-
expect(Lutaml::Xml::PlanCompiler.compile(klass,
|
|
226
|
+
expect(Lutaml::Xml::Leptris::PlanCompiler.compile(klass,
|
|
227
227
|
Lutaml::Model::Config.default_register)).not_to be_nil
|
|
228
228
|
parsed = klass.from_xml("<doc><note>hi</note></doc>")
|
|
229
229
|
expect(parsed.tgt.note).to eq("hi")
|
|
230
230
|
end
|
|
231
231
|
|
|
232
232
|
it "routes a single collection row natively (hybrid routing)" do
|
|
233
|
-
plan = Lutaml::Xml::PlanCompiler.compile(
|
|
233
|
+
plan = Lutaml::Xml::Leptris::PlanCompiler.compile(
|
|
234
234
|
Class.new(Lutaml::Model::Serializable) do
|
|
235
235
|
attribute :xs, :string, collection: true
|
|
236
236
|
attribute :name, :string
|
|
@@ -400,7 +400,7 @@ RSpec.describe "XML plan fast path" do
|
|
|
400
400
|
map_element "para", to: :para
|
|
401
401
|
end
|
|
402
402
|
end
|
|
403
|
-
plan = Lutaml::Xml::PlanCompiler.compile(
|
|
403
|
+
plan = Lutaml::Xml::Leptris::PlanCompiler.compile(
|
|
404
404
|
doc_class, Lutaml::Model::Config.default_register
|
|
405
405
|
)
|
|
406
406
|
expect(plan).not_to be_nil
|
|
@@ -623,7 +623,7 @@ RSpec.describe "XML plan fast path" do
|
|
|
623
623
|
expect(req.guidance.map(&:text)).to eq(%w[g1 g2])
|
|
624
624
|
expect(req.purpose.map(&:text)).to eq(["p1"])
|
|
625
625
|
|
|
626
|
-
expect(Lutaml::Xml::PlanCompiler.compile(partitioned,
|
|
626
|
+
expect(Lutaml::Xml::Leptris::PlanCompiler.compile(partitioned,
|
|
627
627
|
:default)).to be_nil
|
|
628
628
|
end
|
|
629
629
|
|
|
@@ -708,7 +708,7 @@ RSpec.describe "XML plan fast path" do
|
|
|
708
708
|
stub_const("PlanFastPath::UpdateFields847", klass)
|
|
709
709
|
|
|
710
710
|
expect(klass.new(value: false).to_xml).to include("http://example.com/ord847")
|
|
711
|
-
plan = Lutaml::Xml::PlanCompiler.compile(
|
|
711
|
+
plan = Lutaml::Xml::Leptris::PlanCompiler.compile(
|
|
712
712
|
klass, Lutaml::Model::Config.default_register
|
|
713
713
|
)
|
|
714
714
|
expect(plan[:namespaced]).to be(true)
|
|
@@ -37,7 +37,7 @@ RSpec.describe "Plan fast path with when_attribute partitions" do
|
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
it "compiles the partitioned model with row tags" do
|
|
40
|
-
plan = Lutaml::Xml::PlanCompiler.compile(
|
|
40
|
+
plan = Lutaml::Xml::Leptris::PlanCompiler.compile(
|
|
41
41
|
model, Lutaml::Model::Config.default_register
|
|
42
42
|
)
|
|
43
43
|
expect(plan).not_to be_nil
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
|
-
require "lutaml/xml/plan_walk"
|
|
4
|
+
require "lutaml/xml/leptris/plan_walk"
|
|
5
5
|
|
|
6
6
|
RSpec.describe "XML PlanWalk consumer surface" do
|
|
7
7
|
around do |example|
|
|
@@ -25,7 +25,7 @@ RSpec.describe "XML PlanWalk consumer surface" do
|
|
|
25
25
|
|
|
26
26
|
it "hydrates equal to the interpretive path on a single-row document" do
|
|
27
27
|
xml = %(<row id="7"><name>Alice</name><tags>x</tags><tags>y</tags></row>)
|
|
28
|
-
walked = Lutaml::Xml::PlanWalk.call(item_class, xml)
|
|
28
|
+
walked = Lutaml::Xml::Leptris::PlanWalk.call(item_class, xml)
|
|
29
29
|
expected = item_class.from_xml(xml)
|
|
30
30
|
|
|
31
31
|
expect(walked).to be_a(item_class)
|
|
@@ -46,7 +46,7 @@ RSpec.describe "XML PlanWalk consumer surface" do
|
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
-
walked = Lutaml::Xml::PlanWalk.call(root_class, xml)
|
|
49
|
+
walked = Lutaml::Xml::Leptris::PlanWalk.call(root_class, xml)
|
|
50
50
|
expected = root_class.from_xml(xml)
|
|
51
51
|
|
|
52
52
|
expect(walked.item).to be_an(Array)
|
|
@@ -71,7 +71,7 @@ RSpec.describe "XML PlanWalk consumer surface" do
|
|
|
71
71
|
end
|
|
72
72
|
end
|
|
73
73
|
|
|
74
|
-
walked = Lutaml::Xml::PlanWalk.call(root_class, xml)
|
|
74
|
+
walked = Lutaml::Xml::Leptris::PlanWalk.call(root_class, xml)
|
|
75
75
|
interpretive = root_class.from_xml(xml)
|
|
76
76
|
expect(walked.item.size).to eq(interpretive.item.size)
|
|
77
77
|
expect(walked.item.map(&:id)).to eq(interpretive.item.map(&:id))
|
|
@@ -94,9 +94,9 @@ RSpec.describe "XML PlanWalk consumer surface" do
|
|
|
94
94
|
end
|
|
95
95
|
end
|
|
96
96
|
|
|
97
|
-
expect(Lutaml::Xml::PlanCompiler.compile(klass,
|
|
97
|
+
expect(Lutaml::Xml::Leptris::PlanCompiler.compile(klass,
|
|
98
98
|
Lutaml::Model::Config.default_register)).not_to be_nil
|
|
99
|
-
expect(Lutaml::Xml::PlanWalk.call(klass, "<doc><note>x</note></doc>").tgt.note)
|
|
99
|
+
expect(Lutaml::Xml::Leptris::PlanWalk.call(klass, "<doc><note>x</note></doc>").tgt.note)
|
|
100
100
|
.to eq("x")
|
|
101
101
|
end
|
|
102
102
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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.85
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -781,7 +781,13 @@ files:
|
|
|
781
781
|
- lib/lutaml/xml/format_chooser.rb
|
|
782
782
|
- lib/lutaml/xml/hoisting_algorithm.rb
|
|
783
783
|
- lib/lutaml/xml/html_entities.rb
|
|
784
|
+
- lib/lutaml/xml/leptris.rb
|
|
784
785
|
- lib/lutaml/xml/leptris/element.rb
|
|
786
|
+
- lib/lutaml/xml/leptris/plan_compiler.rb
|
|
787
|
+
- lib/lutaml/xml/leptris/plan_hydrator.rb
|
|
788
|
+
- lib/lutaml/xml/leptris/plan_order.rb
|
|
789
|
+
- lib/lutaml/xml/leptris/plan_serializer.rb
|
|
790
|
+
- lib/lutaml/xml/leptris/plan_walk.rb
|
|
785
791
|
- lib/lutaml/xml/listener.rb
|
|
786
792
|
- lib/lutaml/xml/mapping.rb
|
|
787
793
|
- lib/lutaml/xml/mapping_rule.rb
|
|
@@ -810,11 +816,6 @@ files:
|
|
|
810
816
|
- lib/lutaml/xml/parse_session.rb
|
|
811
817
|
- lib/lutaml/xml/parsed_namespace_declaration.rb
|
|
812
818
|
- lib/lutaml/xml/parsed_namespace_set.rb
|
|
813
|
-
- lib/lutaml/xml/plan_compiler.rb
|
|
814
|
-
- lib/lutaml/xml/plan_hydrator.rb
|
|
815
|
-
- lib/lutaml/xml/plan_order.rb
|
|
816
|
-
- lib/lutaml/xml/plan_serializer.rb
|
|
817
|
-
- lib/lutaml/xml/plan_walk.rb
|
|
818
819
|
- lib/lutaml/xml/polymorphic_value_handler.rb
|
|
819
820
|
- lib/lutaml/xml/qualified_inheritance_strategy.rb
|
|
820
821
|
- lib/lutaml/xml/rexml.rb
|