lutaml-model 0.8.78 → 0.8.80
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: 8375b9ceb21e41c8f236b2e96728983065a6b547f31401686ab5b9b520db2d8d
|
|
4
|
+
data.tar.gz: 3e9f7da096049d3cf0472a18782f014341df12b8ae0e0394dcab18a24de73c9b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8c925f539d5fdb6ca0e57dae30b6e3b4fe8ed162fbfdb8dc66f04661c885399eefdd99259a7f3067b9a98cab678fb6b9b3d5176418e6d80c7d2ec2b58eea86aa
|
|
7
|
+
data.tar.gz: 8673fafc5fc984374916bf509e855ce69dcfd89134149d9e348b7f56eede5b95b6e4e0eca064c1cc0dfdcb169aecf27b47a75251a4cd3dc7c356c92ef05da317
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "lutaml/model"
|
|
4
|
+
|
|
5
|
+
module AllocAudit
|
|
6
|
+
class Row < Lutaml::Model::Serializable
|
|
7
|
+
attribute :id, :integer
|
|
8
|
+
attribute :name, :string
|
|
9
|
+
|
|
10
|
+
xml do
|
|
11
|
+
root "row"
|
|
12
|
+
map_element "id", to: :id
|
|
13
|
+
map_element "name", to: :name
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
json do
|
|
17
|
+
map "id", to: :id
|
|
18
|
+
map "name", to: :name
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
class Doc < Lutaml::Model::Serializable
|
|
23
|
+
attribute :rows, AllocAudit::Row, collection: true
|
|
24
|
+
|
|
25
|
+
xml do
|
|
26
|
+
root "doc"
|
|
27
|
+
map_element "row", to: :rows
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
json do
|
|
31
|
+
map "rows", to: :rows
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
DOC = Doc.new(rows: Array.new(500) { |i| Row.new(id: i, name: "n#{i}") })
|
|
36
|
+
|
|
37
|
+
def self.alloc
|
|
38
|
+
GC.start
|
|
39
|
+
before = GC.stat(:total_allocated_objects)
|
|
40
|
+
yield
|
|
41
|
+
GC.stat(:total_allocated_objects) - before
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
3.times do
|
|
45
|
+
DOC.to_xml
|
|
46
|
+
DOC.to_json
|
|
47
|
+
DOC.to_hash
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
puts "rows=500"
|
|
51
|
+
puts "to_xml_alloc=#{alloc { DOC.to_xml }}"
|
|
52
|
+
puts "to_json_alloc=#{alloc { DOC.to_json }}"
|
|
53
|
+
puts "to_hash_alloc=#{alloc { DOC.to_hash }}"
|
|
54
|
+
puts "from_xml_alloc=#{alloc { Doc.from_xml(DOC.to_xml) }}"
|
|
55
|
+
puts "from_json_alloc=#{alloc { Doc.from_json(DOC.to_json) }}"
|
|
56
|
+
end
|
|
@@ -9,6 +9,17 @@ module Lutaml
|
|
|
9
9
|
include DeepDupable
|
|
10
10
|
include RestrictionValidation
|
|
11
11
|
|
|
12
|
+
# Symbol interpolation (:"to_#{format}") allocates a String and a
|
|
13
|
+
# Symbol per call on the serialization hot path; the table serves
|
|
14
|
+
# the known formats and the fallback keeps exotic ones working.
|
|
15
|
+
TO_FORMAT_METHODS = {
|
|
16
|
+
xml: :to_xml,
|
|
17
|
+
json: :to_json,
|
|
18
|
+
yaml: :to_yaml,
|
|
19
|
+
toml: :to_toml,
|
|
20
|
+
hash: :to_hash,
|
|
21
|
+
}.freeze
|
|
22
|
+
|
|
12
23
|
ALLOWED_OPTIONS = %i[
|
|
13
24
|
raw
|
|
14
25
|
default
|
|
@@ -838,11 +849,10 @@ instance_object = nil)
|
|
|
838
849
|
return value if value.nil? || Utils.uninitialized?(value)
|
|
839
850
|
|
|
840
851
|
resolved_type = options[:resolved_type] || type(register)
|
|
841
|
-
serialize_options = options.merge(resolved_type: resolved_type)
|
|
842
852
|
value = reference_key(value) if unresolved_type == Lutaml::Model::Type::Reference
|
|
843
853
|
if collection_instance?(value)
|
|
844
854
|
return serialize_array(value, format, register,
|
|
845
|
-
|
|
855
|
+
options.merge(resolved_type: resolved_type))
|
|
846
856
|
end
|
|
847
857
|
if resolved_type <= Serialize
|
|
848
858
|
return serialize_model(value, format, register,
|
|
@@ -1223,8 +1233,19 @@ instance_object = nil)
|
|
|
1223
1233
|
end
|
|
1224
1234
|
|
|
1225
1235
|
def serialize_value(value, format, resolved_type)
|
|
1226
|
-
|
|
1227
|
-
|
|
1236
|
+
# The Value wrapper is a pass-through on the to_ side (its
|
|
1237
|
+
# to_<format> returns the wrapped raw value unless a custom
|
|
1238
|
+
# format serializer is registered), so the common path returns
|
|
1239
|
+
# the raw value and lets the caller stringify — one object
|
|
1240
|
+
# instead of three per serialized scalar. Reference and
|
|
1241
|
+
# custom-serializer rows keep the wrapped path.
|
|
1242
|
+
if resolved_type <= Type::Reference ||
|
|
1243
|
+
Type::Value.format_type_serializer_for(format, resolved_type)&.dig(:to)
|
|
1244
|
+
value = wrap_in_type_if_needed(value, resolved_type)
|
|
1245
|
+
return value.public_send(TO_FORMAT_METHODS[format] || :"to_#{format}")
|
|
1246
|
+
end
|
|
1247
|
+
|
|
1248
|
+
value
|
|
1228
1249
|
end
|
|
1229
1250
|
|
|
1230
1251
|
def wrap_in_type_if_needed(value, resolved_type)
|
|
@@ -182,13 +182,18 @@ module Lutaml
|
|
|
182
182
|
alias from name
|
|
183
183
|
alias render_default? render_default
|
|
184
184
|
|
|
185
|
+
# Frozen default: render? only reads options (render_nil?/render_empty?/
|
|
186
|
+
# render_omitted? policies); a fresh {} per call is pure churn on the
|
|
187
|
+
# serialization hot path.
|
|
188
|
+
EMPTY_RENDER_OPTIONS = {}.freeze
|
|
189
|
+
|
|
185
190
|
# Whether this rule participates in serialization output. False
|
|
186
191
|
# marks a hydrate-only mapping: consumed by from_* but never
|
|
187
192
|
# rendered by to_*. (The value callback #serialize is separate.)
|
|
188
193
|
def serialize? = @serialize_mapping
|
|
189
194
|
alias attribute? attribute
|
|
190
195
|
|
|
191
|
-
def render?(value, instance = nil, options =
|
|
196
|
+
def render?(value, instance = nil, options = EMPTY_RENDER_OPTIONS)
|
|
192
197
|
if invalid_value?(value, options)
|
|
193
198
|
false
|
|
194
199
|
# FIXED: Check if collection was mutated after initialization
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -107,7 +107,9 @@ module Lutaml
|
|
|
107
107
|
kwargs = {}
|
|
108
108
|
children = []
|
|
109
109
|
delegates = []
|
|
110
|
-
|
|
110
|
+
# Lazy: models without multi-spelling rows never touch it, and
|
|
111
|
+
# the block-backed Hash is a fresh object per hydrated row.
|
|
112
|
+
spellings = nil
|
|
111
113
|
row_tags = plan[:row_tags]
|
|
112
114
|
plan[:rows].each_with_index do |(rule, attr, kind, spelling, delegate), idx|
|
|
113
115
|
tag = row_tags&.[](idx)
|
|
@@ -174,6 +176,7 @@ module Lutaml
|
|
|
174
176
|
assign(kwargs, delegates, delegate, rule, attr, values)
|
|
175
177
|
end
|
|
176
178
|
when :spelling
|
|
179
|
+
spellings ||= Hash.new { |h, k| h[k] = [] }
|
|
177
180
|
spellings[[rule, attr]] << grouped[spelling.to_s].to_a
|
|
178
181
|
when :nested
|
|
179
182
|
child_type = attr.type(register)
|
|
@@ -193,7 +196,7 @@ module Lutaml
|
|
|
193
196
|
attr.collection? ? items : items.first)
|
|
194
197
|
end
|
|
195
198
|
end
|
|
196
|
-
unless spellings.empty?
|
|
199
|
+
unless !spellings || spellings.empty?
|
|
197
200
|
spellings.each do |(rule, attr), groups|
|
|
198
201
|
# Interpretive order for shared-attribute groups is
|
|
199
202
|
# spelling-group order (first spelling's matches, then
|
|
@@ -397,8 +400,8 @@ module Lutaml
|
|
|
397
400
|
|
|
398
401
|
def group_children(value, row_tags = nil)
|
|
399
402
|
grouped = {}
|
|
400
|
-
tagged = {}
|
|
401
403
|
want_tags = !row_tags.nil?
|
|
404
|
+
tagged = want_tags ? {} : nil
|
|
402
405
|
value.count.times do |i|
|
|
403
406
|
child = value.at(i)
|
|
404
407
|
# One FFI crossing per child: the name was read twice here
|
|
@@ -73,10 +73,17 @@ module Lutaml
|
|
|
73
73
|
when :scalar
|
|
74
74
|
# Multi-capture parity: an attribute that collected
|
|
75
75
|
# several occurrences serializes one element per item,
|
|
76
|
-
# as the interpretive writer does.
|
|
77
|
-
Array(
|
|
76
|
+
# as the interpretive writer does. A plain scalar skips
|
|
77
|
+
# the Array() wrap — the common case.
|
|
78
|
+
if value.is_a?(::Array)
|
|
79
|
+
value.each do |item|
|
|
80
|
+
add_leaf(element, row_name(rule, spelling),
|
|
81
|
+
attr.serialize(item, :xml, reg), doc,
|
|
82
|
+
attrs: rule.when_attribute)
|
|
83
|
+
end
|
|
84
|
+
else
|
|
78
85
|
add_leaf(element, row_name(rule, spelling),
|
|
79
|
-
attr.serialize(
|
|
86
|
+
attr.serialize(value, :xml, reg), doc,
|
|
80
87
|
attrs: rule.when_attribute)
|
|
81
88
|
end
|
|
82
89
|
when :collection_native, :collection_cb
|
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.80
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -181,6 +181,7 @@ files:
|
|
|
181
181
|
- Rakefile
|
|
182
182
|
- bench/baselines/.gitkeep
|
|
183
183
|
- bench/bench_all.rb
|
|
184
|
+
- bench/bench_alloc_audit.rb
|
|
184
185
|
- bench/bench_common.rb
|
|
185
186
|
- bench/bench_compare.rb
|
|
186
187
|
- bench/bench_mml.rb
|