lutaml-model 0.8.130 → 0.8.132
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/docs/key_value_data_model.adoc +9 -9
- data/lib/lutaml/json/adapter/multi_json_adapter.rb +1 -7
- data/lib/lutaml/json/adapter/oj_adapter.rb +1 -7
- data/lib/lutaml/json/adapter/standard_adapter.rb +1 -7
- data/lib/lutaml/key_value/adapter/json/multi_json_adapter.rb +1 -7
- data/lib/lutaml/key_value/adapter/json/oj_adapter.rb +1 -7
- data/lib/lutaml/key_value/adapter/json/standard_adapter.rb +1 -7
- data/lib/lutaml/key_value/adapter/toml/teptris_adapter.rb +1 -7
- data/lib/lutaml/key_value/adapter/toml/toml_rb_adapter.rb +1 -7
- data/lib/lutaml/key_value/adapter/toml/tomlib_adapter.rb +1 -7
- data/lib/lutaml/key_value/adapter/yaml/standard_adapter.rb +1 -7
- data/lib/lutaml/key_value/data_model/element.rb +31 -32
- data/lib/lutaml/key_value/transform.rb +24 -8
- data/lib/lutaml/key_value/transformation/value_serializer.rb +14 -2
- data/lib/lutaml/key_value/transformation.rb +33 -20
- data/lib/lutaml/model/attribute.rb +15 -2
- data/lib/lutaml/model/collection.rb +1 -5
- data/lib/lutaml/model/schema/xml_compiler/spec_builder/complex_types.rb +9 -4
- data/lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb +15 -8
- data/lib/lutaml/model/schema/xml_compiler/spec_builder.rb +2 -2
- data/lib/lutaml/model/schema/xml_compiler/supported_data_types.rb +10 -0
- data/lib/lutaml/model/serialize/attribute_definition.rb +57 -4
- data/lib/lutaml/model/transform.rb +78 -25
- data/lib/lutaml/model/type_context.rb +9 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/toml/adapter/toml_rb_adapter.rb +1 -7
- data/lib/lutaml/toml/adapter/tomlib_adapter.rb +1 -7
- data/lib/lutaml/xml/builder/base.rb +3 -1
- data/lib/lutaml/xml/transformation/rule_compiler.rb +2 -2
- data/lib/lutaml/yaml/adapter/standard_adapter.rb +1 -7
- data/lib/lutaml/yaml/adapter/yeptris_adapter.rb +1 -7
- data/lib/lutaml/yamlld/adapter.rb +1 -6
- data/spec/lutaml/key_value/adapter/toml/teptris_adapter_spec.rb +3 -3
- data/spec/lutaml/key_value/transformation_spec.rb +50 -50
- data/spec/lutaml/model/collection_spec.rb +43 -0
- data/spec/lutaml/model/schema/xml_compiler_runtime_spec.rb +81 -0
- metadata +2 -2
|
@@ -110,8 +110,11 @@ module Lutaml
|
|
|
110
110
|
end
|
|
111
111
|
|
|
112
112
|
local = Utils.last_of_split(raw_type)
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
primitive = SupportedDataTypes.primitive_symbol(local)
|
|
114
|
+
Definitions::TypeRef.new(
|
|
115
|
+
kind: :symbol,
|
|
116
|
+
value: primitive || Utils.snake_case(local),
|
|
117
|
+
)
|
|
115
118
|
end
|
|
116
119
|
|
|
117
120
|
private
|
|
@@ -169,8 +172,10 @@ module Lutaml
|
|
|
169
172
|
element.simple_type)
|
|
170
173
|
end
|
|
171
174
|
if element.complex_type
|
|
172
|
-
return register_anonymous_complex_type(
|
|
173
|
-
|
|
175
|
+
return register_anonymous_complex_type(
|
|
176
|
+
"CT_#{element.name}", element.complex_type,
|
|
177
|
+
root_name: element.name
|
|
178
|
+
)
|
|
174
179
|
end
|
|
175
180
|
|
|
176
181
|
"string"
|
|
@@ -184,8 +189,10 @@ module Lutaml
|
|
|
184
189
|
end
|
|
185
190
|
|
|
186
191
|
if item.respond_to?(:complex_type) && item.complex_type
|
|
187
|
-
register_anonymous_complex_type(
|
|
188
|
-
|
|
192
|
+
register_anonymous_complex_type(
|
|
193
|
+
"CT_#{item.name}", item.complex_type,
|
|
194
|
+
root_name: item.name
|
|
195
|
+
)
|
|
189
196
|
end
|
|
190
197
|
end
|
|
191
198
|
|
|
@@ -196,10 +203,10 @@ module Lutaml
|
|
|
196
203
|
anon_name
|
|
197
204
|
end
|
|
198
205
|
|
|
199
|
-
def register_anonymous_complex_type(anon_name, anon_node)
|
|
206
|
+
def register_anonymous_complex_type(anon_name, anon_node, root_name: nil)
|
|
200
207
|
anon_node.name = anon_name
|
|
201
208
|
@parent.complex_types[anon_name] =
|
|
202
|
-
@parent.build_complex_type(anon_node)
|
|
209
|
+
@parent.build_complex_type(anon_node, root_name: root_name)
|
|
203
210
|
anon_name
|
|
204
211
|
end
|
|
205
212
|
|
|
@@ -156,8 +156,8 @@ module Lutaml
|
|
|
156
156
|
@simple_types_builder.build(simple_type)
|
|
157
157
|
end
|
|
158
158
|
|
|
159
|
-
def build_complex_type(complex_type)
|
|
160
|
-
@complex_types_builder.build(complex_type)
|
|
159
|
+
def build_complex_type(complex_type, root_name: nil)
|
|
160
|
+
@complex_types_builder.build(complex_type, root_name: root_name)
|
|
161
161
|
end
|
|
162
162
|
|
|
163
163
|
private
|
|
@@ -83,6 +83,16 @@ module Lutaml
|
|
|
83
83
|
def skippable?(value)
|
|
84
84
|
SKIPPABLE_NAMES.include?(value.to_s)
|
|
85
85
|
end
|
|
86
|
+
|
|
87
|
+
# Lutaml primitive symbol for a skippable XSD type
|
|
88
|
+
# (`"int"` -> `:integer`, `"dateTime"` -> `:date_time`); nil
|
|
89
|
+
# when the name is not a skippable built-in.
|
|
90
|
+
def primitive_symbol(value)
|
|
91
|
+
info = TABLE[value.to_sym]
|
|
92
|
+
return nil unless info && info[:skippable]
|
|
93
|
+
|
|
94
|
+
Utils.snake_case(info[:class_name].split("::").last)
|
|
95
|
+
end
|
|
86
96
|
end
|
|
87
97
|
end
|
|
88
98
|
end
|
|
@@ -142,6 +142,7 @@ module Lutaml
|
|
|
142
142
|
marks = {}
|
|
143
143
|
simple = []
|
|
144
144
|
complex = []
|
|
145
|
+
lazy = []
|
|
145
146
|
attrs.each do |name, attr|
|
|
146
147
|
next if attr.derived?
|
|
147
148
|
|
|
@@ -154,8 +155,17 @@ module Lutaml
|
|
|
154
155
|
# per-attribute code, so its state is identical by
|
|
155
156
|
# construction.
|
|
156
157
|
marks[name] = false
|
|
157
|
-
|
|
158
|
-
|
|
158
|
+
plain_name = name.to_s.match?(PLAIN_NAME)
|
|
159
|
+
if plain_name && attr.lazy_collection_default?
|
|
160
|
+
# The implicit empty-collection default: the constructor
|
|
161
|
+
# ends at `[]` + a default mark, and the LAZY sentinel
|
|
162
|
+
# answers `[]` from the reader — so seed the sentinel and
|
|
163
|
+
# skip the per-instance lambda (#1010). The false mark is
|
|
164
|
+
# what the XML unmatched-rule contract reads: a seeded
|
|
165
|
+
# collection must not render as a mid-parse default.
|
|
166
|
+
lazy << name
|
|
167
|
+
elsif attr.default_kind == :none && attr.options[:values].nil? &&
|
|
168
|
+
plain_name
|
|
159
169
|
simple << name
|
|
160
170
|
else
|
|
161
171
|
complex << name
|
|
@@ -169,6 +179,9 @@ module Lutaml
|
|
|
169
179
|
"@using_default = { #{pairs.join(', ')} }"
|
|
170
180
|
end
|
|
171
181
|
simple_lines = simple.map { |n| "@#{n} = nil" }
|
|
182
|
+
lazy_lines = lazy.map do |n|
|
|
183
|
+
"@#{n} = Lutaml::Model::Serialize::LAZY_EMPTY_COLLECTION"
|
|
184
|
+
end
|
|
172
185
|
complex_lines = complex.map do |n|
|
|
173
186
|
"initialize_single_attribute({}, #{n.inspect}, " \
|
|
174
187
|
"self.class.attributes(@lutaml_register)[#{n.inspect}], " \
|
|
@@ -179,6 +192,11 @@ module Lutaml
|
|
|
179
192
|
define_method(method_name) do
|
|
180
193
|
@using_default = marks
|
|
181
194
|
simple.each { |n| IVAR_SET.bind_call(self, :"@#{n}", nil) }
|
|
195
|
+
lazy.each do |n|
|
|
196
|
+
IVAR_SET.bind_call(
|
|
197
|
+
self, :"@#{n}", Lutaml::Model::Serialize::LAZY_EMPTY_COLLECTION
|
|
198
|
+
)
|
|
199
|
+
end
|
|
182
200
|
complex.each do |n|
|
|
183
201
|
initialize_single_attribute(
|
|
184
202
|
{}, n, self.class.attributes(@lutaml_register)[n],
|
|
@@ -193,6 +211,7 @@ module Lutaml
|
|
|
193
211
|
def #{method_name}
|
|
194
212
|
#{marks_line}
|
|
195
213
|
#{simple_lines.join("\n")}
|
|
214
|
+
#{lazy_lines.join("\n")}
|
|
196
215
|
#{complex_lines.join("\n")}
|
|
197
216
|
end
|
|
198
217
|
RUBY
|
|
@@ -452,7 +471,7 @@ module Lutaml
|
|
|
452
471
|
|
|
453
472
|
if !AttributeDefinition.source_compilation?
|
|
454
473
|
define_block_attribute_setters(name, attr)
|
|
455
|
-
elsif attr.collection?
|
|
474
|
+
elsif attr.collection? && !attr.lazy_collection_default?
|
|
456
475
|
# class_eval interpolates, e.g.:
|
|
457
476
|
# def items=(value)
|
|
458
477
|
# value_set_for(:items)
|
|
@@ -493,6 +512,25 @@ module Lutaml
|
|
|
493
512
|
record_mutation_collection(:#{name}, value)
|
|
494
513
|
end
|
|
495
514
|
RUBY
|
|
515
|
+
elsif attr.collection?
|
|
516
|
+
# Lazy-seeded default collections (#1010): a nil write is a
|
|
517
|
+
# real state here (initialize_empty reads nil after an
|
|
518
|
+
# explicit nil value), so it must land over the sentinel
|
|
519
|
+
# instead of preserving it.
|
|
520
|
+
class_eval(<<~RUBY, __FILE__, __LINE__ + 1) # rubocop:disable Style/DocumentDynamicEvalDefinition
|
|
521
|
+
def #{name}=(value)
|
|
522
|
+
value_set_for(:#{name})
|
|
523
|
+
value = __attribute_definition_#{name}.cast_value(value, lutaml_register)
|
|
524
|
+
@#{name} = value
|
|
525
|
+
record_mutation_collection(:#{name}, value)
|
|
526
|
+
end
|
|
527
|
+
|
|
528
|
+
def __assign_parsed_#{name}=(value)
|
|
529
|
+
value_set_for(:#{name})
|
|
530
|
+
@#{name} = value
|
|
531
|
+
record_mutation_collection(:#{name}, value)
|
|
532
|
+
end
|
|
533
|
+
RUBY
|
|
496
534
|
else
|
|
497
535
|
class_eval(<<~RUBY, __FILE__, __LINE__ + 1) # rubocop:disable Style/DocumentDynamicEvalDefinition
|
|
498
536
|
def #{name}=(value)
|
|
@@ -551,7 +589,7 @@ module Lutaml
|
|
|
551
589
|
name = name.to_sym # the compiled form passes :name literals
|
|
552
590
|
ivar = :"@#{name}"
|
|
553
591
|
handle = :"__attribute_definition_#{name}"
|
|
554
|
-
if attr.collection?
|
|
592
|
+
if attr.collection? && !attr.lazy_collection_default?
|
|
555
593
|
assign = lambda do |model, value|
|
|
556
594
|
current = IVAR_GET.bind_call(model, ivar)
|
|
557
595
|
unless current.equal?(Lutaml::Model::Serialize::LAZY_EMPTY_COLLECTION) &&
|
|
@@ -568,6 +606,21 @@ module Lutaml
|
|
|
568
606
|
value_set_for(name)
|
|
569
607
|
assign.call(self, value)
|
|
570
608
|
end
|
|
609
|
+
elsif attr.collection?
|
|
610
|
+
# Lazy-seeded default collections (#1010): nil lands over the
|
|
611
|
+
# sentinel — see the source-compiled branch.
|
|
612
|
+
assign = lambda do |model, value|
|
|
613
|
+
IVAR_SET.bind_call(model, ivar, value)
|
|
614
|
+
SEND.bind_call(model, :record_mutation_collection, name, value)
|
|
615
|
+
end
|
|
616
|
+
define_method(:"#{name}=") do |value|
|
|
617
|
+
value_set_for(name)
|
|
618
|
+
assign.call(self, SEND.bind_call(self, handle).cast_value(value, lutaml_register))
|
|
619
|
+
end
|
|
620
|
+
define_method(:"__assign_parsed_#{name}=") do |value|
|
|
621
|
+
value_set_for(name)
|
|
622
|
+
assign.call(self, value)
|
|
623
|
+
end
|
|
571
624
|
else
|
|
572
625
|
define_method(:"#{name}=") do |value|
|
|
573
626
|
value_set_for(name)
|
|
@@ -3,12 +3,81 @@
|
|
|
3
3
|
module Lutaml
|
|
4
4
|
module Model
|
|
5
5
|
class Transform
|
|
6
|
-
@transform_cache = {}
|
|
7
|
-
|
|
8
6
|
# Maximum number of cached Transform instances before eviction.
|
|
9
7
|
# Covers most OOXML/ISO schemas with ~1000+ classes and multiple registers.
|
|
10
8
|
MAX_CACHE_SIZE = 2048
|
|
11
9
|
|
|
10
|
+
# The (lane, context, register) memo lives in a shared constant,
|
|
11
|
+
# not in class-level ivars: KeyValue::Transform subclasses this
|
|
12
|
+
# class, and inherited class methods run with the subclass as
|
|
13
|
+
# self — ivar state forked per subclass, and clear_cache! on the
|
|
14
|
+
# base class never reached the subclass's copy (stale compiled
|
|
15
|
+
# plans across register resets). The lane is part of the key:
|
|
16
|
+
# each transform class compiles format-specific rules, so a KV
|
|
17
|
+
# transform and the base one must never answer for each other.
|
|
18
|
+
class TransformCache
|
|
19
|
+
attr_reader :size
|
|
20
|
+
|
|
21
|
+
def initialize
|
|
22
|
+
@entries = {}
|
|
23
|
+
@size = 0
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Nested memo, not an array key: the hot path is one lookup per
|
|
27
|
+
# parsed node and the key array was that lookup's only
|
|
28
|
+
# allocation (60k arrays on a 6k-node corpus).
|
|
29
|
+
def fetch_or_store(lane, context, register)
|
|
30
|
+
by_context = @entries[lane]
|
|
31
|
+
by_register = by_context&.[](context)
|
|
32
|
+
return by_register[register] if by_register&.key?(register)
|
|
33
|
+
|
|
34
|
+
by_register = ((@entries[lane] ||= {})[context] ||= {})
|
|
35
|
+
transform = yield
|
|
36
|
+
by_register[register] = transform
|
|
37
|
+
@size += 1
|
|
38
|
+
transform
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def evict_half_if_full
|
|
42
|
+
return unless @size >= MAX_CACHE_SIZE
|
|
43
|
+
|
|
44
|
+
drop = @size / 2
|
|
45
|
+
@entries.each do |lane, by_context|
|
|
46
|
+
by_context.each do |ctx, by_register|
|
|
47
|
+
break if drop <= 0
|
|
48
|
+
|
|
49
|
+
drop -= by_register.size
|
|
50
|
+
by_context.delete(ctx)
|
|
51
|
+
end
|
|
52
|
+
@entries.delete(lane) if by_context.empty?
|
|
53
|
+
break if drop <= 0
|
|
54
|
+
end
|
|
55
|
+
@size = @entries.sum { |_, by_context| by_context.sum { |_, br| br.size } }
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def invalidate(context, register = nil)
|
|
59
|
+
@entries.each_value do |by_context|
|
|
60
|
+
if register
|
|
61
|
+
by_register = by_context[context]
|
|
62
|
+
next unless by_register&.delete(register)
|
|
63
|
+
|
|
64
|
+
@size -= 1
|
|
65
|
+
by_context.delete(context) if by_register.empty?
|
|
66
|
+
else
|
|
67
|
+
removed = by_context.delete(context)
|
|
68
|
+
@size -= removed.size if removed
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def clear
|
|
74
|
+
@entries.clear
|
|
75
|
+
@size = 0
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
TRANSFORM_CACHE = TransformCache.new
|
|
80
|
+
|
|
12
81
|
def self.data_to_model(context, data, format, options = {})
|
|
13
82
|
register = options[:register] || Lutaml::Model::Config.default_register
|
|
14
83
|
transform = cached_transform(context, register, options[:mappings])
|
|
@@ -28,13 +97,10 @@ module Lutaml
|
|
|
28
97
|
def self.cached_transform(context, register, mappings = nil)
|
|
29
98
|
return override_transform(context, register, mappings) if mappings
|
|
30
99
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
evict_if_needed if @transform_cache.size >= MAX_CACHE_SIZE
|
|
37
|
-
@transform_cache[cache_key] = new(context, register)
|
|
100
|
+
TRANSFORM_CACHE.evict_half_if_full
|
|
101
|
+
TRANSFORM_CACHE.fetch_or_store(self, context, register) do
|
|
102
|
+
new(context, register)
|
|
103
|
+
end
|
|
38
104
|
end
|
|
39
105
|
|
|
40
106
|
def self.override_transform(context, register, mappings)
|
|
@@ -54,30 +120,17 @@ module Lutaml
|
|
|
54
120
|
private_class_method :evict_override_if_needed
|
|
55
121
|
|
|
56
122
|
def self.clear_cache!
|
|
57
|
-
|
|
123
|
+
TRANSFORM_CACHE.clear
|
|
58
124
|
@override_transform_cache&.clear
|
|
59
125
|
end
|
|
60
126
|
|
|
61
127
|
def self.cache_size
|
|
62
|
-
|
|
128
|
+
TRANSFORM_CACHE.size
|
|
63
129
|
end
|
|
64
130
|
|
|
65
131
|
def self.invalidate_for(context, register = nil)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
if register
|
|
69
|
-
@transform_cache.delete([context, register])
|
|
70
|
-
else
|
|
71
|
-
@transform_cache.reject! { |(ctx, _reg)| ctx == context }
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
def self.evict_if_needed
|
|
76
|
-
# Evict oldest half of entries when cache is full
|
|
77
|
-
keys_to_remove = @transform_cache.keys.first(@transform_cache.size / 2)
|
|
78
|
-
keys_to_remove.each { |k| @transform_cache.delete(k) }
|
|
132
|
+
TRANSFORM_CACHE.invalidate(context, register)
|
|
79
133
|
end
|
|
80
|
-
private_class_method :evict_if_needed
|
|
81
134
|
|
|
82
135
|
attr_reader :context, :lutaml_register
|
|
83
136
|
|
|
@@ -38,6 +38,8 @@ module Lutaml
|
|
|
38
38
|
# # Has :custom, falls back to default for built-in types
|
|
39
39
|
#
|
|
40
40
|
class TypeContext
|
|
41
|
+
EMPTY_SUBSTITUTIONS = [].freeze
|
|
42
|
+
|
|
41
43
|
# @return [Symbol] The context identifier
|
|
42
44
|
attr_reader :id
|
|
43
45
|
|
|
@@ -204,6 +206,13 @@ module Lutaml
|
|
|
204
206
|
# @param from_type [Class, Symbol, String] The type to find substitutions for
|
|
205
207
|
# @return [Array<TypeSubstitution>] Matching substitutions
|
|
206
208
|
def substitution_for(from_type)
|
|
209
|
+
# The no-substitution context is the common case, and this
|
|
210
|
+
# lookup runs per nested model per serialized instance — the
|
|
211
|
+
# select's result array was the allocation (#KV-to profile
|
|
212
|
+
# 2026-10-26). The frozen shared array answers readers only;
|
|
213
|
+
# every consumer here selects/any?/eaches it.
|
|
214
|
+
return EMPTY_SUBSTITUTIONS if substitutions.empty?
|
|
215
|
+
|
|
207
216
|
from_type_class = from_type.is_a?(Class) ? from_type : nil
|
|
208
217
|
|
|
209
218
|
substitutions.select do |sub|
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -19,13 +19,7 @@ module Lutaml
|
|
|
19
19
|
def to_toml(*)
|
|
20
20
|
require "toml-rb"
|
|
21
21
|
# Handle KeyValueElement input (new symmetric architecture)
|
|
22
|
-
attributes_to_serialize =
|
|
23
|
-
# Unwrap __root__ wrapper to get actual content
|
|
24
|
-
@attributes.to_hash["__root__"]
|
|
25
|
-
else
|
|
26
|
-
# Legacy Hash input (backward compatibility)
|
|
27
|
-
@attributes
|
|
28
|
-
end
|
|
22
|
+
attributes_to_serialize = @attributes
|
|
29
23
|
|
|
30
24
|
TomlRB.dump(attributes_to_serialize)
|
|
31
25
|
rescue LoadError
|
|
@@ -34,13 +34,7 @@ module Lutaml
|
|
|
34
34
|
def to_toml(*)
|
|
35
35
|
require "tomlib"
|
|
36
36
|
# Handle KeyValueElement input (new symmetric architecture)
|
|
37
|
-
attributes_to_serialize =
|
|
38
|
-
# Unwrap __root__ wrapper to get actual content
|
|
39
|
-
@attributes.to_hash["__root__"]
|
|
40
|
-
else
|
|
41
|
-
# Legacy Hash input (backward compatibility)
|
|
42
|
-
@attributes
|
|
43
|
-
end
|
|
37
|
+
attributes_to_serialize = @attributes
|
|
44
38
|
|
|
45
39
|
Tomlib.dump(attributes_to_serialize)
|
|
46
40
|
# Tomlib::Generator.new(to_h).toml_str
|
|
@@ -116,7 +116,9 @@ module Lutaml
|
|
|
116
116
|
|
|
117
117
|
def add_xml_fragment(element, content)
|
|
118
118
|
target = resolve_target(element)
|
|
119
|
-
|
|
119
|
+
# The wrapper tag only gives the parser a root; its name is
|
|
120
|
+
# discarded — only the parsed children are adopted.
|
|
121
|
+
parsed = @context.parse("<fragment>#{content}</fragment>")
|
|
120
122
|
parsed.root&.children&.each { |child| target.add_child(child) }
|
|
121
123
|
rescue Moxml::ParseError
|
|
122
124
|
target.add_child(@doc.create_text(content.to_s))
|
|
@@ -64,8 +64,8 @@ module Lutaml
|
|
|
64
64
|
# This ensures root namespace is included in all_namespaces
|
|
65
65
|
if mapping_dsl.namespace_class
|
|
66
66
|
rules << ::Lutaml::Model::CompiledRule.new(
|
|
67
|
-
attribute_name: :
|
|
68
|
-
serialized_name: "
|
|
67
|
+
attribute_name: :root_namespace,
|
|
68
|
+
serialized_name: "root_namespace",
|
|
69
69
|
namespace_class: mapping_dsl.namespace_class,
|
|
70
70
|
mapping_type: :root_namespace,
|
|
71
71
|
)
|
|
@@ -25,13 +25,7 @@ module Lutaml
|
|
|
25
25
|
|
|
26
26
|
def to_yaml(options = {})
|
|
27
27
|
# Handle KeyValueElement input (new symmetric architecture)
|
|
28
|
-
attributes_to_serialize =
|
|
29
|
-
# Unwrap __root__ wrapper to get actual content
|
|
30
|
-
@attributes.to_hash["__root__"]
|
|
31
|
-
else
|
|
32
|
-
# Legacy Hash input (backward compatibility)
|
|
33
|
-
@attributes
|
|
34
|
-
end
|
|
28
|
+
attributes_to_serialize = @attributes
|
|
35
29
|
|
|
36
30
|
YAML.dump(attributes_to_serialize, options)
|
|
37
31
|
end
|
|
@@ -91,13 +91,7 @@ module Lutaml
|
|
|
91
91
|
private_class_method :syntax_error
|
|
92
92
|
|
|
93
93
|
def to_yaml(_options = {})
|
|
94
|
-
attributes_to_serialize =
|
|
95
|
-
# Unwrap __root__ wrapper to get actual content
|
|
96
|
-
@attributes.to_hash["__root__"]
|
|
97
|
-
else
|
|
98
|
-
# Legacy Hash input (backward compatibility)
|
|
99
|
-
@attributes
|
|
100
|
-
end
|
|
94
|
+
attributes_to_serialize = @attributes
|
|
101
95
|
|
|
102
96
|
# Generation must match the standard (Psych) adapter's output
|
|
103
97
|
# byte-for-byte: document separator, quoting of digit-leading
|
|
@@ -12,12 +12,7 @@ module Lutaml
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def to_yamlld(options = {})
|
|
15
|
-
attributes_to_serialize =
|
|
16
|
-
if @attributes.is_a?(Lutaml::KeyValue::DataModel::Element)
|
|
17
|
-
@attributes.to_hash["__root__"]
|
|
18
|
-
else
|
|
19
|
-
@attributes
|
|
20
|
-
end
|
|
15
|
+
attributes_to_serialize = @attributes
|
|
21
16
|
YAML.dump(attributes_to_serialize, options)
|
|
22
17
|
end
|
|
23
18
|
end
|
|
@@ -54,12 +54,12 @@ RSpec.describe(TEPTRIS_AVAILABLE ? Lutaml::KeyValue::Adapter::Toml::TeptrisAdapt
|
|
|
54
54
|
.to include("name", "[nested]", "a = [1, 2]")
|
|
55
55
|
end
|
|
56
56
|
|
|
57
|
-
it "
|
|
58
|
-
element = Lutaml::KeyValue::DataModel::Element.new("
|
|
57
|
+
it "serializes Element children through their keyed hash shape" do
|
|
58
|
+
element = Lutaml::KeyValue::DataModel::Element.new("doc")
|
|
59
59
|
name_child = Lutaml::KeyValue::DataModel::Element.new("name")
|
|
60
60
|
name_child.value = "x"
|
|
61
61
|
element.add_child(name_child)
|
|
62
|
-
expect(
|
|
62
|
+
expect(element.to_hash).to eq("doc" => { "name" => "x" })
|
|
63
63
|
end
|
|
64
64
|
end
|
|
65
65
|
|