lutaml-model 0.8.49 → 0.8.50
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: f2f88962ec380d731bd7a31ce5ff62f9aec9dcef4b7783aebfb128b6b5c86bbb
|
|
4
|
+
data.tar.gz: b282edc8ccf91c2381315e58a34d54a15642153e673ba31bbbd46c084c7634c4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f92f932e37bed4d355b3a41c1d2599bf23a5f0907f2ba18967f27cb5a572a4be11d080d54d0a73787055b6e9143414928e87086f2269f42acfb77665e9cccda6
|
|
7
|
+
data.tar.gz: a5801daa0947b0a2308fc720412d0add3cd5956f6a902cf20aa62b0ece6d883ec801dc4c4112319ab161a5d68934d54aac0253d601515823d04440df52011400
|
|
@@ -350,6 +350,59 @@ module Lutaml
|
|
|
350
350
|
instance
|
|
351
351
|
end
|
|
352
352
|
|
|
353
|
+
# Fast bulk constructor for deserialization-heavy callers
|
|
354
|
+
# (native extensions building object trees bottom-up).
|
|
355
|
+
#
|
|
356
|
+
# Allocates without running #initialize and applies each present
|
|
357
|
+
# attribute through its compiled writer, which casts the value
|
|
358
|
+
# and marks it as explicitly set — so defaults, to_hash output,
|
|
359
|
+
# and using_default? behave exactly as if the instance had been
|
|
360
|
+
# produced by from_hash. Values may be primitives or already
|
|
361
|
+
# built instances (instances pass through casting unchanged);
|
|
362
|
+
# absent keys keep their defaults. Unknown keys raise.
|
|
363
|
+
#
|
|
364
|
+
# @param attrs [Hash] attribute names (String or Symbol) to
|
|
365
|
+
# pre-cast values
|
|
366
|
+
# @param register [Symbol, nil] The register context
|
|
367
|
+
# @return [Object] The hydrated instance
|
|
368
|
+
def instantiate(attrs = {}, register = nil)
|
|
369
|
+
instance = allocate_for_deserialization(register)
|
|
370
|
+
register_id = instance.lutaml_register
|
|
371
|
+
given = {}
|
|
372
|
+
attrs.each do |key, value|
|
|
373
|
+
name = key.to_sym
|
|
374
|
+
next if name == :lutaml_register
|
|
375
|
+
|
|
376
|
+
unless attributes(register_id).key?(name)
|
|
377
|
+
raise Error, "unknown attribute '#{name}' for #{self}"
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
given[name] = value
|
|
381
|
+
end
|
|
382
|
+
attributes(register_id).each do |name, attr|
|
|
383
|
+
next if attr.derived?
|
|
384
|
+
|
|
385
|
+
if given.key?(name)
|
|
386
|
+
instance.public_send(:"#{name}=", given[name])
|
|
387
|
+
else
|
|
388
|
+
# Absent keys seed their default explicitly, mirroring
|
|
389
|
+
# initialize_attributes: every mapped attribute ends up
|
|
390
|
+
# set (nil when no default), never left as the
|
|
391
|
+
# uninitialized sentinel — readers and formatters touch
|
|
392
|
+
# absent attributes freely.
|
|
393
|
+
default = attr.default_value(register_id, instance)
|
|
394
|
+
value = if Lutaml::Model::Utils.uninitialized?(default)
|
|
395
|
+
nil
|
|
396
|
+
else
|
|
397
|
+
attr.cast_value(default, register_id)
|
|
398
|
+
end
|
|
399
|
+
instance.public_send(:"#{name}=", value)
|
|
400
|
+
instance.using_default_for(name)
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
instance
|
|
404
|
+
end
|
|
405
|
+
|
|
353
406
|
# Define register-specific attribute methods on the class itself.
|
|
354
407
|
#
|
|
355
408
|
# Called once per (class, register) combination. Replaces per-instance
|
data/lib/lutaml/model/version.rb
CHANGED
|
@@ -30,7 +30,11 @@ module Lutaml
|
|
|
30
30
|
|
|
31
31
|
child_kwargs[name] = []
|
|
32
32
|
end
|
|
33
|
-
|
|
33
|
+
# TODO.max-perf/33: the bulk constructor — allocate +
|
|
34
|
+
# compiled writers, from_hash semantics — measured ~30x on
|
|
35
|
+
# hydration-heavy corpora versus the generic constructor.
|
|
36
|
+
instance = model_class.instantiate(attr_kwargs.merge(child_kwargs),
|
|
37
|
+
register)
|
|
34
38
|
instance.lutaml_parent = parent if parent
|
|
35
39
|
instance.lutaml_root ||= parent&.lutaml_root || parent
|
|
36
40
|
instance.element_order = PlanOrder.build(node) if node && plan[:ordered]
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require_relative "../../../lib/lutaml/model"
|
|
5
|
+
|
|
6
|
+
module InstantiateMapping
|
|
7
|
+
class Part < Lutaml::Model::Serializable
|
|
8
|
+
attribute :label, :string
|
|
9
|
+
attribute :count, :integer
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class Widget < Lutaml::Model::Serializable
|
|
13
|
+
attribute :name, :string
|
|
14
|
+
attribute :flag, :boolean
|
|
15
|
+
attribute :part, Part
|
|
16
|
+
attribute :tags, :string, collection: true
|
|
17
|
+
|
|
18
|
+
key_value do
|
|
19
|
+
map "name", to: :name
|
|
20
|
+
map "flag", to: :flag
|
|
21
|
+
map "part", to: :part
|
|
22
|
+
map "tags", to: :tags
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
RSpec.describe "Serializable.instantiate" do
|
|
28
|
+
it "hydrates attributes from primitives" do
|
|
29
|
+
widget = InstantiateMapping::Widget.instantiate("name" => "w", "flag" => true,
|
|
30
|
+
"tags" => %w[a b])
|
|
31
|
+
expect(widget.name).to eq("w")
|
|
32
|
+
expect(widget.flag).to be(true)
|
|
33
|
+
expect(widget.tags).to eq(%w[a b])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "accepts pre-built instances for typed attributes" do
|
|
37
|
+
part = InstantiateMapping::Part.instantiate(label: "p", count: 2)
|
|
38
|
+
widget = InstantiateMapping::Widget.instantiate(name: "w", part: part)
|
|
39
|
+
|
|
40
|
+
expect(widget.part).to equal(part)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "keeps defaults for absent keys and reports them as defaults" do
|
|
44
|
+
widget = InstantiateMapping::Widget.instantiate
|
|
45
|
+
# Absent scalars read as the uninitialized sentinel, exactly like the
|
|
46
|
+
# XML fast path; serialization omits them either way.
|
|
47
|
+
expect(Lutaml::Model::Utils.uninitialized?(widget.name) ||
|
|
48
|
+
widget.name.nil?).to be(true)
|
|
49
|
+
expect(widget).to be_using_default(:name)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "marks set attributes as explicitly set" do
|
|
53
|
+
widget = InstantiateMapping::Widget.instantiate(name: "w")
|
|
54
|
+
expect(widget).not_to be_using_default(:name)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "serializes identically to from_hash" do
|
|
58
|
+
input = { "name" => "w", "flag" => false,
|
|
59
|
+
"part" => { "label" => "p", "count" => 3 },
|
|
60
|
+
"tags" => ["x"] }
|
|
61
|
+
from_hash = InstantiateMapping::Widget.from_hash(input)
|
|
62
|
+
|
|
63
|
+
part = InstantiateMapping::Part.instantiate(input["part"])
|
|
64
|
+
fast = InstantiateMapping::Widget.instantiate(
|
|
65
|
+
name: "w", flag: false, part: part, tags: ["x"],
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
expect(fast.to_hash).to eq(from_hash.to_hash)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "raises on unknown attribute names" do
|
|
72
|
+
expect { InstantiateMapping::Widget.instantiate(bogus: 1) }
|
|
73
|
+
.to raise_error(Lutaml::Model::Error, /unknown attribute/)
|
|
74
|
+
end
|
|
75
|
+
end
|
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.50
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -1797,6 +1797,7 @@ files:
|
|
|
1797
1797
|
- spec/lutaml/model/schema/yaml_schema_spec.rb
|
|
1798
1798
|
- spec/lutaml/model/sequence_choice_compositor_spec.rb
|
|
1799
1799
|
- spec/lutaml/model/sequence_spec.rb
|
|
1800
|
+
- spec/lutaml/model/serializable_instantiate_spec.rb
|
|
1800
1801
|
- spec/lutaml/model/serializable_spec.rb
|
|
1801
1802
|
- spec/lutaml/model/serializable_validation_spec.rb
|
|
1802
1803
|
- spec/lutaml/model/serialize/builder_spec.rb
|