lutaml-model 0.8.56 → 0.8.58
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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9c115914d1bb1d737ad93c4ef3d5ecb9090200d8fd3558309421e23fca5a9171
|
|
4
|
+
data.tar.gz: a017029e28d68c4eda43e5e4a79733b6f31c4258ccfb47b0969dae50fe9f0107
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5a9f912ee3bdd11d2fe2266b2de6880553fe64ab95cc6891a5184bf067205a9ab76fc61faee3812ded44af10dcc430f5b7aa6acc6051c6dfdcd622c5276127cc
|
|
7
|
+
data.tar.gz: 61b39b97fe5c532f4aa367b2c7c9d5efe5b43acc786bfe192832d3379f8b8f7b253538550478028f676ea7b8c5e31f5dea5cda189374318bcab7ea0f1c441a32
|
|
@@ -103,7 +103,8 @@ module Lutaml
|
|
|
103
103
|
|
|
104
104
|
register = Lutaml::Model::Config.default_register
|
|
105
105
|
plan = Lutaml::Xml::PlanCompiler.compile(self, register)
|
|
106
|
-
return nil unless plan &&
|
|
106
|
+
return nil unless plan && !plan[:namespaced] &&
|
|
107
|
+
Lutaml::Xml::PlanSerializer.serializable?(plan)
|
|
107
108
|
|
|
108
109
|
Lutaml::Xml::PlanSerializer.call(instance, plan)
|
|
109
110
|
end
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -213,6 +213,12 @@ module Lutaml
|
|
|
213
213
|
|
|
214
214
|
row_tags = partition_row_tags!(compiled, rows, tag)
|
|
215
215
|
|
|
216
|
+
# The plan serializer does not emit namespace declarations —
|
|
217
|
+
# namespaced models serialize through the interpretive
|
|
218
|
+
# writer (lutaml-model#847: standalone to_xml under leptris
|
|
219
|
+
# dropped the element xmlns entirely).
|
|
220
|
+
namespaced = !model_ns.nil? || rows.any? { |r| r[:ns] }
|
|
221
|
+
|
|
216
222
|
flags = []
|
|
217
223
|
flags << :cdata if cdata
|
|
218
224
|
flags << :mixed_content if mixed_content
|
|
@@ -233,7 +239,7 @@ module Lutaml
|
|
|
233
239
|
|
|
234
240
|
{ descriptor: descriptor, tree: tree, rows: compiled,
|
|
235
241
|
attr_rows: attr_rows, mapping: mapping,
|
|
236
|
-
row_tags: row_tags,
|
|
242
|
+
row_tags: row_tags, namespaced: namespaced,
|
|
237
243
|
ordered: mapping.ordered? || mapping.mixed_content?,
|
|
238
244
|
needs_nodes: needs_nodes,
|
|
239
245
|
collection_defaults: collection_defaults }
|
|
@@ -22,7 +22,7 @@ module Lutaml
|
|
|
22
22
|
# hydrate natively against their own nodes
|
|
23
23
|
def call(model_class, plan, value, parent: nil, node: nil)
|
|
24
24
|
buckets = node && plan[:needs_nodes] ? element_buckets(node) : nil
|
|
25
|
-
attr_kwargs = attributes_kwargs(plan, value)
|
|
25
|
+
attr_kwargs = attributes_kwargs(plan, value, node)
|
|
26
26
|
child_kwargs, children, delegates =
|
|
27
27
|
children_kwargs(model_class, plan, value, buckets)
|
|
28
28
|
plan[:collection_defaults].each do |name|
|
|
@@ -53,10 +53,18 @@ module Lutaml
|
|
|
53
53
|
Lutaml::Model::Config.default_register
|
|
54
54
|
end
|
|
55
55
|
|
|
56
|
-
def attributes_kwargs(plan, value)
|
|
56
|
+
def attributes_kwargs(plan, value, node = nil)
|
|
57
57
|
kwargs = {}
|
|
58
|
+
sole_claimants = sole_claimant_names(plan)
|
|
58
59
|
plan[:attr_rows].each do |rule, attr|
|
|
59
60
|
v = value.attribute(rule.name.to_s)
|
|
61
|
+
if v.nil? && node && sole_claimants.include?(rule.name.to_s)
|
|
62
|
+
# #754/#790 parity: a sole-claimant attribute rule binds
|
|
63
|
+
# any qualification (the interpretive matcher's lenient
|
|
64
|
+
# recovery). The walk captures exact (URI, local) matches
|
|
65
|
+
# only, so the qualified spelling is read off the node.
|
|
66
|
+
v = lenient_node_attribute(node, rule.name.to_s)
|
|
67
|
+
end
|
|
60
68
|
next if v.nil?
|
|
61
69
|
|
|
62
70
|
v = v.split(rule.delimiter) if rule.delimiter
|
|
@@ -331,6 +339,31 @@ module Lutaml
|
|
|
331
339
|
Lutaml::Xml::Adapter::LeptrisAdapter.parse(raw).root
|
|
332
340
|
end
|
|
333
341
|
|
|
342
|
+
# Attribute names claimed by exactly one attr row — the only
|
|
343
|
+
# names eligible for #754/#790 lenient binding (multi-claimant
|
|
344
|
+
# names stay exact; per #841 leniency is sole-claimant-only).
|
|
345
|
+
def sole_claimant_names(plan)
|
|
346
|
+
plan[:attr_rows].map { |rule, _attr| rule.name.to_s }
|
|
347
|
+
.tally
|
|
348
|
+
.select { |_n, c| c == 1 }
|
|
349
|
+
.keys
|
|
350
|
+
end
|
|
351
|
+
|
|
352
|
+
# Local-name attribute lookup on the source node, qualified
|
|
353
|
+
# spellings included (w:val matches rule "val").
|
|
354
|
+
def lenient_node_attribute(node, local_name)
|
|
355
|
+
return nil unless node.respond_to?(:attributes)
|
|
356
|
+
|
|
357
|
+
node.attributes.each_value do |attr|
|
|
358
|
+
# Leptris::XML::Attr carries the raw (possibly prefixed)
|
|
359
|
+
# name; strip the prefix for the local-name comparison.
|
|
360
|
+
name = attr.name.to_s
|
|
361
|
+
name = name.split(":").last if name.include?(":")
|
|
362
|
+
return attr.value if name == local_name
|
|
363
|
+
end
|
|
364
|
+
nil
|
|
365
|
+
end
|
|
366
|
+
|
|
334
367
|
def group_children(value, row_tags = nil)
|
|
335
368
|
grouped = {}
|
|
336
369
|
tagged = {}
|
|
@@ -688,4 +688,56 @@ RSpec.describe "XML plan fast path" do
|
|
|
688
688
|
expect(parsed.to_xml).to eq(xml)
|
|
689
689
|
end
|
|
690
690
|
end
|
|
691
|
+
|
|
692
|
+
# lutaml-model#847: the plan serializer does not emit namespace
|
|
693
|
+
# declarations — namespaced models must serialize through the
|
|
694
|
+
# interpretive writer even standalone, or the element xmlns is lost.
|
|
695
|
+
it "falls back to the interpretive writer for namespaced models" do
|
|
696
|
+
ns = Class.new(Lutaml::Xml::Namespace) do
|
|
697
|
+
uri "http://example.com/ord847"
|
|
698
|
+
end
|
|
699
|
+
stub_const("PlanFastPath::Ord847Ns", ns)
|
|
700
|
+
klass = Class.new(Lutaml::Model::Serializable) do
|
|
701
|
+
attribute :value, :boolean
|
|
702
|
+
xml do
|
|
703
|
+
element "updateFields"
|
|
704
|
+
namespace PlanFastPath::Ord847Ns
|
|
705
|
+
map_attribute "val", to: :value
|
|
706
|
+
end
|
|
707
|
+
end
|
|
708
|
+
stub_const("PlanFastPath::UpdateFields847", klass)
|
|
709
|
+
|
|
710
|
+
expect(klass.new(value: false).to_xml).to include("http://example.com/ord847")
|
|
711
|
+
plan = Lutaml::Xml::PlanCompiler.compile(
|
|
712
|
+
klass, Lutaml::Model::Config.default_register
|
|
713
|
+
)
|
|
714
|
+
expect(plan[:namespaced]).to be(true)
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
# lutaml-model#850: a sole-claimant attribute rule binds any
|
|
718
|
+
# qualification on the plan path (#754/#790 parity with the
|
|
719
|
+
# interpretive matcher) — the qualified spelling is read off the
|
|
720
|
+
# source node when the exact (URI, local) walk capture misses.
|
|
721
|
+
it "binds qualified spellings to sole-claimant attribute rules" do
|
|
722
|
+
ns = Class.new(Lutaml::Xml::Namespace) do
|
|
723
|
+
uri "http://example.com/w"
|
|
724
|
+
prefix_default "w"
|
|
725
|
+
end
|
|
726
|
+
stub_const("PlanFastPath::W850Ns", ns)
|
|
727
|
+
klass = Class.new(Lutaml::Model::Serializable) do
|
|
728
|
+
attribute :value, :boolean
|
|
729
|
+
xml do
|
|
730
|
+
element "b"
|
|
731
|
+
namespace PlanFastPath::W850Ns
|
|
732
|
+
map_attribute "val", to: :value
|
|
733
|
+
end
|
|
734
|
+
end
|
|
735
|
+
stub_const("PlanFastPath::Sole850", klass)
|
|
736
|
+
|
|
737
|
+
doc = %(<w:b xmlns:w="http://example.com/w" w:val="false"/>)
|
|
738
|
+
expect(klass.from_xml(doc).value).to be(false)
|
|
739
|
+
expect(klass.from_xml(
|
|
740
|
+
%(<b xmlns="http://example.com/w" val="false"/>),
|
|
741
|
+
).value).to be(false)
|
|
742
|
+
end
|
|
691
743
|
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.58
|
|
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-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|