lutaml-model 0.6.7 → 0.7.2
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/.github/workflows/dependent-repos-todo.json +7 -0
- data/.github/workflows/dependent-repos.json +17 -9
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +51 -65
- data/Gemfile +4 -1
- data/README.adoc +5083 -2612
- data/RELEASE_NOTES.adoc +346 -0
- data/docs/custom_adapters.adoc +144 -0
- data/lib/lutaml/model/attribute.rb +101 -16
- data/lib/lutaml/model/choice.rb +7 -0
- data/lib/lutaml/model/comparable_model.rb +48 -9
- data/lib/lutaml/model/config.rb +48 -42
- data/lib/lutaml/model/error/collection_count_out_of_range_error.rb +1 -1
- data/lib/lutaml/model/error/polymorphic_error.rb +14 -0
- data/lib/lutaml/model/error.rb +1 -0
- data/lib/lutaml/model/format_registry.rb +41 -0
- data/lib/lutaml/model/hash/document.rb +11 -0
- data/lib/lutaml/model/hash/mapping.rb +19 -0
- data/lib/lutaml/model/hash/mapping_rule.rb +9 -0
- data/lib/lutaml/model/hash/standard_adapter.rb +17 -0
- data/lib/lutaml/model/hash/transform.rb +8 -0
- data/lib/lutaml/model/hash.rb +21 -0
- data/lib/lutaml/model/json/document.rb +11 -0
- data/lib/lutaml/model/json/mapping.rb +19 -0
- data/lib/lutaml/model/json/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{json_adapter → json}/multi_json_adapter.rb +4 -5
- data/lib/lutaml/model/{json_adapter/standard_json_adapter.rb → json/standard_adapter.rb} +5 -3
- data/lib/lutaml/model/json/transform.rb +8 -0
- data/lib/lutaml/model/json.rb +21 -0
- data/lib/lutaml/model/key_value_document.rb +27 -0
- data/lib/lutaml/model/{key_value_mapping.rb → mapping/key_value_mapping.rb} +64 -16
- data/lib/lutaml/model/{key_value_mapping_rule.rb → mapping/key_value_mapping_rule.rb} +18 -2
- data/lib/lutaml/model/mapping/mapping.rb +13 -0
- data/lib/lutaml/model/mapping/mapping_rule.rb +300 -0
- data/lib/lutaml/model/schema/xml_compiler.rb +15 -15
- data/lib/lutaml/model/sequence.rb +2 -2
- data/lib/lutaml/model/serialization_adapter.rb +22 -0
- data/lib/lutaml/model/serialize.rb +219 -444
- data/lib/lutaml/model/services/logger.rb +54 -0
- data/lib/lutaml/model/services/transformer.rb +48 -0
- data/lib/lutaml/model/services.rb +2 -0
- data/lib/lutaml/model/toml/document.rb +11 -0
- data/lib/lutaml/model/toml/mapping.rb +27 -0
- data/lib/lutaml/model/toml/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{toml_adapter → toml}/toml_rb_adapter.rb +3 -3
- data/lib/lutaml/model/toml/tomlib_adapter.rb +19 -0
- data/lib/lutaml/model/toml/transform.rb +8 -0
- data/lib/lutaml/model/toml.rb +30 -0
- data/lib/lutaml/model/transform/key_value_transform.rb +291 -0
- data/lib/lutaml/model/transform/xml_transform.rb +239 -0
- data/lib/lutaml/model/transform.rb +78 -0
- data/lib/lutaml/model/type/date.rb +1 -1
- data/lib/lutaml/model/type/date_time.rb +2 -2
- data/lib/lutaml/model/type/hash.rb +1 -1
- data/lib/lutaml/model/type/time.rb +2 -2
- data/lib/lutaml/model/type/time_without_date.rb +2 -2
- data/lib/lutaml/model/type/value.rb +6 -9
- data/lib/lutaml/model/uninitialized_class.rb +64 -0
- data/lib/lutaml/model/utils.rb +44 -0
- data/lib/lutaml/model/validation.rb +1 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/builder/nokogiri.rb +2 -2
- data/lib/lutaml/model/{xml_adapter → xml}/builder/oga.rb +10 -10
- data/lib/lutaml/model/{xml_adapter → xml}/builder/ox.rb +1 -1
- data/lib/lutaml/model/{xml_adapter/xml_document.rb → xml/document.rb} +41 -21
- data/lib/lutaml/model/xml/element.rb +32 -0
- data/lib/lutaml/model/xml/mapping.rb +410 -0
- data/lib/lutaml/model/xml/mapping_rule.rb +141 -0
- data/lib/lutaml/model/xml/nokogiri_adapter.rb +232 -0
- data/lib/lutaml/model/{xml_adapter → xml}/oga/document.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/oga/element.rb +3 -1
- data/lib/lutaml/model/xml/oga_adapter.rb +171 -0
- data/lib/lutaml/model/xml/ox_adapter.rb +215 -0
- data/lib/lutaml/model/xml/transform.rb +8 -0
- data/lib/lutaml/model/{xml_adapter → xml}/xml_attribute.rb +1 -1
- data/lib/lutaml/model/{xml_adapter → xml}/xml_element.rb +23 -10
- data/lib/lutaml/model/{xml_adapter → xml}/xml_namespace.rb +1 -1
- data/lib/lutaml/model/xml.rb +31 -0
- data/lib/lutaml/model/xml_adapter/element.rb +11 -25
- data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +6 -223
- data/lib/lutaml/model/xml_adapter/oga_adapter.rb +13 -163
- data/lib/lutaml/model/xml_adapter/ox_adapter.rb +10 -207
- data/lib/lutaml/model/yaml/document.rb +10 -0
- data/lib/lutaml/model/yaml/mapping.rb +19 -0
- data/lib/lutaml/model/yaml/mapping_rule.rb +9 -0
- data/lib/lutaml/model/{yaml_adapter/standard_yaml_adapter.rb → yaml/standard_adapter.rb} +4 -3
- data/lib/lutaml/model/yaml/transform.rb +8 -0
- data/lib/lutaml/model/yaml.rb +21 -0
- data/lib/lutaml/model.rb +40 -4
- data/lutaml-model.gemspec +0 -4
- data/spec/benchmarks/xml_parsing_benchmark_spec.rb +7 -7
- data/spec/fixtures/person.rb +5 -5
- data/spec/lutaml/model/attribute_spec.rb +37 -1
- data/spec/lutaml/model/cdata_spec.rb +9 -9
- data/spec/lutaml/model/collection_spec.rb +50 -2
- data/spec/lutaml/model/comparable_model_spec.rb +92 -27
- data/spec/lutaml/model/custom_bibtex_adapter_spec.rb +598 -0
- data/spec/lutaml/model/custom_vobject_adapter_spec.rb +1226 -0
- data/spec/lutaml/model/defaults_spec.rb +1 -1
- data/spec/lutaml/model/enum_spec.rb +1 -1
- data/spec/lutaml/model/group_spec.rb +333 -20
- data/spec/lutaml/model/hash/adapter_spec.rb +255 -0
- data/spec/lutaml/model/json_adapter_spec.rb +6 -6
- data/spec/lutaml/model/key_value_mapping_spec.rb +65 -3
- data/spec/lutaml/model/mixed_content_spec.rb +24 -24
- data/spec/lutaml/model/multiple_mapping_spec.rb +5 -5
- data/spec/lutaml/model/ordered_content_spec.rb +6 -6
- data/spec/lutaml/model/polymorphic_spec.rb +526 -0
- data/spec/lutaml/model/render_empty_spec.rb +194 -0
- data/spec/lutaml/model/render_nil_spec.rb +206 -22
- data/spec/lutaml/model/root_mappings_spec.rb +3 -3
- data/spec/lutaml/model/schema/xml_compiler_spec.rb +6 -6
- data/spec/lutaml/model/serializable_spec.rb +179 -103
- data/spec/lutaml/model/simple_model_spec.rb +9 -9
- data/spec/lutaml/model/toml_adapter_spec.rb +6 -6
- data/spec/lutaml/model/toml_spec.rb +51 -0
- data/spec/lutaml/model/transformation_spec.rb +72 -15
- data/spec/lutaml/model/uninitialized_class_spec.rb +96 -0
- data/spec/lutaml/model/value_map_spec.rb +240 -0
- data/spec/lutaml/model/xml/namespace/nested_with_explicit_namespace_spec.rb +85 -0
- data/spec/lutaml/model/xml/namespace_spec.rb +57 -0
- data/spec/lutaml/model/xml/xml_element_spec.rb +93 -0
- data/spec/lutaml/model/xml_adapter/nokogiri_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +2 -2
- data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +6 -6
- data/spec/lutaml/model/xml_adapter_spec.rb +6 -6
- data/spec/lutaml/model/xml_mapping_rule_spec.rb +105 -5
- data/spec/lutaml/model/xml_mapping_spec.rb +70 -16
- data/spec/lutaml/model/xml_spec.rb +63 -0
- data/spec/lutaml/model/yaml_adapter_spec.rb +3 -5
- data/spec/sample_model_spec.rb +3 -3
- data/spec/spec_helper.rb +3 -3
- metadata +76 -59
- data/lib/lutaml/model/json_adapter/json_document.rb +0 -20
- data/lib/lutaml/model/json_adapter/json_object.rb +0 -28
- data/lib/lutaml/model/loggable.rb +0 -15
- data/lib/lutaml/model/mapping_rule.rb +0 -109
- data/lib/lutaml/model/toml_adapter/toml_document.rb +0 -20
- data/lib/lutaml/model/toml_adapter/toml_object.rb +0 -28
- data/lib/lutaml/model/toml_adapter/tomlib_adapter.rb +0 -20
- data/lib/lutaml/model/toml_adapter.rb +0 -6
- data/lib/lutaml/model/xml_mapping.rb +0 -307
- data/lib/lutaml/model/xml_mapping_rule.rb +0 -122
- data/lib/lutaml/model/yaml_adapter/yaml_document.rb +0 -20
- data/lib/lutaml/model/yaml_adapter/yaml_object.rb +0 -28
- data/lib/lutaml/model/yaml_adapter.rb +0 -8
@@ -1,214 +1,17 @@
|
|
1
|
-
require "ox"
|
2
|
-
require_relative "xml_document"
|
3
|
-
require_relative "builder/ox"
|
1
|
+
# require "ox"
|
2
|
+
# require_relative "xml_document"
|
3
|
+
# require_relative "builder/ox"
|
4
|
+
|
5
|
+
require_relative "../xml/ox_adapter"
|
4
6
|
|
5
7
|
module Lutaml
|
6
8
|
module Model
|
7
9
|
module XmlAdapter
|
8
|
-
class OxAdapter <
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
@root = OxElement.new(parsed)
|
14
|
-
new(@root, Ox.default_options[:encoding])
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_xml(options = {})
|
18
|
-
builder_options = { version: options[:version] }
|
19
|
-
|
20
|
-
builder_options[:encoding] = if options.key?(:encoding)
|
21
|
-
options[:encoding] unless options[:encoding].nil?
|
22
|
-
elsif options.key?(:parse_encoding)
|
23
|
-
options[:parse_encoding]
|
24
|
-
else
|
25
|
-
"UTF-8"
|
26
|
-
end
|
27
|
-
|
28
|
-
builder = Builder::Ox.build(builder_options)
|
29
|
-
builder.xml.instruct(:xml, encoding: builder_options[:encoding])
|
30
|
-
|
31
|
-
if @root.is_a?(Lutaml::Model::XmlAdapter::OxElement)
|
32
|
-
@root.build_xml(builder)
|
33
|
-
elsif ordered?(@root, options)
|
34
|
-
build_ordered_element(builder, @root, options)
|
35
|
-
else
|
36
|
-
mapper_class = options[:mapper_class] || @root.class
|
37
|
-
options[:xml_attributes] = build_namespace_attributes(mapper_class)
|
38
|
-
build_element(builder, @root, options)
|
39
|
-
end
|
40
|
-
|
41
|
-
xml_data = builder.xml.to_s
|
42
|
-
stripped_data = xml_data.lines.drop(1).join
|
43
|
-
options[:declaration] ? declaration(options) + stripped_data : stripped_data
|
44
|
-
end
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
def build_ordered_element(builder, element, options = {})
|
49
|
-
mapper_class = options[:mapper_class] || element.class
|
50
|
-
xml_mapping = mapper_class.mappings_for(:xml)
|
51
|
-
return xml unless xml_mapping
|
52
|
-
|
53
|
-
attributes = build_attributes(element, xml_mapping).compact
|
54
|
-
|
55
|
-
tag_name = options[:tag_name] || xml_mapping.root_element
|
56
|
-
builder.create_and_add_element(tag_name,
|
57
|
-
attributes: attributes) do |el|
|
58
|
-
index_hash = {}
|
59
|
-
content = []
|
60
|
-
|
61
|
-
element.element_order.each do |object|
|
62
|
-
index_hash[object.name] ||= -1
|
63
|
-
curr_index = index_hash[object.name] += 1
|
64
|
-
|
65
|
-
element_rule = xml_mapping.find_by_name(object.name)
|
66
|
-
next if element_rule.nil?
|
67
|
-
|
68
|
-
attribute_def = attribute_definition_for(element, element_rule,
|
69
|
-
mapper_class: mapper_class)
|
70
|
-
value = attribute_value_for(element, element_rule)
|
71
|
-
|
72
|
-
next if element_rule == xml_mapping.content_mapping && element_rule.cdata && object.text?
|
73
|
-
|
74
|
-
if element_rule == xml_mapping.content_mapping
|
75
|
-
text = element.send(xml_mapping.content_mapping.to)
|
76
|
-
text = text[curr_index] if text.is_a?(Array)
|
77
|
-
|
78
|
-
next el.add_text(el, text, cdata: element_rule.cdata) if element.mixed?
|
79
|
-
|
80
|
-
content << text
|
81
|
-
elsif !value.nil? || element_rule.render_nil?
|
82
|
-
value = value[curr_index] if attribute_def.collection?
|
83
|
-
|
84
|
-
add_to_xml(
|
85
|
-
el,
|
86
|
-
element,
|
87
|
-
nil,
|
88
|
-
value,
|
89
|
-
options.merge(
|
90
|
-
attribute: attribute_def,
|
91
|
-
rule: element_rule,
|
92
|
-
),
|
93
|
-
)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
el.add_text(el, content.join)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
class OxElement < XmlElement
|
103
|
-
def initialize(node, root_node: nil)
|
104
|
-
case node
|
105
|
-
when String
|
106
|
-
super("text", {}, [], node, parent_document: root_node)
|
107
|
-
when Ox::Comment
|
108
|
-
super("comment", {}, [], node.value, parent_document: root_node)
|
109
|
-
when Ox::CData
|
110
|
-
super("#cdata-section", {}, [], node.value, parent_document: root_node)
|
111
|
-
else
|
112
|
-
namespace_attributes(node.attributes).each do |(name, value)|
|
113
|
-
if root_node
|
114
|
-
root_node.add_namespace(XmlNamespace.new(value, name))
|
115
|
-
else
|
116
|
-
add_namespace(XmlNamespace.new(value, name))
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
attributes = node.attributes.each_with_object({}) do |(name, value), hash|
|
121
|
-
next if attribute_is_namespace?(name)
|
122
|
-
|
123
|
-
namespace_prefix = name.to_s.split(":").first
|
124
|
-
if (n = name.to_s.split(":")).length > 1
|
125
|
-
namespace = (root_node || self).namespaces[namespace_prefix]&.uri
|
126
|
-
namespace ||= XML_NAMESPACE_URI
|
127
|
-
prefix = n.first
|
128
|
-
end
|
129
|
-
|
130
|
-
hash[name.to_s] = XmlAttribute.new(
|
131
|
-
name.to_s,
|
132
|
-
value,
|
133
|
-
namespace: namespace,
|
134
|
-
namespace_prefix: prefix,
|
135
|
-
)
|
136
|
-
end
|
137
|
-
|
138
|
-
super(
|
139
|
-
node,
|
140
|
-
attributes,
|
141
|
-
parse_children(node, root_node: root_node || self),
|
142
|
-
node.text,
|
143
|
-
parent_document: root_node,
|
144
|
-
)
|
145
|
-
end
|
146
|
-
end
|
147
|
-
|
148
|
-
def to_xml
|
149
|
-
return text if text?
|
150
|
-
|
151
|
-
build_xml.xml.to_s
|
152
|
-
end
|
153
|
-
|
154
|
-
def inner_xml
|
155
|
-
# Ox builder by default, adds a newline at the end, so `chomp` is used
|
156
|
-
children.map { |child| child.to_xml.chomp }.join
|
157
|
-
end
|
158
|
-
|
159
|
-
def build_xml(builder = nil)
|
160
|
-
builder ||= Builder::Ox.build
|
161
|
-
attrs = build_attributes(self)
|
162
|
-
|
163
|
-
if text?
|
164
|
-
builder.add_text(builder, text)
|
165
|
-
else
|
166
|
-
builder.create_and_add_element(name, attributes: attrs) do |el|
|
167
|
-
children.each { |child| child.build_xml(el) }
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
builder
|
172
|
-
end
|
173
|
-
|
174
|
-
def namespace_attributes(attributes)
|
175
|
-
attributes.select { |attr| attribute_is_namespace?(attr) }
|
176
|
-
end
|
177
|
-
|
178
|
-
def text?
|
179
|
-
# false
|
180
|
-
children.empty? && text&.length&.positive?
|
181
|
-
end
|
182
|
-
|
183
|
-
def build_attributes(node)
|
184
|
-
attrs = node.attributes.transform_values(&:value)
|
185
|
-
|
186
|
-
node.own_namespaces.each_value do |namespace|
|
187
|
-
attrs[namespace.attr_name] = namespace.uri
|
188
|
-
end
|
189
|
-
|
190
|
-
attrs
|
191
|
-
end
|
192
|
-
|
193
|
-
def nodes
|
194
|
-
children
|
195
|
-
end
|
196
|
-
|
197
|
-
def cdata
|
198
|
-
super || cdata_children.first&.text
|
199
|
-
end
|
200
|
-
|
201
|
-
def text
|
202
|
-
super || cdata
|
203
|
-
end
|
204
|
-
|
205
|
-
private
|
206
|
-
|
207
|
-
def parse_children(node, root_node: nil)
|
208
|
-
node.nodes.map do |child|
|
209
|
-
OxElement.new(child, root_node: root_node)
|
210
|
-
end
|
211
|
-
end
|
10
|
+
class OxAdapter < ::Lutaml::Model::Xml::OxAdapter
|
11
|
+
Logger.warn_future_deprication(
|
12
|
+
old: "Lutaml::Model::XmlAdapter::OxAdapter",
|
13
|
+
replacement: "Lutaml::Model::Xml::OxAdapter",
|
14
|
+
)
|
212
15
|
end
|
213
16
|
end
|
214
17
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative "../mapping/key_value_mapping"
|
2
|
+
|
3
|
+
module Lutaml
|
4
|
+
module Model
|
5
|
+
module Yaml
|
6
|
+
class Mapping < Lutaml::Model::KeyValueMapping
|
7
|
+
def initialize
|
8
|
+
super(:yaml)
|
9
|
+
end
|
10
|
+
|
11
|
+
def deep_dup
|
12
|
+
self.class.new.tap do |new_mapping|
|
13
|
+
new_mapping.instance_variable_set(:@mappings, duplicate_mappings)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -1,10 +1,11 @@
|
|
1
1
|
require "yaml"
|
2
|
-
require_relative "
|
2
|
+
require_relative "document"
|
3
3
|
|
4
4
|
module Lutaml
|
5
5
|
module Model
|
6
|
-
module
|
7
|
-
class
|
6
|
+
module Yaml
|
7
|
+
class StandardAdapter < Document
|
8
|
+
FORMAT_SYMBOL = :yaml
|
8
9
|
PERMITTED_CLASSES_BASE = [Date, Time, DateTime, Symbol, Hash,
|
9
10
|
Array].freeze
|
10
11
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Lutaml
|
4
|
+
module Model
|
5
|
+
module Yaml
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
require_relative "yaml/standard_adapter"
|
11
|
+
require_relative "yaml/document"
|
12
|
+
require_relative "yaml/mapping"
|
13
|
+
require_relative "yaml/mapping_rule"
|
14
|
+
require_relative "yaml/transform"
|
15
|
+
|
16
|
+
Lutaml::Model::FormatRegistry.register(
|
17
|
+
:yaml,
|
18
|
+
mapping_class: Lutaml::Model::Yaml::Mapping,
|
19
|
+
adapter_class: Lutaml::Model::Yaml::StandardAdapter,
|
20
|
+
transformer: Lutaml::Model::Yaml::Transform,
|
21
|
+
)
|
data/lib/lutaml/model.rb
CHANGED
@@ -1,17 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "moxml"
|
4
|
+
require_relative "model/uninitialized_class"
|
5
|
+
require_relative "model/services"
|
4
6
|
require_relative "model/version"
|
5
|
-
require_relative "model/loggable"
|
6
7
|
require_relative "model/type"
|
7
8
|
require_relative "model/utils"
|
8
9
|
require_relative "model/serializable"
|
9
|
-
require_relative "model/json_adapter/standard_json_adapter"
|
10
|
-
require_relative "model/yaml_adapter/standard_yaml_adapter"
|
11
10
|
require_relative "model/xml_adapter"
|
12
|
-
require_relative "model/toml_adapter"
|
13
11
|
require_relative "model/error"
|
14
12
|
require_relative "model/constants"
|
13
|
+
require_relative "model/config"
|
14
|
+
require_relative "model/format_registry"
|
15
|
+
|
16
|
+
require_relative "model/key_value_document"
|
17
|
+
require_relative "model/yaml"
|
18
|
+
require_relative "model/json"
|
19
|
+
require_relative "model/toml"
|
20
|
+
require_relative "model/hash"
|
21
|
+
require_relative "model/xml"
|
15
22
|
|
16
23
|
module Lutaml
|
17
24
|
module Model
|
@@ -23,5 +30,34 @@ module Lutaml
|
|
23
30
|
|
24
31
|
class BaseModel < Serializable
|
25
32
|
end
|
33
|
+
|
34
|
+
# Register default adapters
|
35
|
+
# Lutaml::Model::FormatRegistry.register(
|
36
|
+
# :json,
|
37
|
+
# mapping_class: KeyValueMapping,
|
38
|
+
# adapter_class: JsonAdapter::StandardJsonAdapter,
|
39
|
+
# transformer: Lutaml::Model::KeyValueTransform,
|
40
|
+
# )
|
41
|
+
|
42
|
+
# Lutaml::Model::FormatRegistry.register(
|
43
|
+
# :yaml,
|
44
|
+
# mapping_class: KeyValueMapping,
|
45
|
+
# adapter_class: YamlAdapter::StandardYamlAdapter,
|
46
|
+
# transformer: Lutaml::Model::KeyValueTransform,
|
47
|
+
# )
|
48
|
+
|
49
|
+
# Lutaml::Model::FormatRegistry.register(
|
50
|
+
# :toml,
|
51
|
+
# mapping_class: KeyValueMapping,
|
52
|
+
# adapter_class: nil,
|
53
|
+
# transformer: Lutaml::Model::KeyValueTransform,
|
54
|
+
# )
|
55
|
+
|
56
|
+
# Lutaml::Model::FormatRegistry.register(
|
57
|
+
# :xml,
|
58
|
+
# mapping_class: XmlMapping,
|
59
|
+
# adapter_class: nil,
|
60
|
+
# transformer: Lutaml::Model::XmlTransform,
|
61
|
+
# )
|
26
62
|
end
|
27
63
|
end
|
data/lutaml-model.gemspec
CHANGED
@@ -30,10 +30,6 @@ Gem::Specification.new do |spec|
|
|
30
30
|
end
|
31
31
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
32
|
|
33
|
-
# TODO: remove once https://github.com/Shopify/liquid/issues/1772 is fixed
|
34
|
-
# needed for liquid with ruby 3.4
|
35
|
-
spec.add_dependency "base64"
|
36
|
-
spec.add_dependency "liquid", "~> 5"
|
37
33
|
spec.add_dependency "moxml", ">= 0.1.2"
|
38
34
|
spec.add_dependency "thor"
|
39
35
|
spec.metadata["rubygems_mfa_required"] = "true"
|
@@ -1,11 +1,11 @@
|
|
1
1
|
require "benchmark"
|
2
2
|
require "benchmark/ips"
|
3
3
|
require "lutaml/model"
|
4
|
-
require "lutaml/model/
|
4
|
+
require "lutaml/model/xml/oga_adapter"
|
5
5
|
|
6
6
|
RSpec.describe "LutaML Model Performance" do
|
7
7
|
after do
|
8
|
-
Lutaml::Model::Config.xml_adapter = Lutaml::Model::
|
8
|
+
Lutaml::Model::Config.xml_adapter = Lutaml::Model::Xml::NokogiriAdapter
|
9
9
|
end
|
10
10
|
|
11
11
|
let(:large_xml) do
|
@@ -48,12 +48,12 @@ RSpec.describe "LutaML Model Performance" do
|
|
48
48
|
end
|
49
49
|
|
50
50
|
x.report("Ox Adapter") do
|
51
|
-
Lutaml::Model::Config.xml_adapter = Lutaml::Model::
|
51
|
+
Lutaml::Model::Config.xml_adapter = Lutaml::Model::Xml::OxAdapter
|
52
52
|
Deserializer.from_xml(large_xml)
|
53
53
|
end
|
54
54
|
|
55
55
|
x.report("Oga Adapter") do
|
56
|
-
Lutaml::Model::Config.xml_adapter = Lutaml::Model::
|
56
|
+
Lutaml::Model::Config.xml_adapter = Lutaml::Model::Xml::OgaAdapter
|
57
57
|
Deserializer.from_xml(large_xml)
|
58
58
|
end
|
59
59
|
|
@@ -61,9 +61,9 @@ RSpec.describe "LutaML Model Performance" do
|
|
61
61
|
end
|
62
62
|
|
63
63
|
thresholds = {
|
64
|
-
"Nokogiri Adapter" =>
|
65
|
-
"Ox Adapter" =>
|
66
|
-
"Oga Adapter" =>
|
64
|
+
"Nokogiri Adapter" => 3,
|
65
|
+
"Ox Adapter" => 7,
|
66
|
+
"Oga Adapter" => 3,
|
67
67
|
}
|
68
68
|
|
69
69
|
report.entries.each do |entry|
|
data/spec/fixtures/person.rb
CHANGED
@@ -17,11 +17,11 @@ class Person < Lutaml::Model::Serializable
|
|
17
17
|
map_element "FirstName",
|
18
18
|
to: :first_name,
|
19
19
|
namespace: "http://example.com/nsp1",
|
20
|
-
prefix: "nsp1"
|
20
|
+
prefix: "nsp1", render_empty: :omit
|
21
21
|
map_element "LastName",
|
22
22
|
to: :last_name,
|
23
23
|
namespace: "http://example.com/nsp1",
|
24
|
-
prefix: "nsp1"
|
24
|
+
prefix: "nsp1", render_empty: :as_blank
|
25
25
|
map_element "Age", to: :age
|
26
26
|
map_element "Height", to: :height
|
27
27
|
map_element "Birthdate", to: :birthdate
|
@@ -31,9 +31,9 @@ class Person < Lutaml::Model::Serializable
|
|
31
31
|
end
|
32
32
|
|
33
33
|
json do
|
34
|
-
map "firstName", to: :first_name
|
35
|
-
map "lastName", to: :last_name
|
36
|
-
map "age", to: :age
|
34
|
+
map "firstName", to: :first_name, render_empty: :omit
|
35
|
+
map "lastName", to: :last_name, render_empty: :as_empty
|
36
|
+
map "age", to: :age, render_empty: :as_nil
|
37
37
|
map "height", to: :height
|
38
38
|
map "birthdate", to: :birthdate
|
39
39
|
map "lastLogin", to: :last_login
|
@@ -136,7 +136,9 @@ RSpec.describe Lutaml::Model::Attribute do
|
|
136
136
|
context "when default is not set" do
|
137
137
|
let(:attribute) { described_class.new("name", :string) }
|
138
138
|
|
139
|
-
it
|
139
|
+
it "returns uninitialized" do
|
140
|
+
expect(attribute.default).to be(Lutaml::Model::UninitializedClass.instance)
|
141
|
+
end
|
140
142
|
end
|
141
143
|
|
142
144
|
context "when default is set as a proc" do
|
@@ -165,4 +167,38 @@ RSpec.describe Lutaml::Model::Attribute do
|
|
165
167
|
end
|
166
168
|
end
|
167
169
|
end
|
170
|
+
|
171
|
+
describe "#deep_dup" do
|
172
|
+
let(:duplicate_attribute) { Lutaml::Model::Utils.deep_dup(attribute) }
|
173
|
+
|
174
|
+
context "when deep_dup method is not defined and instance is deep_duplicated" do
|
175
|
+
let(:attribute) { described_class.new("name", :string) }
|
176
|
+
|
177
|
+
before do
|
178
|
+
described_class.alias_method :orig_deep_dup, :deep_dup
|
179
|
+
described_class.undef_method :deep_dup
|
180
|
+
end
|
181
|
+
|
182
|
+
after do
|
183
|
+
described_class.alias_method :deep_dup, :orig_deep_dup
|
184
|
+
attribute.options.delete(:foo)
|
185
|
+
end
|
186
|
+
|
187
|
+
it "confirms that options values are linked of original and duplicate instances" do
|
188
|
+
duplicate_attribute
|
189
|
+
attribute.options[:foo] = "bar"
|
190
|
+
expect(duplicate_attribute.options).to include(:foo)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context "when deep_dup method is defined and instance is deep_duplicated" do
|
195
|
+
let(:attribute) { described_class.new("name", :string) }
|
196
|
+
|
197
|
+
it "confirms that options values are not linked of original and duplicate instances" do
|
198
|
+
duplicate_attribute
|
199
|
+
attribute.options[:foo] = "bar"
|
200
|
+
expect(duplicate_attribute.options).not_to include(:foo)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
168
204
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
require "lutaml/model"
|
3
|
-
require "lutaml/model/
|
4
|
-
require "lutaml/model/
|
3
|
+
require "lutaml/model/xml/nokogiri_adapter"
|
4
|
+
require "lutaml/model/xml/ox_adapter"
|
5
5
|
|
6
6
|
module CDATA
|
7
7
|
class Beta < Lutaml::Model::Serializable
|
@@ -117,8 +117,8 @@ module CDATA
|
|
117
117
|
|
118
118
|
def child_from_xml(model, value)
|
119
119
|
model.child_mapper ||= CustomModelChild.new
|
120
|
-
model.child_mapper.street = value.first.find_child_by_name("street").
|
121
|
-
model.child_mapper.city = value.first.find_child_by_name("city").
|
120
|
+
model.child_mapper.street = value.first.find_child_by_name("street").cdata
|
121
|
+
model.child_mapper.city = value.first.find_child_by_name("city").cdata
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
@@ -350,7 +350,7 @@ RSpec.describe "CDATA" do
|
|
350
350
|
instance = parent_mapper.from_xml(input_xml)
|
351
351
|
result_xml = parent_mapper.to_xml(instance)
|
352
352
|
|
353
|
-
expected_output = adapter_class == Lutaml::Model::
|
353
|
+
expected_output = adapter_class == Lutaml::Model::Xml::OxAdapter ? expected_ox_xml : expected_nokogiri_xml
|
354
354
|
|
355
355
|
expect(result_xml.strip).to eq(expected_output.strip)
|
356
356
|
end
|
@@ -439,7 +439,7 @@ RSpec.describe "CDATA" do
|
|
439
439
|
|
440
440
|
# due to the difference in capturing
|
441
441
|
# newlines in ox and nokogiri adapters
|
442
|
-
if adapter_class == Lutaml::Model::
|
442
|
+
if adapter_class == Lutaml::Model::Xml::OxAdapter
|
443
443
|
expected_xml = expected_ox_xml
|
444
444
|
end
|
445
445
|
|
@@ -496,7 +496,7 @@ RSpec.describe "CDATA" do
|
|
496
496
|
|
497
497
|
# due to the difference in capturing
|
498
498
|
# newlines in ox and nokogiri adapters
|
499
|
-
if adapter_class == Lutaml::Model::
|
499
|
+
if adapter_class == Lutaml::Model::Xml::OxAdapter
|
500
500
|
expected_xml = expected_ox_xml
|
501
501
|
end
|
502
502
|
|
@@ -509,11 +509,11 @@ RSpec.describe "CDATA" do
|
|
509
509
|
end
|
510
510
|
end
|
511
511
|
|
512
|
-
describe Lutaml::Model::
|
512
|
+
describe Lutaml::Model::Xml::NokogiriAdapter do
|
513
513
|
it_behaves_like "cdata behavior", described_class
|
514
514
|
end
|
515
515
|
|
516
|
-
describe Lutaml::Model::
|
516
|
+
describe Lutaml::Model::Xml::OxAdapter do
|
517
517
|
it_behaves_like "cdata behavior", described_class
|
518
518
|
end
|
519
519
|
end
|
@@ -54,6 +54,16 @@ module CollectionTests
|
|
54
54
|
doc.add_element(parent, "<city>#{model.city}</city>")
|
55
55
|
end
|
56
56
|
end
|
57
|
+
|
58
|
+
class ReturnNilTest < Lutaml::Model::Serializable
|
59
|
+
attribute :default_items, :string, collection: true
|
60
|
+
attribute :regular_items, :string, collection: true, initialize_empty: true
|
61
|
+
|
62
|
+
yaml do
|
63
|
+
map "default_items", to: :default_items
|
64
|
+
map "regular_items", to: :regular_items, render_default: true, render_empty: true
|
65
|
+
end
|
66
|
+
end
|
57
67
|
end
|
58
68
|
|
59
69
|
RSpec.describe CollectionTests do
|
@@ -95,8 +105,8 @@ RSpec.describe CollectionTests do
|
|
95
105
|
it "initializes with default values" do
|
96
106
|
default_model = CollectionTests::Kiln.new
|
97
107
|
expect(default_model.brand).to be_nil
|
98
|
-
expect(default_model.pots).to
|
99
|
-
expect(default_model.temperatures).to
|
108
|
+
expect(default_model.pots).to be_nil
|
109
|
+
expect(default_model.temperatures).to be_nil
|
100
110
|
expect(default_model.operators).to eq(["Default Operator"])
|
101
111
|
expect(default_model.sensors).to eq(["Default Sensor"])
|
102
112
|
end
|
@@ -280,4 +290,42 @@ RSpec.describe CollectionTests do
|
|
280
290
|
end.not_to raise_error
|
281
291
|
end
|
282
292
|
end
|
293
|
+
|
294
|
+
context "when using initialize_empty option with collections" do
|
295
|
+
let(:parsed) { CollectionTests::ReturnNilTest.from_yaml(yaml) }
|
296
|
+
let(:model) { CollectionTests::ReturnNilTest.new }
|
297
|
+
|
298
|
+
let(:yaml) do
|
299
|
+
<<~YAML
|
300
|
+
---
|
301
|
+
regular_items: ~
|
302
|
+
YAML
|
303
|
+
end
|
304
|
+
|
305
|
+
it "sets nil value when reading from YAML with nil value" do
|
306
|
+
expect(parsed.default_items).to be_nil
|
307
|
+
expect(parsed.regular_items).to be_nil
|
308
|
+
end
|
309
|
+
|
310
|
+
it "initializes with empty array when initialize_empty is true" do
|
311
|
+
expect(model.regular_items).to eq([])
|
312
|
+
end
|
313
|
+
|
314
|
+
it "preserves initialize_empty behavior when serializing and deserializing" do
|
315
|
+
expected_yaml = <<~YAML
|
316
|
+
---
|
317
|
+
regular_items: []
|
318
|
+
YAML
|
319
|
+
|
320
|
+
expect(model.to_yaml).to eq(expected_yaml)
|
321
|
+
end
|
322
|
+
|
323
|
+
it "raises StandardError for initialize_empty without collection" do
|
324
|
+
expect do
|
325
|
+
Class.new(Lutaml::Model::Serializable) do
|
326
|
+
attribute :invalid_range, :string, initialize_empty: true
|
327
|
+
end
|
328
|
+
end.to raise_error(StandardError, /Invalid option `initialize_empty` given without `collection: true` option/)
|
329
|
+
end
|
330
|
+
end
|
283
331
|
end
|