lutaml-model 0.8.17 → 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.
Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/downstream-performance.yml +27 -1
  3. data/.github/workflows/js-pr-check.yml +102 -0
  4. data/.github/workflows/js-sync.yml +51 -0
  5. data/.github/workflows/opal.yml +26 -6
  6. data/.github/workflows/performance.yml +32 -7
  7. data/.github/workflows/rake.yml +78 -32
  8. data/.gitmodules +6 -0
  9. data/.rubocop_todo.yml +8 -0
  10. data/Gemfile +16 -1
  11. data/README.adoc +267 -0
  12. data/Rakefile +166 -4
  13. data/docs/_guides/schema-import.adoc +42 -0
  14. data/docs/_guides/xml-mapping.adoc +21 -0
  15. data/docs/_pages/validation.adoc +65 -0
  16. data/lib/compat/opal/generate_boot.rb +123 -0
  17. data/lib/compat/opal/js_bundle_entry.rb +42 -0
  18. data/lib/compat/opal/lutaml_model_boot.rb +497 -0
  19. data/lib/compat/opal/moxml_boot.rb +68 -0
  20. data/lib/compat/opal/yaml_compat.rb +32 -0
  21. data/lib/lutaml/json.rb +1 -1
  22. data/lib/lutaml/key_value/transform.rb +3 -8
  23. data/lib/lutaml/key_value/transformation/value_serializer.rb +14 -1
  24. data/lib/lutaml/key_value/transformation.rb +17 -5
  25. data/lib/lutaml/model/adapter_resolver.rb +2 -2
  26. data/lib/lutaml/model/attribute.rb +88 -11
  27. data/lib/lutaml/model/cached_type_resolver.rb +1 -1
  28. data/lib/lutaml/model/error/union_schema_unsupported_error.rb +11 -0
  29. data/lib/lutaml/model/global_context.rb +11 -8
  30. data/lib/lutaml/model/instrumentation.rb +2 -2
  31. data/lib/lutaml/model/mapping/mapping_rule.rb +0 -6
  32. data/lib/lutaml/model/register.rb +2 -2
  33. data/lib/lutaml/model/runtime_compatibility.rb +50 -0
  34. data/lib/lutaml/model/schema/class_loader.rb +58 -0
  35. data/lib/lutaml/model/schema/compiled_output.rb +83 -0
  36. data/lib/lutaml/model/schema/definitions/attribute.rb +32 -0
  37. data/lib/lutaml/model/schema/definitions/choice.rb +20 -0
  38. data/lib/lutaml/model/schema/definitions/facet.rb +40 -0
  39. data/lib/lutaml/model/schema/definitions/group_import.rb +22 -0
  40. data/lib/lutaml/model/schema/definitions/member_walk.rb +33 -0
  41. data/lib/lutaml/model/schema/definitions/model.rb +40 -0
  42. data/lib/lutaml/model/schema/definitions/namespace.rb +23 -0
  43. data/lib/lutaml/model/schema/definitions/restricted_type.rb +30 -0
  44. data/lib/lutaml/model/schema/definitions/sequence.rb +19 -0
  45. data/lib/lutaml/model/schema/definitions/simple_content.rb +22 -0
  46. data/lib/lutaml/model/schema/definitions/transform_facet.rb +21 -0
  47. data/lib/lutaml/model/schema/definitions/type_ref.rb +20 -0
  48. data/lib/lutaml/model/schema/definitions/union_type.rb +28 -0
  49. data/lib/lutaml/model/schema/definitions/xml_root.rb +20 -0
  50. data/lib/lutaml/model/schema/definitions.rb +24 -0
  51. data/lib/lutaml/model/schema/file_writer.rb +70 -0
  52. data/lib/lutaml/model/schema/generator/definitions_collection.rb +16 -2
  53. data/lib/lutaml/model/schema/generator/property.rb +21 -4
  54. data/lib/lutaml/model/schema/module_nesting.rb +31 -0
  55. data/lib/lutaml/model/schema/namespace_naming.rb +46 -0
  56. data/lib/lutaml/model/schema/registry_generator.rb +115 -0
  57. data/lib/lutaml/model/schema/renderers/base.rb +40 -0
  58. data/lib/lutaml/model/schema/renderers/mappings.rb +72 -0
  59. data/lib/lutaml/model/schema/renderers/member_decls.rb +115 -0
  60. data/lib/lutaml/model/schema/renderers/model.rb +121 -0
  61. data/lib/lutaml/model/schema/renderers/namespace.rb +30 -0
  62. data/lib/lutaml/model/schema/renderers/registration.rb +64 -0
  63. data/lib/lutaml/model/schema/renderers/required_files_calculator.rb +93 -0
  64. data/lib/lutaml/model/schema/renderers/restricted_type.rb +88 -0
  65. data/lib/lutaml/model/schema/renderers/union.rb +83 -0
  66. data/lib/lutaml/model/schema/renderers.rb +19 -0
  67. data/lib/lutaml/model/schema/rnc_compiler/source_resolver.rb +47 -0
  68. data/lib/lutaml/model/schema/rnc_compiler.rb +62 -0
  69. data/lib/lutaml/model/schema/rng_compiler/define_classifier.rb +91 -0
  70. data/lib/lutaml/model/schema/rng_compiler/element_visitor.rb +392 -0
  71. data/lib/lutaml/model/schema/rng_compiler/member_collector.rb +30 -0
  72. data/lib/lutaml/model/schema/rng_compiler/rng_helpers.rb +152 -0
  73. data/lib/lutaml/model/schema/rng_compiler/value_type_resolver.rb +125 -0
  74. data/lib/lutaml/model/schema/rng_compiler.rb +220 -0
  75. data/lib/lutaml/model/schema/templates.rb +162 -0
  76. data/lib/lutaml/model/schema/xml_compiler/element_order.rb +41 -0
  77. data/lib/lutaml/model/schema/xml_compiler/registry_generator.rb +31 -107
  78. data/lib/lutaml/model/schema/xml_compiler/spec_builder/complex_types.rb +191 -0
  79. data/lib/lutaml/model/schema/xml_compiler/spec_builder/members.rb +216 -0
  80. data/lib/lutaml/model/schema/xml_compiler/spec_builder/simple_types.rb +153 -0
  81. data/lib/lutaml/model/schema/xml_compiler/spec_builder.rb +167 -0
  82. data/lib/lutaml/model/schema/xml_compiler/supported_data_types.rb +87 -0
  83. data/lib/lutaml/model/schema/xml_compiler.rb +38 -517
  84. data/lib/lutaml/model/schema.rb +19 -0
  85. data/lib/lutaml/model/serialize/attribute_definition.rb +14 -2
  86. data/lib/lutaml/model/serialize/builder.rb +15 -2
  87. data/lib/lutaml/model/serialize/value_mapping.rb +9 -57
  88. data/lib/lutaml/model/serialize.rb +6 -9
  89. data/lib/lutaml/model/services/rule_value_extractor.rb +2 -3
  90. data/lib/lutaml/model/services.rb +0 -2
  91. data/lib/lutaml/model/store.rb +2 -1
  92. data/lib/lutaml/model/toml.rb +1 -1
  93. data/lib/lutaml/model/transform.rb +17 -39
  94. data/lib/lutaml/model/transformation_registry.rb +1 -1
  95. data/lib/lutaml/model/type.rb +1 -0
  96. data/lib/lutaml/model/union.rb +320 -0
  97. data/lib/lutaml/model/utils.rb +6 -0
  98. data/lib/lutaml/model/validation.rb +1 -4
  99. data/lib/lutaml/model/version.rb +1 -1
  100. data/lib/lutaml/model.rb +18 -0
  101. data/lib/lutaml/toml.rb +1 -1
  102. data/lib/lutaml/xml/adapter.rb +1 -1
  103. data/lib/lutaml/xml/adapter_loader.rb +1 -1
  104. data/lib/lutaml/xml/builder/base.rb +1 -1
  105. data/lib/lutaml/xml/builder.rb +1 -1
  106. data/lib/lutaml/xml/error/schema_validation_error.rb +25 -0
  107. data/lib/lutaml/xml/model_transform.rb +5 -1
  108. data/lib/lutaml/xml/schema/relaxng_schema.rb +5 -0
  109. data/lib/lutaml/xml/schema/xsd_schema.rb +4 -0
  110. data/lib/lutaml/xml/serialization/format_conversion.rb +48 -0
  111. data/lib/lutaml/xml/serialization/instance_methods.rb +13 -0
  112. data/lib/lutaml/xml/transformation/element_builder.rb +21 -8
  113. data/lib/lutaml/xml/transformation/ordered_applier.rb +6 -0
  114. data/lib/lutaml/xml/xsd_validator.rb +66 -0
  115. data/lib/lutaml/xml.rb +53 -12
  116. data/lutaml-model.gemspec +4 -2
  117. data/spec/fixtures/xml/schema/rnc/address_book.rnc +15 -0
  118. data/spec/fixtures/xml/schema/rnc/book_features.rnc +18 -0
  119. data/spec/fixtures/xml/schema/rnc/includes/book.rnc +6 -0
  120. data/spec/fixtures/xml/schema/rnc/includes/circular_a.rnc +8 -0
  121. data/spec/fixtures/xml/schema/rnc/includes/circular_b.rnc +8 -0
  122. data/spec/fixtures/xml/schema/rnc/includes/library.rnc +8 -0
  123. data/spec/fixtures/xml/schema/rng/address_book.rng +16 -0
  124. data/spec/fixtures/xml/schema/rng/book.rng +27 -0
  125. data/spec/fixtures/xml/schema/rng/fixed_value.rng +11 -0
  126. data/spec/fixtures/xml/schema/rng/fragment_in_choice.rng +30 -0
  127. data/spec/fixtures/xml/schema/rng/full_name.rng +39 -0
  128. data/spec/fixtures/xml/schema/rng/integer_range.rng +32 -0
  129. data/spec/fixtures/xml/schema/rng/list_type.rng +12 -0
  130. data/spec/fixtures/xml/schema/rng/namespaced.rng +9 -0
  131. data/spec/fixtures/xml/schema/rng/paragraph.rng +13 -0
  132. data/spec/fixtures/xml/schema/rng/person.rng +23 -0
  133. data/spec/fixtures/xml/schema/rng/union.rng +14 -0
  134. data/spec/fixtures/xml/validate_xml_with_address.xsd +13 -0
  135. data/spec/fixtures/xml/validate_xml_with_contact.xsd +11 -0
  136. data/spec/fixtures/xml/validate_xml_with_person.xsd +11 -0
  137. data/spec/fixtures/xml/validate_xml_with_person_strict.xsd +17 -0
  138. data/spec/fixtures/xml/validate_xml_with_product.xsd +37 -0
  139. data/spec/lutaml/model/attribute_apply_value_map_spec.rb +134 -0
  140. data/spec/lutaml/model/attribute_spec.rb +169 -12
  141. data/spec/lutaml/model/boot_manifest_spec.rb +30 -0
  142. data/spec/lutaml/model/collection_spec.rb +18 -0
  143. data/spec/lutaml/model/mixed_content_spec.rb +171 -0
  144. data/spec/lutaml/model/opal_smoke_spec.rb +67 -2
  145. data/spec/lutaml/model/ordered_content_spec.rb +30 -0
  146. data/spec/lutaml/model/raw_element_spec.rb +125 -0
  147. data/spec/lutaml/model/rule_value_extractor_spec.rb +7 -14
  148. data/spec/lutaml/model/runtime_compatibility_spec.rb +25 -0
  149. data/spec/lutaml/model/schema/renderers/model_spec.rb +149 -0
  150. data/spec/lutaml/model/schema/renderers/namespace_spec.rb +36 -0
  151. data/spec/lutaml/model/schema/renderers/restricted_type_spec.rb +75 -0
  152. data/spec/lutaml/model/schema/renderers/union_spec.rb +58 -0
  153. data/spec/lutaml/model/transform_apply_value_map_spec.rb +64 -0
  154. data/spec/lutaml/model/union_attribute_spec.rb +658 -0
  155. data/spec/lutaml/model/union_spec.rb +257 -0
  156. data/spec/lutaml/model/utils_spec.rb +14 -0
  157. data/spec/lutaml/xml/opal_xml_spec.rb +22 -20
  158. data/spec/lutaml/xml/schema/compiler_spec.rb +21 -4
  159. data/spec/lutaml/xml/schema/rnc_compiler_spec.rb +404 -0
  160. data/spec/lutaml/xml/schema/rng_compiler_spec.rb +893 -0
  161. data/spec/lutaml/xml/validate_xml_with_constructs_spec.rb +222 -0
  162. data/spec/lutaml/xml/validate_xml_with_spec.rb +186 -0
  163. data/spec/spec_helper.rb +28 -11
  164. data/spec/support/opal.rb +5 -2
  165. metadata +97 -31
  166. data/lib/lutaml/model/schema/xml_compiler/attribute.rb +0 -106
  167. data/lib/lutaml/model/schema/xml_compiler/attribute_group.rb +0 -47
  168. data/lib/lutaml/model/schema/xml_compiler/choice.rb +0 -67
  169. data/lib/lutaml/model/schema/xml_compiler/complex_content.rb +0 -27
  170. data/lib/lutaml/model/schema/xml_compiler/complex_content_restriction.rb +0 -34
  171. data/lib/lutaml/model/schema/xml_compiler/complex_type.rb +0 -173
  172. data/lib/lutaml/model/schema/xml_compiler/element.rb +0 -121
  173. data/lib/lutaml/model/schema/xml_compiler/group.rb +0 -113
  174. data/lib/lutaml/model/schema/xml_compiler/restriction.rb +0 -104
  175. data/lib/lutaml/model/schema/xml_compiler/sequence.rb +0 -52
  176. data/lib/lutaml/model/schema/xml_compiler/simple_content.rb +0 -40
  177. data/lib/lutaml/model/schema/xml_compiler/simple_type.rb +0 -265
  178. data/lib/lutaml/model/schema/xml_compiler/xml_namespace_class.rb +0 -110
  179. data/lib/lutaml/model/services/default_value_resolver.rb +0 -60
  180. data/spec/lutaml/model/services/default_value_resolver_spec.rb +0 -162
  181. data/spec/lutaml/xml/schema/compiler/attribute_group_spec.rb +0 -71
  182. data/spec/lutaml/xml/schema/compiler/attribute_spec.rb +0 -67
  183. data/spec/lutaml/xml/schema/compiler/choice_spec.rb +0 -74
  184. data/spec/lutaml/xml/schema/compiler/complex_content_restriction_spec.rb +0 -60
  185. data/spec/lutaml/xml/schema/compiler/complex_content_spec.rb +0 -41
  186. data/spec/lutaml/xml/schema/compiler/complex_type_spec.rb +0 -202
  187. data/spec/lutaml/xml/schema/compiler/element_spec.rb +0 -68
  188. data/spec/lutaml/xml/schema/compiler/group_spec.rb +0 -90
  189. data/spec/lutaml/xml/schema/compiler/restriction_spec.rb +0 -77
  190. data/spec/lutaml/xml/schema/compiler/sequence_spec.rb +0 -65
  191. data/spec/lutaml/xml/schema/compiler/simple_content_spec.rb +0 -61
  192. data/spec/lutaml/xml/schema/compiler/simple_type_spec.rb +0 -184
@@ -1,67 +0,0 @@
1
- require "spec_helper"
2
- require "support/xml/schema_helper"
3
-
4
- RSpec.describe Lutaml::Model::Schema::XmlCompiler::Attribute do
5
- let(:attribute) { described_class.new(name: "foo", ref: "bar:Ref") }
6
-
7
- describe "#initialize" do
8
- it "sets name and ref" do
9
- a = described_class.new(name: "foo", ref: "bar")
10
- expect(a.name).to eq("foo")
11
- expect(a.ref).to eq("bar")
12
- end
13
- end
14
-
15
- describe "#to_attributes" do
16
- it "returns attribute line if not skippable" do
17
- allow(attribute).to receive_messages(skippable?: false,
18
- resolved_name: "foo", resolved_type: "string")
19
- expect(attribute.to_attributes(" ")).to include("attribute :foo, :string")
20
- end
21
-
22
- it "returns nil if skippable" do
23
- allow(attribute).to receive(:skippable?).and_return(true)
24
- expect(attribute.to_attributes(" ")).to be_nil
25
- end
26
- end
27
-
28
- describe "#to_xml_mapping" do
29
- it "returns map_attribute line if not skippable" do
30
- allow(attribute).to receive_messages(skippable?: false,
31
- resolved_name: "foo")
32
- expect(attribute.to_xml_mapping(" ")).to include("map_attribute :foo, to: :foo")
33
- end
34
-
35
- it "returns nil if skippable" do
36
- allow(attribute).to receive(:skippable?).and_return(true)
37
- expect(attribute.to_xml_mapping(" ")).to be_nil
38
- end
39
- end
40
-
41
- describe "#required_files" do
42
- it "returns require 'bigdecimal' for decimal type" do
43
- attribute = described_class.new(name: "test")
44
- attribute.type = "decimal"
45
- expect(attribute.required_files).to eq(["require \"bigdecimal\""])
46
- end
47
-
48
- it "returns require_relative for non-skippable type" do
49
- attribute = described_class.new(name: "test")
50
- attribute.type = "foo"
51
- expect(attribute.required_files).to eq(["require_relative \"foo\""])
52
- end
53
-
54
- it "returns nil for skippable type" do
55
- allow(attribute).to receive(:skippable?).and_return(true)
56
- expect(attribute.required_files).to be_nil
57
- end
58
- end
59
-
60
- describe "private methods" do
61
- it "last_of_split returns last part after colon" do
62
- expect(attribute.send(:last_of_split, "foo:Bar")).to eq("Bar")
63
- expect(attribute.send(:last_of_split, "Bar")).to eq("Bar")
64
- expect(attribute.send(:last_of_split, nil)).to be_nil
65
- end
66
- end
67
- end
@@ -1,74 +0,0 @@
1
- require "spec_helper"
2
- require "support/xml/schema_helper"
3
-
4
- RSpec.describe Lutaml::Model::Schema::XmlCompiler::Choice do
5
- let(:choice) { described_class.new }
6
- let(:dummy_class) do
7
- Class.new do
8
- def to_attributes(indent); end
9
- def to_xml_mapping(indent); end
10
- def required_files; end
11
- end
12
- end
13
-
14
- describe "#initialize" do
15
- it "starts with empty instances" do
16
- expect(choice.instances).to eq([])
17
- end
18
- end
19
-
20
- describe "#<<" do
21
- it "adds instances to the list" do
22
- instance = instance_double(dummy_class)
23
- expect { choice << instance }.to change { choice.instances.size }.by(1)
24
- expect(choice.instances).to include(instance)
25
- end
26
-
27
- it "ignores nil instances" do
28
- expect { choice << nil }.not_to(change { choice.instances.size })
29
- end
30
- end
31
-
32
- describe "#to_attributes" do
33
- it "renders the choice block with min/max options" do
34
- instance = instance_double(dummy_class,
35
- to_attributes: " attribute :foo, :string\n")
36
- choice << instance
37
- choice.min_occurs = 1
38
- choice.max_occurs = 2
39
- expect(choice.to_attributes(" ")).to include("choice(")
40
- expect(choice.to_attributes(" ")).to include("attribute :foo, :string")
41
- end
42
- end
43
-
44
- describe "#to_xml_mapping" do
45
- it "returns joined xml mappings from instances" do
46
- instance = instance_double(dummy_class,
47
- to_xml_mapping: " map_element :foo, to: :foo\n")
48
- choice << instance
49
- expect(choice.to_xml_mapping(" ")).to include("map_element :foo, to: :foo")
50
- end
51
- end
52
-
53
- describe "#required_files" do
54
- it "collects required_files from all instances" do
55
- instance = instance_double(dummy_class, required_files: "require 'foo'")
56
- choice << instance
57
- expect(choice.required_files).to include("require 'foo'")
58
- end
59
- end
60
-
61
- describe "private methods" do
62
- it "min_option returns correct min" do
63
- choice.min_occurs = 3
64
- expect(choice.send(:min_option)).to include("min: 3")
65
- end
66
-
67
- it "max_option returns correct max" do
68
- choice.max_occurs = "unbounded"
69
- expect(choice.send(:max_option)).to include("Float::INFINITY")
70
- choice.max_occurs = 5
71
- expect(choice.send(:max_option)).to include("max: 5")
72
- end
73
- end
74
- end
@@ -1,60 +0,0 @@
1
- require "spec_helper"
2
- require "support/xml/schema_helper"
3
-
4
- RSpec.describe Lutaml::Model::Schema::XmlCompiler::ComplexContentRestriction do
5
- let(:restriction) { described_class.new(base: "Base", instances: []) }
6
- let(:dummy_class) do
7
- Class.new do
8
- def to_attributes(indent); end
9
- def to_xml_mapping(indent); end
10
- def required_files; end
11
- end
12
- end
13
-
14
- describe "#initialize" do
15
- it "sets base and instances" do
16
- r = described_class.new(base: "foo", instances: [1, 2])
17
- expect(r.base).to eq("foo")
18
- expect(r.instances).to eq([1, 2])
19
- end
20
- end
21
-
22
- describe "#<<" do
23
- it "adds instances to the list" do
24
- expect { restriction << 1 }.to change {
25
- restriction.instances.size
26
- }.by(1)
27
- expect(restriction.instances).to include(1)
28
- end
29
-
30
- it "ignores nil instances" do
31
- expect { restriction << nil }.not_to(change do
32
- restriction.instances.size
33
- end)
34
- end
35
- end
36
-
37
- describe "#to_attributes" do
38
- it "returns attributes from all instances" do
39
- instance = instance_double(dummy_class, to_attributes: "attr")
40
- restriction.instances = [instance]
41
- expect(restriction.to_attributes(" ")).to include("attr")
42
- end
43
- end
44
-
45
- describe "#to_xml_mapping" do
46
- it "returns xml mappings from all instances" do
47
- instance = instance_double(dummy_class, to_xml_mapping: "xml")
48
- restriction.instances = [instance]
49
- expect(restriction.to_xml_mapping(" ")).to include("xml")
50
- end
51
- end
52
-
53
- describe "#required_files" do
54
- it "collects required_files from all instances" do
55
- instance = instance_double(dummy_class, required_files: "files")
56
- restriction.instances = [instance]
57
- expect(restriction.required_files).to include("files")
58
- end
59
- end
60
- end
@@ -1,41 +0,0 @@
1
- require "spec_helper"
2
- require "support/xml/schema_helper"
3
-
4
- RSpec.describe Lutaml::Model::Schema::XmlCompiler::ComplexContent do
5
- let(:dummy_class) do
6
- Class.new do
7
- def to_attributes(indent); end
8
- def to_xml_mapping(indent); end
9
- def required_files; end
10
- end
11
- end
12
- let(:restriction) do
13
- instance_double(dummy_class, to_attributes: "attr", to_xml_mapping: "xml",
14
- required_files: "files")
15
- end
16
- let(:complex_content) { described_class.new(restriction) }
17
-
18
- describe "#initialize" do
19
- it "sets restriction" do
20
- expect(complex_content.restriction).to eq(restriction)
21
- end
22
- end
23
-
24
- describe "#to_attributes" do
25
- it "delegates to restriction" do
26
- expect(complex_content.to_attributes(" ")).to eq("attr")
27
- end
28
- end
29
-
30
- describe "#to_xml_mapping" do
31
- it "delegates to restriction" do
32
- expect(complex_content.to_xml_mapping(" ")).to eq("xml")
33
- end
34
- end
35
-
36
- describe "#required_files" do
37
- it "delegates to restriction" do
38
- expect(complex_content.required_files).to eq("files")
39
- end
40
- end
41
- end
@@ -1,202 +0,0 @@
1
- require "spec_helper"
2
- require "support/xml/schema_helper"
3
-
4
- RSpec.describe Lutaml::Model::Schema::XmlCompiler::ComplexType do
5
- let(:complex_type) { described_class.new }
6
- let(:dummy_class) do
7
- Class.new do
8
- def to_attributes(indent); end
9
- def to_xml_mapping(indent); end
10
- def required_files; end
11
- end
12
- end
13
- let(:simple_content_class) do
14
- Class.new do
15
- def base_class; end
16
- def to_attributes(indent); end
17
- def to_xml_mapping(indent); end
18
- def required_files; end
19
- end
20
- end
21
-
22
- describe "#initialize" do
23
- it "sets default base_class and empty instances" do
24
- expect(complex_type.base_class).to eq(described_class::SERIALIZABLE_BASE_CLASS)
25
- expect(complex_type.instances).to eq([])
26
- end
27
-
28
- it "allows custom base_class" do
29
- ct = described_class.new(base_class: "CustomBase")
30
- expect(ct.base_class).to eq("CustomBase")
31
- end
32
- end
33
-
34
- describe "attribute accessors" do
35
- it "allows reading and writing id, name, mixed, simple_content" do
36
- complex_type.id = "id"
37
- complex_type.name = "Name"
38
- complex_type.mixed = true
39
- complex_type.simple_content = instance_double(simple_content_class)
40
- expect(complex_type.id).to eq("id")
41
- expect(complex_type.name).to eq("Name")
42
- expect(complex_type.mixed).to be true
43
- expect(complex_type.simple_content).to be_a(RSpec::Mocks::InstanceVerifyingDouble)
44
- end
45
- end
46
-
47
- describe "#<<" do
48
- it "adds instances to the list" do
49
- instance = instance_double(dummy_class)
50
- expect { complex_type << instance }.to change {
51
- complex_type.instances.size
52
- }.by(1)
53
- expect(complex_type.instances).to include(instance)
54
- end
55
-
56
- it "ignores nil instances" do
57
- expect { complex_type << nil }.not_to(change do
58
- complex_type.instances.size
59
- end)
60
- end
61
- end
62
-
63
- describe "#simple_content?" do
64
- it "returns false if simple_content is nil or blank" do
65
- expect(complex_type.simple_content?).to be false
66
- complex_type.simple_content = nil
67
- expect(complex_type.simple_content?).to be false
68
- end
69
-
70
- it "returns true if simple_content is present" do
71
- complex_type.simple_content = instance_double(simple_content_class)
72
- expect(complex_type.simple_content?).to be true
73
- end
74
- end
75
-
76
- describe "#to_class" do
77
- it "renders a class with no instances or simple_content" do
78
- complex_type.name = "TestClass"
79
- code = complex_type.to_class
80
- expect(code).to include("class TestClass < Lutaml::Model::Serializable")
81
- expect(code).to include("def self.register_class_with_id")
82
- end
83
-
84
- it "renders a class with instances" do
85
- instance = instance_double(dummy_class,
86
- to_attributes: " attribute :foo, :string\n", to_xml_mapping: " map_element 'foo', to: :foo\n", required_files: [])
87
- complex_type.name = "TestClass"
88
- complex_type << instance
89
- code = complex_type.to_class
90
- expect(code).to include("attribute :foo, :string")
91
- expect(code).to include("map_element 'foo', to: :foo")
92
- end
93
-
94
- it "renders a class with simple_content" do
95
- simple_content = instance_double(simple_content_class,
96
- base_class: "string", to_attributes: " attribute :content, :string\n", to_xml_mapping: " map_content to: :content\n", required_files: ["require 'simple_content'"])
97
- complex_type.name = "TestClass"
98
- complex_type.simple_content = simple_content
99
- code = complex_type.to_class
100
- expect(code).to include("attribute :content, :string")
101
- expect(code).to include("map_content to: :content")
102
- expect(code).to include("require 'simple_content'")
103
- end
104
-
105
- it "renders a class with mixed content" do
106
- complex_type.name = "TestClass"
107
- complex_type.mixed = true
108
- code = complex_type.to_class
109
- expect(code).to include("mixed_content")
110
- end
111
-
112
- it "renders a class with mixed content and no simple_content has collection: true" do
113
- complex_type.name = "TestClass"
114
- complex_type.mixed = true
115
- # simple_content is nil by default, so simple_content? returns false
116
- code = complex_type.to_class
117
- expect(code).to include("mixed_content")
118
- expect(code).to include("attribute :content, :string, collection: true")
119
- end
120
-
121
- it "renders a class with mixed content and simple_content does not have collection: true" do
122
- simple_content = instance_double(simple_content_class,
123
- base_class: "string", to_attributes: " attribute :content, :string\n", to_xml_mapping: " map_content to: :content\n", required_files: [])
124
- complex_type.name = "TestClass"
125
- complex_type.mixed = true
126
- complex_type.simple_content = simple_content
127
- code = complex_type.to_class
128
- expect(code).to include("mixed_content")
129
- expect(code).to include("attribute :content, :string")
130
- expect(code).not_to include("collection: true")
131
- end
132
-
133
- it "renders a class with namespace and prefix options" do
134
- complex_type.name = "TestClass"
135
- code = complex_type.to_class(options: { namespace: "http://example.com",
136
- indent: 2 })
137
- # Without namespace classes registered in XmlCompiler.namespace_classes,
138
- # no namespace directive will be output. This reflects the new architecture
139
- # where namespace classes must be pre-created.
140
- expect(code).not_to include("namespace")
141
- end
142
- end
143
-
144
- describe "#required_files" do
145
- it "returns empty array for default base_class (require lutaml/model is in template)" do
146
- expect(complex_type.required_files).to eq([])
147
- end
148
-
149
- it "returns empty array for custom base_class (autoload handles dependencies)" do
150
- ct = described_class.new(base_class: "foo:BarBase")
151
- expect(ct.required_files).to eq([])
152
- end
153
-
154
- it "includes required_files from instances and simple_content" do
155
- instance = instance_double(dummy_class,
156
- required_files: ["require 'foo'"])
157
- simple_content = instance_double(simple_content_class,
158
- required_files: ["require 'bar'"])
159
- complex_type << instance
160
- complex_type.simple_content = simple_content
161
- expect(complex_type.required_files).to include("require 'foo'")
162
- expect(complex_type.required_files).to include("require 'bar'")
163
- end
164
- end
165
-
166
- describe "private methods" do
167
- it "base_class_name returns correct value" do
168
- expect(complex_type.send(:base_class_name)).to eq("Lutaml::Model::Serializable")
169
- ct = described_class.new(base_class: "foo:BarBase")
170
- expect(ct.send(:base_class_name)).to eq("BarBase")
171
- end
172
-
173
- it "last_of_split returns last part after colon" do
174
- expect(complex_type.send(:last_of_split,
175
- "foo:BarBase")).to eq("BarBase")
176
- expect(complex_type.send(:last_of_split, "BarBase")).to eq("BarBase")
177
- expect(complex_type.send(:last_of_split, nil)).to be_nil
178
- end
179
- end
180
-
181
- describe "edge cases" do
182
- it "handles no instances or simple_content" do
183
- complex_type.name = "TestClass"
184
- expect { complex_type.to_class }.not_to raise_error
185
- end
186
-
187
- it "handles unusual base_class values" do
188
- ct = described_class.new(base_class: nil)
189
- ct.name = "TestClass"
190
- expect { ct.to_class }.not_to raise_error
191
- end
192
- end
193
-
194
- describe "integration" do
195
- it "generates valid Ruby code for a complex type" do
196
- complex_type.name = "TestClass"
197
- code = complex_type.to_class
198
- expect(code).to include("class TestClass < Lutaml::Model::Serializable")
199
- expect(code).to include("def self.register_class_with_id")
200
- end
201
- end
202
- end
@@ -1,68 +0,0 @@
1
- require "spec_helper"
2
- require "support/xml/schema_helper"
3
-
4
- RSpec.describe Lutaml::Model::Schema::XmlCompiler::Element do
5
- let(:element) { described_class.new(name: "foo", ref: "bar:Ref") }
6
-
7
- describe "#initialize" do
8
- it "sets name and ref" do
9
- e = described_class.new(name: "foo", ref: "bar")
10
- expect(e.name).to eq("foo")
11
- expect(e.ref).to eq("bar")
12
- end
13
- end
14
-
15
- describe "#to_attributes" do
16
- it "returns attribute line if not skippable and resolved_type present" do
17
- allow(element).to receive_messages(resolved_name: "foo",
18
- resolved_type: "string", skippable?: false)
19
- expect(element.to_attributes(" ")).to include("attribute :foo, :string")
20
- end
21
-
22
- it "returns nil if skippable" do
23
- allow(element).to receive(:skippable?).and_return(true)
24
- expect(element.to_attributes(" ")).to be_nil
25
- end
26
- end
27
-
28
- describe "#to_xml_mapping" do
29
- it "returns map_element line if not skippable and resolved_type present" do
30
- allow(element).to receive_messages(resolved_name: "foo",
31
- resolved_type: "string", skippable?: false)
32
- expect(element.to_xml_mapping(" ")).to include("map_element :foo, to: :foo")
33
- end
34
-
35
- it "returns nil if skippable" do
36
- allow(element).to receive(:skippable?).and_return(true)
37
- expect(element.to_xml_mapping(" ")).to be_nil
38
- end
39
- end
40
-
41
- describe "#required_files" do
42
- it "returns require 'bigdecimal' for decimal type" do
43
- allow(element).to receive_messages(resolved_name: "foo",
44
- resolved_type: "decimal", skippable?: false)
45
- expect(element.required_files).to eq("require \"bigdecimal\"")
46
- end
47
-
48
- it "returns require_relative for non-skippable type" do
49
- allow(Lutaml::Model::Schema::XmlCompiler::SimpleType).to receive(:skippable?).and_return(false)
50
- allow(element).to receive_messages(resolved_name: "foo",
51
- resolved_type: "foo")
52
- expect(element.required_files).to eq("require_relative \"foo\"")
53
- end
54
-
55
- it "returns nil for skippable type" do
56
- allow(element).to receive(:skippable?).and_return(true)
57
- expect(element.required_files).to be_nil
58
- end
59
- end
60
-
61
- describe "private methods" do
62
- it "last_of_split returns last part after colon" do
63
- expect(element.send(:last_of_split, "foo:Bar")).to eq("Bar")
64
- expect(element.send(:last_of_split, "Bar")).to eq("Bar")
65
- expect(element.send(:last_of_split, nil)).to be_nil
66
- end
67
- end
68
- end
@@ -1,90 +0,0 @@
1
- require "spec_helper"
2
- require "support/xml/schema_helper"
3
-
4
- RSpec.describe Lutaml::Model::Schema::XmlCompiler::Group do
5
- let(:group) { described_class.new("GroupName", nil) }
6
- let(:dummy_class) do
7
- Class.new do
8
- def to_attributes(indent); end
9
- def to_xml_mapping(indent); end
10
- def required_files; end
11
- end
12
- end
13
-
14
- describe "#initialize" do
15
- it "sets name and ref" do
16
- g = described_class.new("foo", "bar")
17
- expect(g.name).to eq("foo")
18
- expect(g.ref).to eq("bar")
19
- end
20
- end
21
-
22
- describe "#to_xml_mapping" do
23
- it "returns import_model_mappings if ref is present" do
24
- group.ref = "foo:Bar"
25
- group.name = nil
26
- expect(group.to_xml_mapping(" ")).to include("import_model_mappings :bar")
27
- end
28
-
29
- it "delegates to instance if ref is not present" do
30
- instance = instance_double(dummy_class,
31
- to_xml_mapping: " map_element :foo, to: :foo\n")
32
- group.instance = instance
33
- group.ref = nil
34
- expect(group.to_xml_mapping(" ")).to include("map_element :foo, to: :foo")
35
- end
36
- end
37
-
38
- describe "#to_class" do
39
- it "renders the group template" do
40
- group.name = "GroupName"
41
- group.instance = instance_double(dummy_class,
42
- to_attributes: " attribute :foo, :string\n", to_xml_mapping: " map_element :foo, to: :foo\n", required_files: [])
43
- expect(group.to_class).to include("class GroupName")
44
- expect(group.to_class).to include("attribute :foo, :string")
45
- expect(group.to_class).to include("map_element :foo, to: :foo")
46
- end
47
- end
48
-
49
- describe "#required_files" do
50
- it "returns require_relative for ref type when name is blank" do
51
- group.name = nil
52
- group.ref = "foo:Bar"
53
- expect(group.required_files).to eq("require_relative \"bar\"")
54
- end
55
-
56
- it "delegates to instance if name is present" do
57
- instance = instance_double(dummy_class, required_files: "require 'foo'")
58
- group.instance = instance
59
- group.name = "GroupName"
60
- group.ref = nil
61
- expect(group.required_files).to eq("require 'foo'")
62
- end
63
- end
64
-
65
- describe "#to_attributes" do
66
- it "returns import_model_attributes if ref is present" do
67
- group.ref = "foo:Bar"
68
- group.name = nil
69
- expect(group.to_attributes(" ")).to include("import_model_attributes :bar")
70
- end
71
-
72
- it "delegates to instance if ref is not present" do
73
- instance = instance_double(dummy_class,
74
- to_attributes: " attribute :foo, :string\n")
75
- group.instance = instance
76
- group.ref = nil
77
- expect(group.to_attributes(" ")).to include("attribute :foo, :string")
78
- end
79
- end
80
-
81
- describe "#base_name" do
82
- it "returns last part of name or ref" do
83
- group.name = "foo:Bar"
84
- expect(group.base_name).to eq("Bar")
85
- group.name = nil
86
- group.ref = "foo:Baz"
87
- expect(group.base_name).to eq("Baz")
88
- end
89
- end
90
- end
@@ -1,77 +0,0 @@
1
- require "spec_helper"
2
- require "support/xml/schema_helper"
3
-
4
- RSpec.describe Lutaml::Model::Schema::XmlCompiler::Restriction do
5
- let(:restriction) { described_class.new }
6
-
7
- describe "attribute accessors" do
8
- it "allows reading and writing all attributes" do
9
- restriction.min_inclusive = 1
10
- restriction.max_inclusive = 10
11
- restriction.min_exclusive = 2
12
- restriction.max_exclusive = 9
13
- restriction.enumerations = ["A", "B"]
14
- restriction.max_length = 5
15
- restriction.min_length = 1
16
- restriction.base_class = "foo:Bar"
17
- restriction.pattern = /abc/
18
- restriction.length = 3
19
- restriction.transform = "value.upcase"
20
- expect(restriction.min_inclusive).to eq(1)
21
- expect(restriction.max_inclusive).to eq(10)
22
- expect(restriction.enumerations).to eq(["A", "B"])
23
- expect(restriction.pattern).to eq(/abc/)
24
- expect(restriction.transform).to eq("value.upcase")
25
- end
26
- end
27
-
28
- describe "#to_method_body" do
29
- it "returns method body for all present attributes" do
30
- restriction.enumerations = ["A", "B"]
31
- restriction.min_inclusive = 1
32
- restriction.max_inclusive = 10
33
- restriction.pattern = /abc/
34
- restriction.transform = "value.upcase"
35
- body = restriction.to_method_body(" ")
36
- expect(body).to include("options[:values]")
37
- expect(body).to include("options[:min]")
38
- expect(body).to include("options[:max]")
39
- expect(body).to include("options[:pattern]")
40
- expect(body).to include("value = value.upcase")
41
- end
42
-
43
- it "returns empty string if no attributes are set" do
44
- expect(restriction.to_method_body(" ")).to eq("")
45
- end
46
- end
47
-
48
- describe "#required_files" do
49
- it "returns require 'bigdecimal' for decimal base_class" do
50
- restriction.base_class = "decimal"
51
- expect(restriction.required_files).to eq("require \"bigdecimal\"")
52
- end
53
-
54
- it "returns require_relative for non-skippable base_class" do
55
- restriction.base_class = "foo:Base"
56
- expect(restriction.required_files).to eq("require_relative \"base\"")
57
- end
58
-
59
- it "returns nil for skippable base_class" do
60
- restriction.base_class = "string"
61
- expect(restriction.required_files).to be_nil
62
- end
63
- end
64
-
65
- describe "private methods" do
66
- it "base_class_name returns last part as symbol" do
67
- restriction.base_class = "foo:Bar"
68
- expect(restriction.send(:base_class_name)).to eq(:Bar)
69
- end
70
-
71
- it "casted_enumerations returns super calls for each enumeration" do
72
- restriction.enumerations = ["A", "B"]
73
- expect(restriction.send(:casted_enumerations)).to include("super(\"A\")")
74
- expect(restriction.send(:casted_enumerations)).to include("super(\"B\")")
75
- end
76
- end
77
- end