lutaml-model 0.8.11 → 0.8.13
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/opal.yml +31 -0
- data/.rspec-opal +5 -0
- data/.rubocop_todo.yml +45 -34
- data/README.adoc +126 -104
- data/RELEASE_NOTES.adoc +3 -3
- data/benchmark/quick_benchmark.rb +2 -2
- data/benchmark/serialization_benchmark.rb +4 -4
- data/docs/_guides/advanced-mapping.adoc +1 -1
- data/docs/_guides/character-encoding.adoc +3 -3
- data/docs/_guides/index.adoc +4 -0
- data/docs/_guides/missing-values-handling.adoc +6 -6
- data/docs/_guides/ooxml-examples.adoc +7 -7
- data/docs/_guides/opal.adoc +221 -0
- data/docs/_guides/value-transformations.adoc +7 -7
- data/docs/_guides/xml/namespace-presentation.adoc +1 -1
- data/docs/_guides/xml/namespace-semantics.adoc +15 -15
- data/docs/_guides/xml/type-namespaces.adoc +9 -9
- data/docs/_guides/xml-mapping.adoc +32 -26
- data/docs/_guides/xml-namespace-qualification.adoc +4 -4
- data/docs/_guides/xml-namespaces.adoc +2 -2
- data/docs/_guides/xml_mappings/04_xml_namespace_class.adoc +18 -18
- data/docs/_guides/xml_mappings/05_common_patterns.adoc +16 -16
- data/docs/_guides/xml_mappings/06_migration_guide.adoc +5 -5
- data/docs/_guides/xml_mappings/07_best_practices.adoc +13 -12
- data/docs/_migrations/0-8-0-namespace-restructuring.adoc +2 -2
- data/docs/_pages/attributes.adoc +2 -2
- data/docs/_pages/collections.adoc +26 -20
- data/docs/_pages/configuration.adoc +9 -4
- data/docs/_pages/consolidation-mapping.adoc +4 -4
- data/docs/_pages/importable_models.adoc +14 -13
- data/docs/_pages/index.adoc +1 -0
- data/docs/_pages/quick-start.adoc +1 -1
- data/docs/_pages/serialization_adapters.adoc +3 -2
- data/docs/_pages/value_types.adoc +10 -10
- data/docs/_references/custom_registers.adoc +7 -7
- data/docs/_references/format-independent-features.adoc +4 -4
- data/docs/_references/instance-serialization.adoc +1 -1
- data/docs/_references/parent-root-context.adoc +3 -3
- data/docs/_tutorials/basic-model-definition.adoc +1 -1
- data/docs/_tutorials/first-xml-serialization.adoc +4 -4
- data/docs/_tutorials/lutaml-xml-architecture.adoc +4 -4
- data/docs/_tutorials/validation-basics.adoc +1 -1
- data/docs/_tutorials/working-with-collections.adoc +2 -2
- data/docs/_tutorials/xml-namespaces-basics.adoc +1 -1
- data/docs/_tutorials/xml-schema-primer-style-guide.adoc +29 -29
- data/docs/cli_compare.adoc +1 -1
- data/docs/index.adoc +2 -1
- data/docs/namespace-management.adoc +14 -14
- data/lib/lutaml/hash_format/adapter/mapping.rb +2 -4
- data/lib/lutaml/json/adapter/mapping.rb +2 -4
- data/lib/lutaml/jsonl/adapter/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/hash/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/json/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/jsonl/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/toml/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/yaml/mapping.rb +2 -4
- data/lib/lutaml/key_value/adapter/yamls/mapping.rb +2 -4
- data/lib/lutaml/key_value/mapping.rb +35 -10
- data/lib/lutaml/model/adapter_resolver.rb +5 -8
- data/lib/lutaml/model/collection.rb +11 -11
- data/lib/lutaml/model/error/no_root_mapping_error.rb +6 -5
- data/lib/lutaml/model/error/no_root_namespace_error.rb +6 -5
- data/lib/lutaml/model/error/type_only_mapping_error.rb +13 -0
- data/lib/lutaml/model/error/type_only_namespace_error.rb +12 -0
- data/lib/lutaml/model/mapping/mapping.rb +12 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model.rb +3 -0
- data/lib/lutaml/toml/adapter/mapping.rb +2 -4
- data/lib/lutaml/xml/adapter/base_adapter.rb +0 -9
- data/lib/lutaml/xml/adapter/nokogiri_adapter.rb +0 -1
- data/lib/lutaml/xml/adapter/oga_adapter.rb +0 -1
- data/lib/lutaml/xml/adapter/ox_adapter.rb +0 -1
- data/lib/lutaml/xml/adapter/rexml_adapter.rb +0 -1
- data/lib/lutaml/xml/adapter/xml_serializer.rb +42 -22
- data/lib/lutaml/xml/adapter.rb +4 -0
- data/lib/lutaml/xml/builder/base.rb +64 -25
- data/lib/lutaml/xml/builder/nokogiri.rb +0 -2
- data/lib/lutaml/xml/builder/oga.rb +0 -2
- data/lib/lutaml/xml/builder/ox.rb +0 -2
- data/lib/lutaml/xml/builder/rexml.rb +0 -2
- data/lib/lutaml/xml/builder.rb +1 -0
- data/lib/lutaml/xml/configurable.rb +2 -2
- data/lib/lutaml/xml/declaration_handler.rb +3 -105
- data/lib/lutaml/xml/mapping.rb +3 -3
- data/lib/lutaml/xml/schema/xsd/documentation.rb +1 -1
- data/lib/lutaml/xml/schema/xsd.rb +5 -4
- data/lib/lutaml/xml/schema.rb +8 -5
- data/lib/lutaml/xml/serialization/collection_ext.rb +7 -7
- data/lib/lutaml/xml/serialization/format_conversion.rb +1 -1
- data/lib/lutaml/xml/serialization/instance_methods.rb +1 -1
- data/lib/lutaml/xml/xml_orderable.rb +17 -0
- data/lib/lutaml/xml.rb +9 -13
- data/lib/lutaml/yaml/adapter/mapping.rb +2 -4
- data/lib/lutaml/yamls/adapter/mapping.rb +7 -3
- data/lib/tasks/memory_profile.rb +2 -2
- data/lib/tasks/performance_benchmark.rb +5 -5
- data/lutaml-model.gemspec +1 -1
- data/spec/lutaml/key_value/transformation/rule_compiler_spec.rb +1 -1
- data/spec/lutaml/key_value/transformation/value_serializer_spec.rb +1 -1
- data/spec/lutaml/model/attribute_collection_spec.rb +1 -1
- data/spec/lutaml/model/cli_spec.rb +1 -1
- data/spec/lutaml/model/collection_spec.rb +1 -1
- data/spec/lutaml/model/collection_validation_spec.rb +6 -6
- data/spec/lutaml/model/consolidation_spec.rb +8 -8
- data/spec/lutaml/model/custom_collection_spec.rb +3 -3
- data/spec/lutaml/model/default_register_spec.rb +23 -23
- data/spec/lutaml/model/delegation_spec.rb +3 -10
- data/spec/lutaml/model/derived_attribute_serialization_spec.rb +1 -1
- data/spec/lutaml/model/dynamic_attribute_spec.rb +2 -2
- data/spec/lutaml/model/enum_spec.rb +1 -1
- data/spec/lutaml/model/group_spec.rb +12 -12
- data/spec/lutaml/model/lazy_collection_spec.rb +4 -4
- data/spec/lutaml/model/mixed_content_spec.rb +2 -2
- data/spec/lutaml/model/namespace_versioning_spec.rb +4 -4
- data/spec/lutaml/model/opal_smoke_spec.rb +117 -0
- data/spec/lutaml/model/processing_instruction_spec.rb +11 -11
- data/spec/lutaml/model/register_methods_spec.rb +2 -2
- data/spec/lutaml/model/render_empty_spec.rb +1 -1
- data/spec/lutaml/model/serialize_perf_guard_spec.rb +1 -1
- data/spec/lutaml/model/transform_dynamic_attributes_spec.rb +1 -1
- data/spec/lutaml/model/transformation_builder_spec.rb +2 -2
- data/spec/lutaml/model/xml_decoupling_spec.rb +3 -3
- data/spec/lutaml/model/xsd_patterns_spec.rb +2 -3
- data/spec/lutaml/xml/adapter/order_spec.rb +1 -1
- data/spec/lutaml/xml/clear_parse_state_spec.rb +1 -1
- data/spec/lutaml/xml/content_model_validation_spec.rb +4 -2
- data/spec/lutaml/xml/doubly_defined_namespace_spec.rb +5 -5
- data/spec/lutaml/xml/enhanced_mapping_spec.rb +2 -1
- data/spec/lutaml/xml/entity_fragmentation_spec.rb +5 -5
- data/spec/lutaml/xml/indent_spec.rb +109 -0
- data/spec/lutaml/xml/line_ending_spec.rb +66 -0
- data/spec/lutaml/xml/mapping_finalization_guard_spec.rb +2 -2
- data/spec/lutaml/xml/model_transform_guard_spec.rb +4 -4
- data/spec/lutaml/xml/namespace_alias_spec.rb +4 -4
- data/spec/lutaml/xml/namespace_aware_parsing_spec.rb +3 -3
- data/spec/lutaml/xml/namespace_bound_element_roundtrip_spec.rb +2 -2
- data/spec/lutaml/xml/namespace_format_preservation_spec.rb +1 -1
- data/spec/lutaml/xml/namespace_inheritance_spec.rb +3 -3
- data/spec/lutaml/xml/namespace_preservation_spec.rb +5 -5
- data/spec/lutaml/xml/opal_xml_spec.rb +145 -0
- data/spec/lutaml/xml/pipeline_integration_spec.rb +145 -0
- data/spec/lutaml/xml/schema_primer_spec.rb +5 -5
- data/spec/lutaml/xml/transformation_spec.rb +20 -20
- data/spec/lutaml/xml/type_namespace/collector_spec.rb +1 -1
- data/spec/lutaml/xml/type_namespace/planner_spec.rb +3 -3
- data/spec/lutaml/xml/xml_spec.rb +64 -13
- data/spec/support/opal.rb +6 -0
- metadata +16 -4
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "XML with REXML under Opal", if: RUBY_ENGINE == "opal" do
|
|
6
|
+
before do
|
|
7
|
+
Lutaml::Model::Config.xml_adapter_type = :rexml
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "round-trips XML through parse and serialize" do
|
|
11
|
+
klass = Class.new do
|
|
12
|
+
include Lutaml::Model::Serialize
|
|
13
|
+
|
|
14
|
+
attribute :name, :string
|
|
15
|
+
xml do
|
|
16
|
+
element "person"
|
|
17
|
+
map_element "name", to: :name
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
instance = klass.from_xml("<person><name>Alice</name></person>")
|
|
22
|
+
expect(instance.name).to eq("Alice")
|
|
23
|
+
expect(instance.to_xml).to include("<name>Alice</name>")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "handles XML attributes" do
|
|
27
|
+
klass = Class.new do
|
|
28
|
+
include Lutaml::Model::Serialize
|
|
29
|
+
|
|
30
|
+
attribute :id, :string
|
|
31
|
+
attribute :value, :string
|
|
32
|
+
xml do
|
|
33
|
+
element "item"
|
|
34
|
+
map_attribute "id", to: :id
|
|
35
|
+
map_element "value", to: :value
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
instance = klass.from_xml('<item id="42"><value>test</value></item>')
|
|
40
|
+
expect(instance.id).to eq("42")
|
|
41
|
+
expect(instance.value).to eq("test")
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "handles nested elements" do
|
|
45
|
+
address = Class.new do
|
|
46
|
+
include Lutaml::Model::Serialize
|
|
47
|
+
|
|
48
|
+
attribute :city, :string
|
|
49
|
+
xml do
|
|
50
|
+
element "address"
|
|
51
|
+
map_element "city", to: :city
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
person = Class.new do
|
|
56
|
+
include Lutaml::Model::Serialize
|
|
57
|
+
|
|
58
|
+
attribute :name, :string
|
|
59
|
+
attribute :address, address
|
|
60
|
+
xml do
|
|
61
|
+
element "person"
|
|
62
|
+
map_element "name", to: :name
|
|
63
|
+
map_element "address", to: :address
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
instance = person.from_xml("<person><name>Alice</name><address><city>NYC</city></address></person>")
|
|
68
|
+
expect(instance.name).to eq("Alice")
|
|
69
|
+
expect(instance.address.city).to eq("NYC")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "handles element collections" do
|
|
73
|
+
list = Class.new do
|
|
74
|
+
include Lutaml::Model::Serialize
|
|
75
|
+
|
|
76
|
+
attribute :items, :string, collection: true
|
|
77
|
+
xml do
|
|
78
|
+
element "list"
|
|
79
|
+
map_element "item", to: :items
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
instance = list.from_xml("<list><item>a</item><item>b</item><item>c</item></list>")
|
|
84
|
+
expect(instance.items).to eq(%w[a b c])
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
it "handles mixed content" do
|
|
88
|
+
paragraph = Class.new do
|
|
89
|
+
include Lutaml::Model::Serialize
|
|
90
|
+
|
|
91
|
+
attribute :content, :string, collection: true
|
|
92
|
+
xml do
|
|
93
|
+
element "p"
|
|
94
|
+
mixed_content
|
|
95
|
+
map_content to: :content
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
instance = paragraph.from_xml("<p>Hello <b>world</b> end</p>")
|
|
100
|
+
expect(instance.content.join).to include("Hello")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "serializes to XML with correct structure" do
|
|
104
|
+
item = Class.new do
|
|
105
|
+
include Lutaml::Model::Serialize
|
|
106
|
+
|
|
107
|
+
attribute :title, :string
|
|
108
|
+
attribute :count, :integer
|
|
109
|
+
xml do
|
|
110
|
+
element "item"
|
|
111
|
+
map_element "title", to: :title
|
|
112
|
+
map_element "count", to: :count
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
instance = item.new(title: "Widget", count: 5)
|
|
117
|
+
xml = instance.to_xml
|
|
118
|
+
expect(xml).to include("<title>Widget</title>")
|
|
119
|
+
expect(xml).to include("<count>5</count>")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "handles XmlOrderable on plain model classes" do
|
|
123
|
+
plain_model = Class.new do
|
|
124
|
+
attr_accessor :data
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
Class.new do
|
|
128
|
+
include Lutaml::Model::Serialize
|
|
129
|
+
|
|
130
|
+
const_set(:MODEL_CLASS, plain_model)
|
|
131
|
+
model plain_model
|
|
132
|
+
attribute :data, :string
|
|
133
|
+
xml do
|
|
134
|
+
element "data"
|
|
135
|
+
map_element "data", to: :data
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
expect(plain_model.ancestors).to include(Lutaml::Xml::XmlOrderable)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
it "uses REXML adapter by default under Opal" do
|
|
143
|
+
expect(Lutaml::Model::Config.xml_adapter_type).to eq(:rexml)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
RSpec.describe "Full serialization pipeline" do
|
|
6
|
+
before do
|
|
7
|
+
item_class = Class.new do
|
|
8
|
+
include Lutaml::Model::Serialize
|
|
9
|
+
|
|
10
|
+
attribute :name, :string
|
|
11
|
+
attribute :value, :string
|
|
12
|
+
|
|
13
|
+
xml do
|
|
14
|
+
element "item"
|
|
15
|
+
map_element "name", to: :name
|
|
16
|
+
map_element "value", to: :value
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
stub_const("PipeItem", item_class)
|
|
21
|
+
|
|
22
|
+
doc_class = Class.new do
|
|
23
|
+
include Lutaml::Model::Serialize
|
|
24
|
+
|
|
25
|
+
attribute :title, :string
|
|
26
|
+
attribute :items, PipeItem, collection: true
|
|
27
|
+
|
|
28
|
+
xml do
|
|
29
|
+
element "document"
|
|
30
|
+
map_element "title", to: :title
|
|
31
|
+
map_element "item", to: :items
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
stub_const("PipeDoc", doc_class)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
let(:model) do
|
|
39
|
+
PipeDoc.new(
|
|
40
|
+
title: "Test",
|
|
41
|
+
items: [
|
|
42
|
+
PipeItem.new(name: "a", value: "1"),
|
|
43
|
+
PipeItem.new(name: "b", value: "2"),
|
|
44
|
+
],
|
|
45
|
+
)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "produces identical output for identical models across multiple runs" do
|
|
49
|
+
first = model.to_xml
|
|
50
|
+
second = model.to_xml
|
|
51
|
+
expect(first).to eq(second)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
it "handles declaration + doctype + content together" do
|
|
55
|
+
xml = model.to_xml(
|
|
56
|
+
declaration: true,
|
|
57
|
+
doctype: { name: "document", system_id: "doc.dtd" },
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
expect(xml).to start_with("<?xml")
|
|
61
|
+
expect(xml).to include("<!DOCTYPE document SYSTEM \"doc.dtd\">")
|
|
62
|
+
expect(xml).to include("<title>Test</title>")
|
|
63
|
+
expect(xml).to include("<name>a</name>")
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it "CRLF + indent=4 + declaration produces correct output" do
|
|
67
|
+
xml = model.to_xml(
|
|
68
|
+
line_ending: "\r\n",
|
|
69
|
+
indent: 4,
|
|
70
|
+
declaration: true,
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
expect(xml.lines).to all(end_with("\r\n"))
|
|
74
|
+
expect(xml).to include(" <title>Test</title>")
|
|
75
|
+
expect(xml).to include("<?xml")
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "round-trips complex XML with all features preserved" do
|
|
79
|
+
input = <<~XML
|
|
80
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
81
|
+
<document>
|
|
82
|
+
<title>Original</title>
|
|
83
|
+
<item>
|
|
84
|
+
<name>x</name>
|
|
85
|
+
<value>42</value>
|
|
86
|
+
</item>
|
|
87
|
+
</document>
|
|
88
|
+
XML
|
|
89
|
+
|
|
90
|
+
parsed = PipeDoc.from_xml(input)
|
|
91
|
+
expect(parsed.title).to eq("Original")
|
|
92
|
+
expect(parsed.items.length).to eq(1)
|
|
93
|
+
expect(parsed.items.first.name).to eq("x")
|
|
94
|
+
expect(parsed.items.first.value).to eq("42")
|
|
95
|
+
|
|
96
|
+
output = parsed.to_xml(declaration: true)
|
|
97
|
+
expect(output).to start_with("<?xml")
|
|
98
|
+
expect(output).to include("<title>Original</title>")
|
|
99
|
+
expect(output).to include("<name>x</name>")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "round-trip preserves namespace declarations" do
|
|
103
|
+
ns = Class.new(Lutaml::Xml::W3c::XmlNamespace) do
|
|
104
|
+
uri "http://example.com/ns"
|
|
105
|
+
prefix_default "ex"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
stub_const("PipeNs", ns)
|
|
109
|
+
|
|
110
|
+
ns_child = Class.new do
|
|
111
|
+
include Lutaml::Model::Serialize
|
|
112
|
+
|
|
113
|
+
attribute :content, :string
|
|
114
|
+
|
|
115
|
+
xml do
|
|
116
|
+
element "child"
|
|
117
|
+
namespace PipeNs
|
|
118
|
+
map_element "content", to: :content
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
stub_const("PipeNsChild", ns_child)
|
|
123
|
+
|
|
124
|
+
ns_parent = Class.new do
|
|
125
|
+
include Lutaml::Model::Serialize
|
|
126
|
+
|
|
127
|
+
attribute :child, PipeNsChild
|
|
128
|
+
|
|
129
|
+
xml do
|
|
130
|
+
element "parent"
|
|
131
|
+
map_element "child", to: :child
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
stub_const("PipeNsParent", ns_parent)
|
|
136
|
+
|
|
137
|
+
instance = PipeNsParent.new(child: PipeNsChild.new(content: "data"))
|
|
138
|
+
xml = instance.to_xml
|
|
139
|
+
|
|
140
|
+
expect(xml).to include("xmlns")
|
|
141
|
+
|
|
142
|
+
parsed = PipeNsParent.from_xml(xml)
|
|
143
|
+
expect(parsed.child.content).to eq("data")
|
|
144
|
+
end
|
|
145
|
+
end
|
|
@@ -44,7 +44,7 @@ module XmlSchemaPrimerFeaturesSpec
|
|
|
44
44
|
attribute :work_address, AddressType
|
|
45
45
|
|
|
46
46
|
xml do
|
|
47
|
-
|
|
47
|
+
element "Person"
|
|
48
48
|
map_element "homeAddress", to: :home_address
|
|
49
49
|
map_element "workAddress", to: :work_address
|
|
50
50
|
end
|
|
@@ -69,7 +69,7 @@ module XmlSchemaPrimerFeaturesSpec
|
|
|
69
69
|
attribute :ship_to, UsAddress
|
|
70
70
|
|
|
71
71
|
xml do
|
|
72
|
-
|
|
72
|
+
element "purchaseOrder"
|
|
73
73
|
namespace PoNamespace
|
|
74
74
|
map_element "shipTo", to: :ship_to
|
|
75
75
|
end
|
|
@@ -85,7 +85,7 @@ module XmlSchemaPrimerFeaturesSpec
|
|
|
85
85
|
attribute :comment, :string
|
|
86
86
|
|
|
87
87
|
xml do
|
|
88
|
-
|
|
88
|
+
element "purchaseOrder"
|
|
89
89
|
namespace PoNamespaceQualified
|
|
90
90
|
|
|
91
91
|
map_element "shipTo", to: :ship_to
|
|
@@ -103,7 +103,7 @@ module XmlSchemaPrimerFeaturesSpec
|
|
|
103
103
|
attribute :comment, :string
|
|
104
104
|
|
|
105
105
|
xml do
|
|
106
|
-
|
|
106
|
+
element "purchaseOrder"
|
|
107
107
|
namespace PoNamespacePrefixed
|
|
108
108
|
|
|
109
109
|
map_element "shipTo", to: :ship_to
|
|
@@ -129,7 +129,7 @@ module XmlSchemaPrimerFeaturesSpec
|
|
|
129
129
|
attribute :notes, :string
|
|
130
130
|
|
|
131
131
|
xml do
|
|
132
|
-
|
|
132
|
+
element "supplier"
|
|
133
133
|
namespace MixedNamespace
|
|
134
134
|
|
|
135
135
|
map_element "contact", to: :contact
|
|
@@ -10,7 +10,7 @@ module TransformationSpecModels
|
|
|
10
10
|
attribute :value, :integer
|
|
11
11
|
|
|
12
12
|
xml do
|
|
13
|
-
|
|
13
|
+
element "SimpleModel"
|
|
14
14
|
map_element "name", to: :name
|
|
15
15
|
map_element "value", to: :value
|
|
16
16
|
end
|
|
@@ -21,7 +21,7 @@ module TransformationSpecModels
|
|
|
21
21
|
attribute :type, :string
|
|
22
22
|
|
|
23
23
|
xml do
|
|
24
|
-
|
|
24
|
+
element "Model"
|
|
25
25
|
map_attribute "id", to: :id
|
|
26
26
|
map_attribute "type", to: :type
|
|
27
27
|
end
|
|
@@ -31,7 +31,7 @@ module TransformationSpecModels
|
|
|
31
31
|
attribute :text, :string
|
|
32
32
|
|
|
33
33
|
xml do
|
|
34
|
-
|
|
34
|
+
element "Model"
|
|
35
35
|
map_content to: :text
|
|
36
36
|
end
|
|
37
37
|
end
|
|
@@ -41,7 +41,7 @@ module TransformationSpecModels
|
|
|
41
41
|
attribute :email, :string
|
|
42
42
|
|
|
43
43
|
xml do
|
|
44
|
-
|
|
44
|
+
element "Contact"
|
|
45
45
|
map_element "name", to: :name
|
|
46
46
|
map_element "email", to: :email
|
|
47
47
|
end
|
|
@@ -52,7 +52,7 @@ module TransformationSpecModels
|
|
|
52
52
|
attribute :name, :string
|
|
53
53
|
|
|
54
54
|
xml do
|
|
55
|
-
|
|
55
|
+
element "Person"
|
|
56
56
|
map_attribute "id", to: :id
|
|
57
57
|
map_element "name", to: :name
|
|
58
58
|
end
|
|
@@ -62,7 +62,7 @@ module TransformationSpecModels
|
|
|
62
62
|
attribute :content, :string
|
|
63
63
|
|
|
64
64
|
xml do
|
|
65
|
-
|
|
65
|
+
element "Note"
|
|
66
66
|
map_content to: :content
|
|
67
67
|
end
|
|
68
68
|
end
|
|
@@ -72,7 +72,7 @@ module TransformationSpecModels
|
|
|
72
72
|
attribute :city, :string
|
|
73
73
|
|
|
74
74
|
xml do
|
|
75
|
-
|
|
75
|
+
element "Address"
|
|
76
76
|
map_element "street", to: :street
|
|
77
77
|
map_element "city", to: :city
|
|
78
78
|
end
|
|
@@ -83,7 +83,7 @@ module TransformationSpecModels
|
|
|
83
83
|
attribute :address, TransformationSpecModels::Address
|
|
84
84
|
|
|
85
85
|
xml do
|
|
86
|
-
|
|
86
|
+
element "Person"
|
|
87
87
|
map_element "name", to: :name
|
|
88
88
|
map_element "Address", to: :address
|
|
89
89
|
end
|
|
@@ -93,7 +93,7 @@ module TransformationSpecModels
|
|
|
93
93
|
attribute :title, :string
|
|
94
94
|
|
|
95
95
|
xml do
|
|
96
|
-
|
|
96
|
+
element "Book"
|
|
97
97
|
map_element "title", to: :title
|
|
98
98
|
end
|
|
99
99
|
end
|
|
@@ -103,7 +103,7 @@ module TransformationSpecModels
|
|
|
103
103
|
attribute :book, TransformationSpecModels::Book
|
|
104
104
|
|
|
105
105
|
xml do
|
|
106
|
-
|
|
106
|
+
element "Library"
|
|
107
107
|
map_element "name", to: :name
|
|
108
108
|
map_element "Book", to: :book
|
|
109
109
|
end
|
|
@@ -113,7 +113,7 @@ module TransformationSpecModels
|
|
|
113
113
|
attribute :tags, :string, collection: true
|
|
114
114
|
|
|
115
115
|
xml do
|
|
116
|
-
|
|
116
|
+
element "TagList"
|
|
117
117
|
map_element "tag", to: :tags
|
|
118
118
|
end
|
|
119
119
|
end
|
|
@@ -123,7 +123,7 @@ module TransformationSpecModels
|
|
|
123
123
|
attribute :price, :float
|
|
124
124
|
|
|
125
125
|
xml do
|
|
126
|
-
|
|
126
|
+
element "Item"
|
|
127
127
|
map_element "name", to: :name
|
|
128
128
|
map_element "price", to: :price
|
|
129
129
|
end
|
|
@@ -133,7 +133,7 @@ module TransformationSpecModels
|
|
|
133
133
|
attribute :items, TransformationSpecModels::Item, collection: true
|
|
134
134
|
|
|
135
135
|
xml do
|
|
136
|
-
|
|
136
|
+
element "Cart"
|
|
137
137
|
map_element "Item", to: :items
|
|
138
138
|
end
|
|
139
139
|
end
|
|
@@ -149,7 +149,7 @@ module TransformationSpecModels
|
|
|
149
149
|
attribute :value, :string
|
|
150
150
|
|
|
151
151
|
xml do
|
|
152
|
-
|
|
152
|
+
element "Model"
|
|
153
153
|
namespace TestNs::MyNamespace
|
|
154
154
|
map_element "value", to: :value
|
|
155
155
|
end
|
|
@@ -171,7 +171,7 @@ module TransformationSpecModels
|
|
|
171
171
|
attribute :value, :string
|
|
172
172
|
|
|
173
173
|
xml do
|
|
174
|
-
|
|
174
|
+
element "Child"
|
|
175
175
|
namespace NsTest::Ns2
|
|
176
176
|
map_element "value", to: :value
|
|
177
177
|
end
|
|
@@ -182,7 +182,7 @@ module TransformationSpecModels
|
|
|
182
182
|
attribute :child, TransformationSpecModels::Child
|
|
183
183
|
|
|
184
184
|
xml do
|
|
185
|
-
|
|
185
|
+
element "Parent"
|
|
186
186
|
namespace NsTest::Ns1
|
|
187
187
|
map_element "name", to: :name
|
|
188
188
|
map_element "Child", to: :child
|
|
@@ -195,7 +195,7 @@ module TransformationSpecModels
|
|
|
195
195
|
}
|
|
196
196
|
|
|
197
197
|
xml do
|
|
198
|
-
|
|
198
|
+
element "Model"
|
|
199
199
|
map_element "name", to: :name
|
|
200
200
|
end
|
|
201
201
|
end
|
|
@@ -204,7 +204,7 @@ module TransformationSpecModels
|
|
|
204
204
|
attribute :status, :string, default: -> { "active" }
|
|
205
205
|
|
|
206
206
|
xml do
|
|
207
|
-
|
|
207
|
+
element "Model"
|
|
208
208
|
map_element "status", to: :status, render_default: false
|
|
209
209
|
end
|
|
210
210
|
end
|
|
@@ -213,7 +213,7 @@ module TransformationSpecModels
|
|
|
213
213
|
attribute :optional, :string
|
|
214
214
|
|
|
215
215
|
xml do
|
|
216
|
-
|
|
216
|
+
element "Model"
|
|
217
217
|
map_element "optional", to: :optional, render_nil: true
|
|
218
218
|
end
|
|
219
219
|
end
|
|
@@ -222,7 +222,7 @@ module TransformationSpecModels
|
|
|
222
222
|
attribute :value, :string
|
|
223
223
|
|
|
224
224
|
xml do
|
|
225
|
-
|
|
225
|
+
element "Model"
|
|
226
226
|
map_element "value", to: :value
|
|
227
227
|
end
|
|
228
228
|
end
|
|
@@ -33,7 +33,7 @@ RSpec.describe Lutaml::Xml::TypeNamespace::Planner do
|
|
|
33
33
|
attribute :author, :string
|
|
34
34
|
|
|
35
35
|
xml do
|
|
36
|
-
|
|
36
|
+
element "document"
|
|
37
37
|
map_element "title", to: :title
|
|
38
38
|
map_element "author", to: :author
|
|
39
39
|
end
|
|
@@ -155,7 +155,7 @@ RSpec.describe Lutaml::Xml::TypeNamespace::Planner do
|
|
|
155
155
|
attribute :title, type
|
|
156
156
|
|
|
157
157
|
xml do
|
|
158
|
-
|
|
158
|
+
element "document"
|
|
159
159
|
map_element "title", to: :title
|
|
160
160
|
end
|
|
161
161
|
end
|
|
@@ -183,7 +183,7 @@ RSpec.describe Lutaml::Xml::TypeNamespace::Planner do
|
|
|
183
183
|
attribute :title, :string
|
|
184
184
|
|
|
185
185
|
xml do
|
|
186
|
-
|
|
186
|
+
element "document"
|
|
187
187
|
map_element "title", to: :title
|
|
188
188
|
end
|
|
189
189
|
end
|
data/spec/lutaml/xml/xml_spec.rb
CHANGED
|
@@ -1,18 +1,34 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
|
+
require "open3"
|
|
4
5
|
require "lutaml/xml"
|
|
5
6
|
|
|
6
7
|
RSpec.describe Lutaml::Xml do
|
|
7
|
-
|
|
8
|
-
let(:lib_path) { File.expand_path("../../../lib", __dir__) }
|
|
8
|
+
let(:lib_path) { File.expand_path("../../../lib", __dir__) }
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
def run_ruby(script)
|
|
11
|
+
stdout, stderr, status = Open3.capture3(
|
|
12
|
+
RbConfig.ruby, "-I#{lib_path}", "-e", script
|
|
13
|
+
)
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
[stdout + stderr, status]
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "standalone loading" do
|
|
19
|
+
it "lazy-loads the schema namespace from the XML entry point" do
|
|
20
|
+
script = <<~RUBY
|
|
21
|
+
require "lutaml/xml"
|
|
22
|
+
abort "missing Schema autoload" unless Lutaml::Xml.autoload?(:Schema)
|
|
23
|
+
unless Lutaml::Xml::Schema.const_defined?(:Xsd, false)
|
|
24
|
+
abort "missing Xsd autoload"
|
|
25
|
+
end
|
|
26
|
+
puts :ok
|
|
27
|
+
RUBY
|
|
28
|
+
|
|
29
|
+
result, status = run_ruby(script)
|
|
30
|
+
|
|
31
|
+
expect(status.success?).to be(true), result
|
|
16
32
|
expect(result).to include("ok")
|
|
17
33
|
end
|
|
18
34
|
end
|
|
@@ -22,6 +38,44 @@ RSpec.describe Lutaml::Xml do
|
|
|
22
38
|
expect(described_class::Schema.const_defined?(:Xsd, false))
|
|
23
39
|
.to be(!Lutaml::Model::RuntimeCompatibility.opal?)
|
|
24
40
|
end
|
|
41
|
+
|
|
42
|
+
it "does not autoload schema constants when loaded under Opal" do
|
|
43
|
+
script = <<~'RUBY'
|
|
44
|
+
require "lutaml/model/runtime_compatibility"
|
|
45
|
+
|
|
46
|
+
module Lutaml
|
|
47
|
+
module Model
|
|
48
|
+
module RuntimeCompatibility
|
|
49
|
+
def self.opal?
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
require "lutaml/xml/schema"
|
|
57
|
+
|
|
58
|
+
schema_constants = %i[
|
|
59
|
+
Xsd XsdSchema RelaxngSchema Builder BuiltinTypes
|
|
60
|
+
]
|
|
61
|
+
|
|
62
|
+
loaded_constants = schema_constants.select do |constant_name|
|
|
63
|
+
Lutaml::Xml::Schema.autoload?(constant_name) ||
|
|
64
|
+
Lutaml::Xml::Schema.const_defined?(constant_name, false)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
if loaded_constants.any?
|
|
68
|
+
abort "loaded schema constants: #{loaded_constants.join(', ')}"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
puts :ok
|
|
72
|
+
RUBY
|
|
73
|
+
|
|
74
|
+
result, status = run_ruby(script)
|
|
75
|
+
|
|
76
|
+
expect(status.success?).to be(true), result
|
|
77
|
+
expect(result).to include("ok")
|
|
78
|
+
end
|
|
25
79
|
end
|
|
26
80
|
|
|
27
81
|
describe "schema methods" do
|
|
@@ -66,9 +120,6 @@ RSpec.describe Lutaml::Xml do
|
|
|
66
120
|
hide_const("Ox") if Object.const_defined?(:Ox)
|
|
67
121
|
hide_const("Oga") if Object.const_defined?(:Oga)
|
|
68
122
|
hide_const("REXML") if Object.const_defined?(:REXML)
|
|
69
|
-
|
|
70
|
-
# Stub require to prevent any actual requires during testing
|
|
71
|
-
allow(Lutaml::Model::Utils).to receive(:require).and_return(true)
|
|
72
123
|
end
|
|
73
124
|
|
|
74
125
|
context "when Nokogiri is available" do
|
|
@@ -101,9 +152,9 @@ RSpec.describe Lutaml::Xml do
|
|
|
101
152
|
end
|
|
102
153
|
end
|
|
103
154
|
|
|
104
|
-
context "when no adapters are
|
|
105
|
-
it "
|
|
106
|
-
expect(described_class.detect_xml_adapter).to
|
|
155
|
+
context "when no adapters are detected" do
|
|
156
|
+
it "falls back to moxml default (:nokogiri)" do
|
|
157
|
+
expect(described_class.detect_xml_adapter).to eq(:nokogiri)
|
|
107
158
|
end
|
|
108
159
|
end
|
|
109
160
|
|