lutaml-model 0.8.16 → 0.8.18
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/downstream-performance.yml +27 -1
- data/.github/workflows/js-pr-check.yml +102 -0
- data/.github/workflows/js-sync.yml +51 -0
- data/.github/workflows/opal.yml +26 -6
- data/.github/workflows/performance.yml +32 -7
- data/.github/workflows/rake.yml +78 -32
- data/.github/workflows/release.yml +0 -3
- data/.gitmodules +6 -0
- data/.rubocop_todo.yml +76 -12
- data/Gemfile +16 -1
- data/README.adoc +267 -0
- data/Rakefile +166 -4
- data/docs/_guides/schema-import.adoc +42 -0
- data/docs/_guides/xml/namespace-semantics.adoc +2 -0
- data/docs/_guides/xml-mapping.adoc +21 -0
- data/docs/_guides/xml-namespace-qualification.adoc +142 -0
- data/docs/_pages/validation.adoc +65 -0
- data/docs/_tutorials/xml-element-attribute-namespace-guide.adoc +2 -0
- data/docs/_tutorials/xml-schema-primer-style-guide.adoc +2 -0
- data/docs/namespace-management.adoc +2 -0
- data/docs/xml-schema-qualification.md +6 -0
- data/lib/compat/opal/generate_boot.rb +123 -0
- data/lib/compat/opal/js_bundle_entry.rb +42 -0
- data/lib/compat/opal/lutaml_model_boot.rb +497 -0
- data/lib/compat/opal/moxml_boot.rb +68 -0
- data/lib/compat/opal/yaml_compat.rb +32 -0
- data/lib/lutaml/json.rb +1 -1
- data/lib/lutaml/jsonld.rb +1 -4
- data/lib/lutaml/key_value/transform.rb +3 -8
- data/lib/lutaml/key_value/transformation/value_serializer.rb +14 -1
- data/lib/lutaml/key_value/transformation.rb +17 -5
- data/lib/lutaml/model/adapter_resolver.rb +2 -2
- data/lib/lutaml/model/attribute.rb +88 -11
- data/lib/lutaml/model/cached_type_resolver.rb +1 -1
- data/lib/lutaml/model/choice.rb +34 -0
- data/lib/lutaml/model/compiled_rule.rb +7 -0
- data/lib/lutaml/model/error/union_schema_unsupported_error.rb +11 -0
- data/lib/lutaml/model/global_context.rb +11 -8
- data/lib/lutaml/model/instrumentation.rb +2 -2
- data/lib/lutaml/model/mapping/mapping_rule.rb +0 -6
- data/lib/lutaml/model/register.rb +2 -2
- data/lib/lutaml/model/runtime_compatibility.rb +50 -0
- data/lib/lutaml/model/schema/class_loader.rb +58 -0
- data/lib/lutaml/model/schema/compiled_output.rb +83 -0
- data/lib/lutaml/model/schema/definitions/attribute.rb +32 -0
- data/lib/lutaml/model/schema/definitions/choice.rb +20 -0
- data/lib/lutaml/model/schema/definitions/facet.rb +40 -0
- data/lib/lutaml/model/schema/definitions/group_import.rb +22 -0
- data/lib/lutaml/model/schema/definitions/member_walk.rb +33 -0
- data/lib/lutaml/model/schema/definitions/model.rb +40 -0
- data/lib/lutaml/model/schema/definitions/namespace.rb +23 -0
- data/lib/lutaml/model/schema/definitions/restricted_type.rb +30 -0
- data/lib/lutaml/model/schema/definitions/sequence.rb +19 -0
- data/lib/lutaml/model/schema/definitions/simple_content.rb +22 -0
- data/lib/lutaml/model/schema/definitions/transform_facet.rb +21 -0
- data/lib/lutaml/model/schema/definitions/type_ref.rb +20 -0
- data/lib/lutaml/model/schema/definitions/union_type.rb +28 -0
- data/lib/lutaml/model/schema/definitions/xml_root.rb +20 -0
- data/lib/lutaml/model/schema/definitions.rb +24 -0
- data/lib/lutaml/model/schema/file_writer.rb +70 -0
- data/lib/lutaml/model/schema/generator/definitions_collection.rb +16 -2
- data/lib/lutaml/model/schema/generator/property.rb +21 -4
- data/lib/lutaml/model/schema/module_nesting.rb +31 -0
- data/lib/lutaml/model/schema/namespace_naming.rb +46 -0
- data/lib/lutaml/model/schema/registry_generator.rb +115 -0
- data/lib/lutaml/model/schema/renderers/base.rb +40 -0
- data/lib/lutaml/model/schema/renderers/mappings.rb +72 -0
- data/lib/lutaml/model/schema/renderers/member_decls.rb +115 -0
- data/lib/lutaml/model/schema/renderers/model.rb +121 -0
- data/lib/lutaml/model/schema/renderers/namespace.rb +30 -0
- data/lib/lutaml/model/schema/renderers/registration.rb +64 -0
- data/lib/lutaml/model/schema/renderers/required_files_calculator.rb +93 -0
- data/lib/lutaml/model/schema/renderers/restricted_type.rb +88 -0
- data/lib/lutaml/model/schema/renderers/union.rb +83 -0
- data/lib/lutaml/model/schema/renderers.rb +19 -0
- data/lib/lutaml/model/schema/rnc_compiler/source_resolver.rb +47 -0
- data/lib/lutaml/model/schema/rnc_compiler.rb +62 -0
- data/lib/lutaml/model/schema/rng_compiler/define_classifier.rb +91 -0
- data/lib/lutaml/model/schema/rng_compiler/element_visitor.rb +392 -0
- data/lib/lutaml/model/schema/rng_compiler/member_collector.rb +30 -0
- data/lib/lutaml/model/schema/rng_compiler/rng_helpers.rb +152 -0
- data/lib/lutaml/model/schema/rng_compiler/value_type_resolver.rb +125 -0
- data/lib/lutaml/model/schema/rng_compiler.rb +220 -0
- data/lib/lutaml/model/schema/templates.rb +162 -0
- data/lib/lutaml/model/schema/xml_compiler/element_order.rb +41 -0
- data/lib/lutaml/model/schema/xml_compiler/registry_generator.rb +31 -107
- data/lib/lutaml/model/schema/xml_compiler/spec_builder/complex_types.rb +191 -0
- data/lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb +216 -0
- data/lib/lutaml/model/schema/xml_compiler/spec_builder/simple_types.rb +153 -0
- data/lib/lutaml/model/schema/xml_compiler/spec_builder.rb +167 -0
- data/lib/lutaml/model/schema/xml_compiler/supported_data_types.rb +87 -0
- data/lib/lutaml/model/schema/xml_compiler.rb +38 -517
- data/lib/lutaml/model/schema.rb +19 -0
- data/lib/lutaml/model/serialize/attribute_definition.rb +14 -2
- data/lib/lutaml/model/serialize/builder.rb +15 -2
- data/lib/lutaml/model/serialize/value_mapping.rb +9 -57
- data/lib/lutaml/model/serialize.rb +6 -9
- data/lib/lutaml/model/services/rule_value_extractor.rb +2 -3
- data/lib/lutaml/model/services.rb +0 -2
- data/lib/lutaml/model/store.rb +2 -1
- data/lib/lutaml/model/toml.rb +1 -1
- data/lib/lutaml/model/transform.rb +17 -39
- data/lib/lutaml/model/transformation_registry.rb +1 -1
- data/lib/lutaml/model/type.rb +1 -0
- data/lib/lutaml/model/union.rb +320 -0
- data/lib/lutaml/model/utils.rb +6 -0
- data/lib/lutaml/model/validation.rb +1 -4
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model.rb +19 -0
- data/lib/lutaml/{jsonld → rdf}/context.rb +1 -1
- data/lib/lutaml/{jsonld/transform.rb → rdf/linked_data_transform.rb} +33 -35
- data/lib/lutaml/{jsonld → rdf}/term_definition.rb +1 -1
- data/lib/lutaml/rdf.rb +3 -0
- data/lib/lutaml/toml.rb +1 -1
- data/lib/lutaml/xml/adapter.rb +1 -1
- data/lib/lutaml/xml/adapter_element.rb +2 -2
- data/lib/lutaml/xml/adapter_loader.rb +1 -1
- data/lib/lutaml/xml/builder/base.rb +1 -1
- data/lib/lutaml/xml/builder.rb +1 -1
- data/lib/lutaml/xml/error/schema_validation_error.rb +25 -0
- data/lib/lutaml/xml/model_transform.rb +5 -1
- data/lib/lutaml/xml/schema/relaxng_schema.rb +5 -0
- data/lib/lutaml/xml/schema/xsd_schema.rb +4 -0
- data/lib/lutaml/xml/serialization/format_conversion.rb +48 -0
- data/lib/lutaml/xml/serialization/instance_methods.rb +13 -0
- data/lib/lutaml/xml/transformation/element_builder.rb +59 -31
- data/lib/lutaml/xml/transformation/ordered_applier.rb +6 -0
- data/lib/lutaml/xml/xsd_validator.rb +66 -0
- data/lib/lutaml/xml.rb +53 -12
- data/lib/lutaml/yamlld/adapter.rb +25 -0
- data/lib/lutaml/yamlld.rb +25 -0
- data/lutaml-model.gemspec +4 -2
- data/spec/fixtures/xml/schema/rnc/address_book.rnc +15 -0
- data/spec/fixtures/xml/schema/rnc/book_features.rnc +18 -0
- data/spec/fixtures/xml/schema/rnc/includes/book.rnc +6 -0
- data/spec/fixtures/xml/schema/rnc/includes/circular_a.rnc +8 -0
- data/spec/fixtures/xml/schema/rnc/includes/circular_b.rnc +8 -0
- data/spec/fixtures/xml/schema/rnc/includes/library.rnc +8 -0
- data/spec/fixtures/xml/schema/rng/address_book.rng +16 -0
- data/spec/fixtures/xml/schema/rng/book.rng +27 -0
- data/spec/fixtures/xml/schema/rng/fixed_value.rng +11 -0
- data/spec/fixtures/xml/schema/rng/fragment_in_choice.rng +30 -0
- data/spec/fixtures/xml/schema/rng/full_name.rng +39 -0
- data/spec/fixtures/xml/schema/rng/integer_range.rng +32 -0
- data/spec/fixtures/xml/schema/rng/list_type.rng +12 -0
- data/spec/fixtures/xml/schema/rng/namespaced.rng +9 -0
- data/spec/fixtures/xml/schema/rng/paragraph.rng +13 -0
- data/spec/fixtures/xml/schema/rng/person.rng +23 -0
- data/spec/fixtures/xml/schema/rng/union.rng +14 -0
- data/spec/fixtures/xml/validate_xml_with_address.xsd +13 -0
- data/spec/fixtures/xml/validate_xml_with_contact.xsd +11 -0
- data/spec/fixtures/xml/validate_xml_with_person.xsd +11 -0
- data/spec/fixtures/xml/validate_xml_with_person_strict.xsd +17 -0
- data/spec/fixtures/xml/validate_xml_with_product.xsd +37 -0
- data/spec/lutaml/integration/multi_format_spec.rb +23 -0
- data/spec/lutaml/model/attribute_apply_value_map_spec.rb +134 -0
- data/spec/lutaml/model/attribute_spec.rb +177 -13
- data/spec/lutaml/model/boot_manifest_spec.rb +30 -0
- data/spec/lutaml/model/choice_restrict_spec.rb +225 -0
- data/spec/lutaml/model/collection_spec.rb +18 -0
- data/spec/lutaml/model/custom_model_spec.rb +4 -4
- data/spec/lutaml/model/mixed_content_spec.rb +173 -2
- data/spec/lutaml/model/multiple_mapping_spec.rb +4 -4
- data/spec/lutaml/model/opal_smoke_spec.rb +67 -2
- data/spec/lutaml/model/ordered_content_spec.rb +33 -3
- data/spec/lutaml/model/raw_element_spec.rb +125 -0
- data/spec/lutaml/model/rule_value_extractor_spec.rb +7 -14
- data/spec/lutaml/model/runtime_compatibility_spec.rb +25 -0
- data/spec/lutaml/model/schema/renderers/model_spec.rb +149 -0
- data/spec/lutaml/model/schema/renderers/namespace_spec.rb +36 -0
- data/spec/lutaml/model/schema/renderers/restricted_type_spec.rb +75 -0
- data/spec/lutaml/model/schema/renderers/union_spec.rb +58 -0
- data/spec/lutaml/model/transform_apply_value_map_spec.rb +64 -0
- data/spec/lutaml/model/uninitialized_class_spec.rb +1 -1
- data/spec/lutaml/model/union_attribute_spec.rb +658 -0
- data/spec/lutaml/model/union_spec.rb +257 -0
- data/spec/lutaml/model/utils_spec.rb +14 -0
- data/spec/lutaml/model/xsd_form_default_patterns_spec.rb +2 -2
- data/spec/lutaml/model/xsd_patterns_spec.rb +4 -4
- data/spec/lutaml/{jsonld → rdf}/context_spec.rb +2 -2
- data/spec/lutaml/{jsonld/transform_spec.rb → rdf/linked_data_transform_spec.rb} +15 -1
- data/spec/lutaml/{jsonld → rdf}/term_definition_spec.rb +2 -2
- data/spec/lutaml/turtle/transform_spec.rb +2 -2
- data/spec/lutaml/xml/enhanced_mapping_spec.rb +230 -1
- data/spec/lutaml/xml/mapping_spec.rb +4 -4
- data/spec/lutaml/xml/namespace_placement_spec.rb +11 -8
- data/spec/lutaml/xml/namespace_three_phase_spec.rb +1 -1
- data/spec/lutaml/xml/opal_xml_spec.rb +22 -20
- data/spec/lutaml/xml/prefix_control_spec.rb +4 -4
- data/spec/lutaml/xml/schema/compiler_spec.rb +21 -4
- data/spec/lutaml/xml/schema/rnc_compiler_spec.rb +404 -0
- data/spec/lutaml/xml/schema/rng_compiler_spec.rb +893 -0
- data/spec/lutaml/xml/serializable_namespace_spec.rb +6 -6
- data/spec/lutaml/xml/type_namespace_examples_spec.rb +1 -1
- data/spec/lutaml/xml/type_namespace_integration_spec.rb +3 -3
- data/spec/lutaml/xml/validate_xml_with_constructs_spec.rb +222 -0
- data/spec/lutaml/xml/validate_xml_with_spec.rb +186 -0
- data/spec/lutaml/yamlld/adapter_spec.rb +56 -0
- data/spec/lutaml/yamlld/registration_spec.rb +33 -0
- data/spec/spec_helper.rb +28 -11
- data/spec/support/opal.rb +5 -2
- metadata +108 -37
- data/lib/lutaml/model/schema/xml_compiler/attribute.rb +0 -106
- data/lib/lutaml/model/schema/xml_compiler/attribute_group.rb +0 -47
- data/lib/lutaml/model/schema/xml_compiler/choice.rb +0 -67
- data/lib/lutaml/model/schema/xml_compiler/complex_content.rb +0 -27
- data/lib/lutaml/model/schema/xml_compiler/complex_content_restriction.rb +0 -34
- data/lib/lutaml/model/schema/xml_compiler/complex_type.rb +0 -173
- data/lib/lutaml/model/schema/xml_compiler/element.rb +0 -121
- data/lib/lutaml/model/schema/xml_compiler/group.rb +0 -113
- data/lib/lutaml/model/schema/xml_compiler/restriction.rb +0 -104
- data/lib/lutaml/model/schema/xml_compiler/sequence.rb +0 -52
- data/lib/lutaml/model/schema/xml_compiler/simple_content.rb +0 -40
- data/lib/lutaml/model/schema/xml_compiler/simple_type.rb +0 -265
- data/lib/lutaml/model/schema/xml_compiler/xml_namespace_class.rb +0 -110
- data/lib/lutaml/model/services/default_value_resolver.rb +0 -60
- data/spec/lutaml/model/services/default_value_resolver_spec.rb +0 -162
- data/spec/lutaml/xml/schema/compiler/attribute_group_spec.rb +0 -71
- data/spec/lutaml/xml/schema/compiler/attribute_spec.rb +0 -67
- data/spec/lutaml/xml/schema/compiler/choice_spec.rb +0 -74
- data/spec/lutaml/xml/schema/compiler/complex_content_restriction_spec.rb +0 -60
- data/spec/lutaml/xml/schema/compiler/complex_content_spec.rb +0 -41
- data/spec/lutaml/xml/schema/compiler/complex_type_spec.rb +0 -202
- data/spec/lutaml/xml/schema/compiler/element_spec.rb +0 -68
- data/spec/lutaml/xml/schema/compiler/group_spec.rb +0 -90
- data/spec/lutaml/xml/schema/compiler/restriction_spec.rb +0 -77
- data/spec/lutaml/xml/schema/compiler/sequence_spec.rb +0 -65
- data/spec/lutaml/xml/schema/compiler/simple_content_spec.rb +0 -61
- data/spec/lutaml/xml/schema/compiler/simple_type_spec.rb +0 -184
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
|
|
5
|
+
module UnionSpec
|
|
6
|
+
class WithUnit < Lutaml::Model::Serializable
|
|
7
|
+
attribute :number, :float
|
|
8
|
+
attribute :unit, :string
|
|
9
|
+
|
|
10
|
+
key_value do
|
|
11
|
+
map "number", to: :number
|
|
12
|
+
map "unit", to: :unit
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class Celsius < Lutaml::Model::Serializable
|
|
17
|
+
attribute :celsius, :float
|
|
18
|
+
|
|
19
|
+
key_value do
|
|
20
|
+
map "celsius", to: :celsius
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Member declaring an aliased key (two names for one attribute).
|
|
25
|
+
class AliasedName < Lutaml::Model::Serializable
|
|
26
|
+
attribute :name, :string
|
|
27
|
+
|
|
28
|
+
key_value do
|
|
29
|
+
map %w[name product_name], to: :name
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
RSpec.describe Lutaml::Model::Type::Union do
|
|
35
|
+
let(:int_str) do
|
|
36
|
+
[Lutaml::Model::Type::Integer, Lutaml::Model::Type::String]
|
|
37
|
+
end
|
|
38
|
+
let(:int_float) do
|
|
39
|
+
[Lutaml::Model::Type::Integer, Lutaml::Model::Type::Float]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def member_for(value, members, format: nil)
|
|
43
|
+
result = described_class.conforming_member(value, members,
|
|
44
|
+
format: format, register: nil)
|
|
45
|
+
result&.first
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
describe ".conforming_member (scalars)" do
|
|
49
|
+
it "matches Integer for an integer-lexical string" do
|
|
50
|
+
expect(member_for("42", int_str)).to eq(Lutaml::Model::Type::Integer)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it "falls through to String when Integer rejects" do
|
|
54
|
+
expect(member_for("hello", int_str)).to eq(Lutaml::Model::Type::String)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "rejects a float-string for Integer (sound predicate, not Integer('3.7'))" do
|
|
58
|
+
expect(member_for("3.7", int_float)).to eq(Lutaml::Model::Type::Float)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "accepts a numeric integer string for the Integer member first" do
|
|
62
|
+
expect(member_for("1300", int_float)).to eq(Lutaml::Model::Type::Integer)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
it "matches a native Integer value" do
|
|
66
|
+
expect(member_for(42, int_str)).to eq(Lutaml::Model::Type::Integer)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "matches a native Float value to the Float member" do
|
|
70
|
+
expect(member_for(3.7, int_float)).to eq(Lutaml::Model::Type::Float)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "returns nil when no scalar member conforms" do
|
|
74
|
+
expect(member_for("abc", int_float)).to be_nil
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
it "rejects an Integer that Float cannot represent exactly" do
|
|
78
|
+
expect(member_for((2**60) + 1, [Lutaml::Model::Type::Float])).to be_nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it "widens a Float-representable Integer into Float" do
|
|
82
|
+
member, casted = described_class.conforming_member(
|
|
83
|
+
2**60, [Lutaml::Model::Type::Float], format: nil, register: nil
|
|
84
|
+
)
|
|
85
|
+
expect([member, casted]).to eq([Lutaml::Model::Type::Float, (2**60).to_f])
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
it "casts the value to the matched member" do
|
|
89
|
+
member, casted = described_class.conforming_member(
|
|
90
|
+
"42", int_str, format: nil, register: nil
|
|
91
|
+
)
|
|
92
|
+
expect([member, casted]).to eq([Lutaml::Model::Type::Integer, 42])
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
describe ".conforming_member (boolean lexical space)" do
|
|
97
|
+
let(:bool_str) do
|
|
98
|
+
[Lutaml::Model::Type::Boolean, Lutaml::Model::Type::String]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "matches a true/false word to Boolean" do
|
|
102
|
+
expect(member_for("true", bool_str))
|
|
103
|
+
.to eq(Lutaml::Model::Type::Boolean)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "falls through to String for a non-boolean word" do
|
|
107
|
+
expect(member_for("maybe", bool_str))
|
|
108
|
+
.to eq(Lutaml::Model::Type::String)
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe ".conforming_member (models by key-coverage)" do
|
|
113
|
+
let(:members) { [UnionSpec::WithUnit, UnionSpec::Celsius] }
|
|
114
|
+
|
|
115
|
+
it "selects the model whose fields cover the input keys" do
|
|
116
|
+
member, = described_class.conforming_member(
|
|
117
|
+
{ "number" => 1300.0, "unit" => "C" }, members,
|
|
118
|
+
format: :yaml, register: nil
|
|
119
|
+
)
|
|
120
|
+
expect(member).to eq(UnionSpec::WithUnit)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
it "selects the disjoint-key model" do
|
|
124
|
+
member, = described_class.conforming_member(
|
|
125
|
+
{ "celsius" => 1200.0 }, members, format: :yaml, register: nil
|
|
126
|
+
)
|
|
127
|
+
expect(member).to eq(UnionSpec::Celsius)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
it "deserializes the selected model member" do
|
|
131
|
+
_, value = described_class.conforming_member(
|
|
132
|
+
{ "celsius" => 1200.0 }, members, format: :yaml, register: nil
|
|
133
|
+
)
|
|
134
|
+
expect(value).to be_a(UnionSpec::Celsius)
|
|
135
|
+
expect(value.celsius).to eq(1200.0)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it "returns nil when no model covers the keys" do
|
|
139
|
+
result = described_class.conforming_member(
|
|
140
|
+
{ "unknown" => 1 }, members, format: :yaml, register: nil
|
|
141
|
+
)
|
|
142
|
+
expect(result).to be_nil
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
it "selects a member matched through an aliased key" do
|
|
146
|
+
member, value = described_class.conforming_member(
|
|
147
|
+
{ "product_name" => "Vase" }, [UnionSpec::AliasedName],
|
|
148
|
+
format: :yaml, register: nil
|
|
149
|
+
)
|
|
150
|
+
expect(member).to eq(UnionSpec::AliasedName)
|
|
151
|
+
expect(value.name).to eq("Vase")
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
it "returns an existing member instance unchanged (idempotent)" do
|
|
155
|
+
instance = UnionSpec::Celsius.new(celsius: 1200.0)
|
|
156
|
+
member, value = described_class.conforming_member(
|
|
157
|
+
instance, members, format: :yaml, register: nil
|
|
158
|
+
)
|
|
159
|
+
expect(member).to eq(UnionSpec::Celsius)
|
|
160
|
+
expect(value).to be(instance)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
describe "nil passthrough" do
|
|
165
|
+
it "returns nil for nil input" do
|
|
166
|
+
expect(member_for(nil, int_str)).to be_nil
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
describe ".validate_members!" do
|
|
171
|
+
it "raises on an empty member list" do
|
|
172
|
+
expect { described_class.validate_members!([]) }
|
|
173
|
+
.to raise_error(ArgumentError)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
it "raises when a member is not a valid type" do
|
|
177
|
+
expect { described_class.validate_members!([Object]) }
|
|
178
|
+
.to raise_error(ArgumentError)
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it "raises when a catch-all is not last" do
|
|
182
|
+
expect do
|
|
183
|
+
described_class.validate_members!(
|
|
184
|
+
[Lutaml::Model::Type::String, Lutaml::Model::Type::Integer],
|
|
185
|
+
)
|
|
186
|
+
end.to raise_error(ArgumentError)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it "accepts a valid ordered member list" do
|
|
190
|
+
expect do
|
|
191
|
+
described_class.validate_members!(
|
|
192
|
+
[Lutaml::Model::Type::Integer, Lutaml::Model::Type::String],
|
|
193
|
+
)
|
|
194
|
+
end.not_to raise_error
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
describe ".validate_combo!" do
|
|
199
|
+
it "raises when combined with polymorphic" do
|
|
200
|
+
expect { described_class.validate_combo!(polymorphic: {}) }
|
|
201
|
+
.to raise_error(ArgumentError)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
it "raises when combined with raw" do
|
|
205
|
+
expect { described_class.validate_combo!(raw: true) }
|
|
206
|
+
.to raise_error(ArgumentError)
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
it "accepts a plain options hash" do
|
|
210
|
+
expect { described_class.validate_combo!(collection: true) }
|
|
211
|
+
.not_to raise_error
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
describe "schema export" do
|
|
216
|
+
let(:klass) do
|
|
217
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
218
|
+
attribute :v,
|
|
219
|
+
[Lutaml::Model::Type::Integer, Lutaml::Model::Type::String]
|
|
220
|
+
xml do
|
|
221
|
+
element "union_schema_sample"
|
|
222
|
+
map_element "v", to: :v
|
|
223
|
+
end
|
|
224
|
+
key_value { map "v", to: :v }
|
|
225
|
+
|
|
226
|
+
def self.name
|
|
227
|
+
"UnionSchemaSample"
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
it "emits anyOf for JSON Schema (valid if at least one member matches)" do
|
|
233
|
+
schema = JSON.parse(Lutaml::Model::Schema::JsonSchema.generate(klass))
|
|
234
|
+
defs = schema["$defs"] || schema["definitions"] || {}
|
|
235
|
+
property = defs.dig("UnionSchemaSample", "properties", "v") ||
|
|
236
|
+
schema.dig("properties", "v")
|
|
237
|
+
|
|
238
|
+
expect(property).to eq(
|
|
239
|
+
"anyOf" => [
|
|
240
|
+
{ "type" => "integer" },
|
|
241
|
+
{ "type" => "string" },
|
|
242
|
+
{ "type" => "null" },
|
|
243
|
+
],
|
|
244
|
+
)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
it "raises UnionSchemaUnsupportedError for XSD" do
|
|
248
|
+
expect { Lutaml::Xml::Schema::XsdSchema.generate(klass) }
|
|
249
|
+
.to raise_error(Lutaml::Model::UnionSchemaUnsupportedError)
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
it "raises UnionSchemaUnsupportedError for RelaxNG" do
|
|
253
|
+
expect { Lutaml::Xml::Schema::RelaxngSchema.generate(klass) }
|
|
254
|
+
.to raise_error(Lutaml::Model::UnionSchemaUnsupportedError)
|
|
255
|
+
end
|
|
256
|
+
end
|
|
257
|
+
end
|
|
@@ -56,6 +56,20 @@ RSpec.describe Lutaml::Model::Utils do
|
|
|
56
56
|
it_behaves_like "string conversion", :snake_case, SNAKE_CASE_EXAMPLES
|
|
57
57
|
it_behaves_like "string conversion", :pluralize, PLURALIZE_EXAMPLES
|
|
58
58
|
|
|
59
|
+
describe ".last_of_split" do
|
|
60
|
+
it "returns the segment after the colon" do
|
|
61
|
+
expect(utils.last_of_split("foo:Bar")).to eq("Bar")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "returns the input unchanged when there is no colon" do
|
|
65
|
+
expect(utils.last_of_split("Bar")).to eq("Bar")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "returns nil for nil input" do
|
|
69
|
+
expect(utils.last_of_split(nil)).to be_nil
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
59
73
|
describe ".deep_dup" do
|
|
60
74
|
let(:original_hash) do
|
|
61
75
|
{
|
|
@@ -85,7 +85,7 @@ RSpec.describe "XSD Form Default Patterns" do
|
|
|
85
85
|
xml = instance.to_xml
|
|
86
86
|
|
|
87
87
|
# The element should be unqualified (no prefix) in instance
|
|
88
|
-
expect(xml).to
|
|
88
|
+
expect(xml).to include("<premium")
|
|
89
89
|
expect(xml).to include("<elementFormUnqualified")
|
|
90
90
|
end
|
|
91
91
|
end
|
|
@@ -281,7 +281,7 @@ RSpec.describe "XSD Form Default Patterns" do
|
|
|
281
281
|
# and the namespace is already declared on an ancestor
|
|
282
282
|
# The child element should be in the blank namespace without xmlns="" declaration
|
|
283
283
|
# because the parent uses prefix format (xmlns:ex) or the namespace is already declared.
|
|
284
|
-
expect(result).not_to
|
|
284
|
+
expect(result).not_to include('xmlns=""')
|
|
285
285
|
end
|
|
286
286
|
|
|
287
287
|
it "serializes root element with namespace declaration" do
|
|
@@ -43,7 +43,7 @@ RSpec.describe "XSD Three Pattern Architecture" do
|
|
|
43
43
|
|
|
44
44
|
expect(xsd).to include('<element name="item">')
|
|
45
45
|
expect(xsd).to include("<complexType>")
|
|
46
|
-
expect(xsd).not_to
|
|
46
|
+
expect(xsd).not_to include("<complexType name=")
|
|
47
47
|
expect(xsd).to include('<attribute name="id" type="xs:string"/>')
|
|
48
48
|
end
|
|
49
49
|
end
|
|
@@ -68,7 +68,7 @@ RSpec.describe "XSD Three Pattern Architecture" do
|
|
|
68
68
|
expect(xsd).to include('<element name="name" type="xs:string"/>')
|
|
69
69
|
expect(xsd).to include('<element name="value" type="xs:integer"/>')
|
|
70
70
|
# Should NOT generate standalone element declaration
|
|
71
|
-
expect(xsd).not_to
|
|
71
|
+
expect(xsd).not_to include('<element name="product"')
|
|
72
72
|
end
|
|
73
73
|
|
|
74
74
|
it "type-only model can be referenced by other elements" do
|
|
@@ -233,7 +233,7 @@ RSpec.describe "XSD Three Pattern Architecture" do
|
|
|
233
233
|
|
|
234
234
|
xsd = Lutaml::Model::Schema.to_xsd(klass)
|
|
235
235
|
expect(xsd).to include('<element name="simple">')
|
|
236
|
-
expect(xsd).not_to
|
|
236
|
+
expect(xsd).not_to include('<element name="simple" type=')
|
|
237
237
|
end
|
|
238
238
|
|
|
239
239
|
it "Pattern 2: type_name only -> named reusable" do
|
|
@@ -252,7 +252,7 @@ RSpec.describe "XSD Three Pattern Architecture" do
|
|
|
252
252
|
xsd = Lutaml::Model::Schema.to_xsd(klass)
|
|
253
253
|
expect(xsd).to include('<complexType name="SimpleType">')
|
|
254
254
|
# Should not have standalone element declaration (only child elements in sequence are OK)
|
|
255
|
-
expect(xsd).not_to
|
|
255
|
+
expect(xsd).not_to include('<element name="SimpleType"')
|
|
256
256
|
end
|
|
257
257
|
|
|
258
258
|
it "Pattern 3: both -> element with named type" do
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
|
-
require "lutaml/
|
|
4
|
+
require "lutaml/rdf"
|
|
5
5
|
|
|
6
|
-
RSpec.describe Lutaml::
|
|
6
|
+
RSpec.describe Lutaml::Rdf::Context do
|
|
7
7
|
subject(:ctx) { described_class.new }
|
|
8
8
|
|
|
9
9
|
describe "empty context" do
|
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
4
|
require "lutaml/jsonld"
|
|
5
|
+
require "lutaml/yamlld"
|
|
5
6
|
|
|
6
|
-
RSpec.describe Lutaml::
|
|
7
|
+
RSpec.describe Lutaml::Rdf::LinkedDataTransform do
|
|
7
8
|
before do
|
|
8
9
|
stub_const("TestSkosNs", Class.new(Lutaml::Rdf::Namespace) do
|
|
9
10
|
uri "http://www.w3.org/2004/02/skos/core#"
|
|
@@ -138,6 +139,19 @@ RSpec.describe Lutaml::JsonLd::Transform do
|
|
|
138
139
|
expect(parsed["@context"]["skos"]).to eq("http://www.w3.org/2004/02/skos/core#")
|
|
139
140
|
expect(parsed["@context"]["ex"]).to eq("http://example.org/")
|
|
140
141
|
end
|
|
142
|
+
|
|
143
|
+
it "preserves data through model → YAML-LD → model" do
|
|
144
|
+
yaml = instance.to_yamlld
|
|
145
|
+
restored = JsonLdTestModel.from_yamlld(yaml)
|
|
146
|
+
expect(restored.name).to eq("test")
|
|
147
|
+
expect(restored.description).to eq("A test concept")
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "produces the same data model from YAML-LD as JSON-LD" do
|
|
151
|
+
from_yamlld = YAML.safe_load(instance.to_yamlld)
|
|
152
|
+
from_jsonld = JSON.parse(instance.to_jsonld)
|
|
153
|
+
expect(from_yamlld).to eq(from_jsonld)
|
|
154
|
+
end
|
|
141
155
|
end
|
|
142
156
|
|
|
143
157
|
describe "nil attribute values" do
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
|
-
require "lutaml/
|
|
4
|
+
require "lutaml/rdf"
|
|
5
5
|
|
|
6
|
-
RSpec.describe Lutaml::
|
|
6
|
+
RSpec.describe Lutaml::Rdf::TermDefinition do
|
|
7
7
|
it "simple term maps to name => id" do
|
|
8
8
|
td = described_class.new(name: "name", id: "http://example.org/name")
|
|
9
9
|
expect(td.to_context_hash).to eq("name" => "http://example.org/name")
|
|
@@ -119,13 +119,13 @@ RSpec.describe Lutaml::Turtle::Transform do
|
|
|
119
119
|
it "serializes integers as native Turtle literals" do
|
|
120
120
|
instance = TypedModel.new(label: "test", count: 42, active: true)
|
|
121
121
|
result = instance.to_turtle
|
|
122
|
-
expect(result).to
|
|
122
|
+
expect(result).to include("skos:notation 42")
|
|
123
123
|
end
|
|
124
124
|
|
|
125
125
|
it "serializes booleans as native Turtle literals" do
|
|
126
126
|
instance = TypedModel.new(label: "test", count: 1, active: true)
|
|
127
127
|
result = instance.to_turtle
|
|
128
|
-
expect(result).to
|
|
128
|
+
expect(result).to include("skos:note true")
|
|
129
129
|
end
|
|
130
130
|
end
|
|
131
131
|
|
|
@@ -187,6 +187,235 @@ RSpec.describe "Enhanced XML Mapping Features" do
|
|
|
187
187
|
expect(name_rule.form).to eq(:unqualified)
|
|
188
188
|
end
|
|
189
189
|
end
|
|
190
|
+
|
|
191
|
+
context "with Serializable child and form: :qualified" do
|
|
192
|
+
# Regression: form option on the parent's map_element rule must be
|
|
193
|
+
# propagated to the child XmlElement when the child is a Serializable
|
|
194
|
+
# (which goes through create_transformed_nested_element). Otherwise the
|
|
195
|
+
# ElementFormOptionRule cannot fire and the element is serialized
|
|
196
|
+
# without the namespace prefix.
|
|
197
|
+
let(:child_class) do
|
|
198
|
+
ns = namespace_class
|
|
199
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
200
|
+
attribute :label, :string
|
|
201
|
+
|
|
202
|
+
xml do
|
|
203
|
+
element "child"
|
|
204
|
+
namespace ns
|
|
205
|
+
map_element "label", to: :label
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
let(:model_class) do
|
|
211
|
+
ns = namespace_class
|
|
212
|
+
child = child_class
|
|
213
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
214
|
+
attribute :child, child
|
|
215
|
+
|
|
216
|
+
xml do
|
|
217
|
+
element "item"
|
|
218
|
+
namespace ns
|
|
219
|
+
map_element "child", to: :child, form: :qualified
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
it "stores form: :qualified on the parent rule" do
|
|
225
|
+
mapping = model_class.mappings_for(:xml)
|
|
226
|
+
child_rule = mapping.find_element(:child)
|
|
227
|
+
expect(child_rule.form).to eq(:qualified)
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
it "serializes the nested Serializable with a namespace prefix" do
|
|
231
|
+
instance = model_class.new(child: child_class.new(label: "x"))
|
|
232
|
+
doc = Nokogiri::XML(instance.to_xml)
|
|
233
|
+
qualified = doc.at_xpath("//*[name()='ex:child']")
|
|
234
|
+
expect(qualified).not_to be_nil
|
|
235
|
+
expect(qualified.at_xpath("./xmlns:label").text).to eq("x")
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it "round-trips the qualified Serializable child" do
|
|
239
|
+
original = model_class.new(child: child_class.new(label: "round-trip"))
|
|
240
|
+
restored = model_class.from_xml(original.to_xml)
|
|
241
|
+
expect(restored.child.label).to eq("round-trip")
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
context "with Serializable child and form: :unqualified" do
|
|
246
|
+
# Symmetric to the :qualified case: form: :unqualified must propagate
|
|
247
|
+
# to the child XmlElement so ElementFormOptionRule can force the
|
|
248
|
+
# default (unprefixed) form.
|
|
249
|
+
let(:child_class) do
|
|
250
|
+
ns = namespace_class
|
|
251
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
252
|
+
attribute :label, :string
|
|
253
|
+
|
|
254
|
+
xml do
|
|
255
|
+
element "child"
|
|
256
|
+
namespace ns
|
|
257
|
+
map_element "label", to: :label
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
let(:model_class) do
|
|
263
|
+
ns = namespace_class
|
|
264
|
+
child = child_class
|
|
265
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
266
|
+
attribute :child, child
|
|
267
|
+
|
|
268
|
+
xml do
|
|
269
|
+
element "item"
|
|
270
|
+
namespace ns
|
|
271
|
+
map_element "child", to: :child, form: :unqualified
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
it "propagates form: :unqualified and emits an unprefixed child" do
|
|
277
|
+
instance = model_class.new(child: child_class.new(label: "x"))
|
|
278
|
+
doc = Nokogiri::XML(instance.to_xml)
|
|
279
|
+
expect(doc.xpath("//*[name()='ex:child']")).to be_empty
|
|
280
|
+
expect(doc.at_xpath("//*[local-name()='child']")).not_to be_nil
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
context "with a collection of Serializable children" do
|
|
285
|
+
# The form option must propagate to every element produced for a
|
|
286
|
+
# collection attribute, not just the first.
|
|
287
|
+
let(:child_class) do
|
|
288
|
+
ns = namespace_class
|
|
289
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
290
|
+
attribute :label, :string
|
|
291
|
+
|
|
292
|
+
xml do
|
|
293
|
+
element "child"
|
|
294
|
+
namespace ns
|
|
295
|
+
map_element "label", to: :label
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
let(:model_class) do
|
|
301
|
+
ns = namespace_class
|
|
302
|
+
child = child_class
|
|
303
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
304
|
+
attribute :children, child, collection: true
|
|
305
|
+
|
|
306
|
+
xml do
|
|
307
|
+
element "item"
|
|
308
|
+
namespace ns
|
|
309
|
+
map_element "child", to: :children, form: :qualified
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
it "qualifies every child in the collection" do
|
|
315
|
+
instance = model_class.new(
|
|
316
|
+
children: [child_class.new(label: "a"), child_class.new(label: "b")],
|
|
317
|
+
)
|
|
318
|
+
doc = Nokogiri::XML(instance.to_xml)
|
|
319
|
+
qualified = doc.xpath("//*[name()='ex:child']")
|
|
320
|
+
labels = qualified.map { |c| c.at_xpath("./xmlns:label").text }
|
|
321
|
+
expect(labels).to contain_exactly("a", "b")
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
context "with a Serializable child containing a Serializable grandchild" do
|
|
326
|
+
# form: :qualified is a per-rule override; it must NOT propagate
|
|
327
|
+
# transitively to grandchildren. Each level applies its own rule and
|
|
328
|
+
# its own parent_element_form_default.
|
|
329
|
+
let(:grandchild_class) do
|
|
330
|
+
ns = namespace_class
|
|
331
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
332
|
+
attribute :value, :string
|
|
333
|
+
|
|
334
|
+
xml do
|
|
335
|
+
element "grandchild"
|
|
336
|
+
namespace ns
|
|
337
|
+
map_element "value", to: :value
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
let(:child_class) do
|
|
343
|
+
ns = namespace_class
|
|
344
|
+
grandchild = grandchild_class
|
|
345
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
346
|
+
attribute :inner, grandchild
|
|
347
|
+
|
|
348
|
+
xml do
|
|
349
|
+
element "child"
|
|
350
|
+
namespace ns
|
|
351
|
+
map_element "grandchild", to: :inner
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
let(:model_class) do
|
|
357
|
+
ns = namespace_class
|
|
358
|
+
child = child_class
|
|
359
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
360
|
+
attribute :child, child
|
|
361
|
+
|
|
362
|
+
xml do
|
|
363
|
+
element "item"
|
|
364
|
+
namespace ns
|
|
365
|
+
map_element "child", to: :child, form: :qualified
|
|
366
|
+
end
|
|
367
|
+
end
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
it "qualifies the child but leaves the grandchild unprefixed" do
|
|
371
|
+
instance = model_class.new(
|
|
372
|
+
child: child_class.new(inner: grandchild_class.new(value: "x")),
|
|
373
|
+
)
|
|
374
|
+
doc = Nokogiri::XML(instance.to_xml)
|
|
375
|
+
expect(doc.at_xpath("//*[name()='ex:child']")).not_to be_nil
|
|
376
|
+
expect(doc.xpath("//*[name()='ex:grandchild']")).to be_empty
|
|
377
|
+
expect(doc.at_xpath("//*[local-name()='grandchild']")).not_to be_nil
|
|
378
|
+
end
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
context "with Serializable child but no form override" do
|
|
382
|
+
# Sanity: when no form: :qualified is set on the rule, the W3C
|
|
383
|
+
# element_form_default :unqualified override should still kick in and
|
|
384
|
+
# the nested Serializable should serialize unprefixed.
|
|
385
|
+
let(:child_class) do
|
|
386
|
+
ns = namespace_class
|
|
387
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
388
|
+
attribute :label, :string
|
|
389
|
+
|
|
390
|
+
xml do
|
|
391
|
+
element "child"
|
|
392
|
+
namespace ns
|
|
393
|
+
map_element "label", to: :label
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
let(:model_class) do
|
|
399
|
+
ns = namespace_class
|
|
400
|
+
child = child_class
|
|
401
|
+
Class.new(Lutaml::Model::Serializable) do
|
|
402
|
+
attribute :child, child
|
|
403
|
+
|
|
404
|
+
xml do
|
|
405
|
+
element "item"
|
|
406
|
+
namespace ns
|
|
407
|
+
map_element "child", to: :child
|
|
408
|
+
end
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
it "honors element_form_default :unqualified by leaving the child unprefixed" do
|
|
413
|
+
instance = model_class.new(child: child_class.new(label: "x"))
|
|
414
|
+
doc = Nokogiri::XML(instance.to_xml)
|
|
415
|
+
expect(doc.xpath("//*[name()='ex:child']")).to be_empty
|
|
416
|
+
expect(doc.at_xpath("//*[local-name()='child']")).not_to be_nil
|
|
417
|
+
end
|
|
418
|
+
end
|
|
190
419
|
end
|
|
191
420
|
|
|
192
421
|
describe "form option on map_attribute" do
|
|
@@ -222,7 +451,7 @@ RSpec.describe "Enhanced XML Mapping Features" do
|
|
|
222
451
|
instance = model_class.new(id: "ABC123")
|
|
223
452
|
xml = instance.to_xml
|
|
224
453
|
# Form affects qualification but implementation varies by adapter
|
|
225
|
-
expect(xml).to
|
|
454
|
+
expect(xml).to include('id="ABC123"')
|
|
226
455
|
end
|
|
227
456
|
end
|
|
228
457
|
|
|
@@ -86,16 +86,16 @@ module XmlMappingSpec
|
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
class Address < Lutaml::Model::Serializable
|
|
89
|
-
attribute :street, ::Lutaml::Model::Type::String
|
|
90
|
-
attribute :city, :string
|
|
89
|
+
attribute :street, ::Lutaml::Model::Type::String
|
|
90
|
+
attribute :city, :string
|
|
91
91
|
attribute :text, :string
|
|
92
92
|
attribute :address, Address
|
|
93
93
|
|
|
94
94
|
xml do
|
|
95
95
|
element "address"
|
|
96
96
|
|
|
97
|
-
map_element "street", to: :street
|
|
98
|
-
map_element "city", to: :city
|
|
97
|
+
map_element "street", to: :street, raw: :content
|
|
98
|
+
map_element "city", to: :city, raw: :content
|
|
99
99
|
map_element "text", to: :text
|
|
100
100
|
end
|
|
101
101
|
end
|