lutaml-model 0.8.78 → 0.8.79

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: bbb8929566d9265231917502a2f69360d8ae3f386a7dae26289bfd7764d08938
4
- data.tar.gz: 6dd3b2b0eb762944dbd39ee8f799012d9b808c980030d9daaf8fb8fed9cbbec6
3
+ metadata.gz: baaf76af5592d1f15c959d624311b2275e3871728b7c74ca416032c743929134
4
+ data.tar.gz: cc5bc7a1cea2b151c51f720f971c8799d1d005e4ef7fc79fa415e611e161a2b5
5
5
  SHA512:
6
- metadata.gz: 2f495fccd94badb5057c976aec507acbcf8319bf0f4cf56783ad0d9cade2f982a0806b473a6e89ed7496d6baa4cb8e05aa871bccf5d432c963c6e66c8ad22661
7
- data.tar.gz: 44bc1cc78b2ef1e8f75e9d0237d35eab9dc4d2d5d0f49efed9966c87933a607f49724999c7854cbd428f5a6fd4c2fdc945bd1750876ab2f603d25986b2169b01
6
+ metadata.gz: 68ab1cf58c777ef8f508c9c3e10df0026ea2de6affb69fa76f8c25e262dfdce8cdd5d67caccb7672eedeea233a654c5e3cd1c5c16ed3c7a4688f02937e46c897
7
+ data.tar.gz: 53b98253d7946438a13ac912701a271aa32f549525ca17b0645243a2669631dc79ee728928ee808e9a7660c0f3bbd2e963d3cdcc17b70f2adb2419aab68e8904
@@ -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
- serialize_options)
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
- value = wrap_in_type_if_needed(value, resolved_type)
1227
- value.public_send(:"to_#{format}")
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
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Model
5
- VERSION = "0.8.78"
5
+ VERSION = "0.8.79"
6
6
  end
7
7
  end
@@ -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(value).each do |item|
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(item, :xml, reg), doc,
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.78
4
+ version: 0.8.79
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