lutaml-model 0.8.57 → 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 +4 -4
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/xml/plan_hydrator.rb +35 -2
- data/spec/lutaml/xml/plan_fast_path_spec.rb +27 -0
- metadata +2 -2
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
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -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 = {}
|
|
@@ -713,4 +713,31 @@ RSpec.describe "XML plan fast path" do
|
|
|
713
713
|
)
|
|
714
714
|
expect(plan[:namespaced]).to be(true)
|
|
715
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
|
|
716
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
|