lutaml-model 0.7.3 → 0.7.5

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 (184) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +1 -0
  3. data/.github/workflows/release.yml +3 -0
  4. data/.gitignore +6 -1
  5. data/.irbrc +1 -0
  6. data/.pryrc +1 -0
  7. data/.rubocop_todo.yml +25 -52
  8. data/README.adoc +2177 -192
  9. data/docs/custom_registers.adoc +228 -0
  10. data/docs/schema_generation.adoc +898 -0
  11. data/docs/schema_import.adoc +364 -0
  12. data/flake.lock +114 -0
  13. data/flake.nix +103 -0
  14. data/lib/lutaml/model/attribute.rb +230 -94
  15. data/lib/lutaml/model/choice.rb +30 -0
  16. data/lib/lutaml/model/collection.rb +194 -0
  17. data/lib/lutaml/model/comparable_model.rb +3 -3
  18. data/lib/lutaml/model/config.rb +26 -3
  19. data/lib/lutaml/model/constants.rb +2 -0
  20. data/lib/lutaml/model/error/element_count_out_of_range_error.rb +29 -0
  21. data/lib/lutaml/model/error/invalid_attribute_name_error.rb +15 -0
  22. data/lib/lutaml/model/error/invalid_attribute_options_error.rb +16 -0
  23. data/lib/lutaml/model/error/invalid_choice_range_error.rb +3 -5
  24. data/lib/lutaml/model/error/register/not_registrable_class_error.rb +11 -0
  25. data/lib/lutaml/model/error/type/invalid_value_error.rb +5 -3
  26. data/lib/lutaml/model/error/type/max_bound_error.rb +20 -0
  27. data/lib/lutaml/model/error/type/max_length_error.rb +20 -0
  28. data/lib/lutaml/model/error/type/min_bound_error.rb +20 -0
  29. data/lib/lutaml/model/error/type/min_length_error.rb +20 -0
  30. data/lib/lutaml/model/error/type/pattern_not_matched_error.rb +18 -0
  31. data/lib/lutaml/model/error/validation_failed_error.rb +9 -0
  32. data/lib/lutaml/model/error.rb +10 -0
  33. data/lib/lutaml/model/errors.rb +36 -0
  34. data/lib/lutaml/model/format_registry.rb +5 -2
  35. data/lib/lutaml/model/global_register.rb +41 -0
  36. data/lib/lutaml/model/{hash.rb → hash_adapter.rb} +5 -5
  37. data/lib/lutaml/model/jsonl/document.rb +14 -0
  38. data/lib/lutaml/model/jsonl/mapping.rb +19 -0
  39. data/lib/lutaml/model/jsonl/mapping_rule.rb +9 -0
  40. data/lib/lutaml/model/jsonl/standard_adapter.rb +33 -0
  41. data/lib/lutaml/model/jsonl/transform.rb +19 -0
  42. data/lib/lutaml/model/jsonl.rb +21 -0
  43. data/lib/lutaml/model/key_value_document.rb +3 -2
  44. data/lib/lutaml/model/mapping/key_value_mapping.rb +64 -4
  45. data/lib/lutaml/model/mapping/key_value_mapping_rule.rb +4 -0
  46. data/lib/lutaml/model/mapping/mapping_rule.rb +8 -3
  47. data/lib/lutaml/model/register.rb +105 -0
  48. data/lib/lutaml/model/registrable.rb +6 -0
  49. data/lib/lutaml/model/schema/base_schema.rb +64 -0
  50. data/lib/lutaml/model/schema/decorators/attribute.rb +114 -0
  51. data/lib/lutaml/model/schema/decorators/choices.rb +31 -0
  52. data/lib/lutaml/model/schema/decorators/class_definition.rb +85 -0
  53. data/lib/lutaml/model/schema/decorators/definition_collection.rb +97 -0
  54. data/lib/lutaml/model/schema/generator/definition.rb +53 -0
  55. data/lib/lutaml/model/schema/generator/definitions_collection.rb +81 -0
  56. data/lib/lutaml/model/schema/generator/properties_collection.rb +63 -0
  57. data/lib/lutaml/model/schema/generator/property.rb +110 -0
  58. data/lib/lutaml/model/schema/generator/ref.rb +24 -0
  59. data/lib/lutaml/model/schema/helpers/template_helper.rb +49 -0
  60. data/lib/lutaml/model/schema/json_schema.rb +42 -49
  61. data/lib/lutaml/model/schema/relaxng_schema.rb +14 -10
  62. data/lib/lutaml/model/schema/renderer.rb +36 -0
  63. data/lib/lutaml/model/schema/shared_methods.rb +24 -0
  64. data/lib/lutaml/model/schema/templates/model.erb +9 -0
  65. data/lib/lutaml/model/schema/xml_compiler/attribute.rb +85 -0
  66. data/lib/lutaml/model/schema/xml_compiler/attribute_group.rb +45 -0
  67. data/lib/lutaml/model/schema/xml_compiler/choice.rb +65 -0
  68. data/lib/lutaml/model/schema/xml_compiler/complex_content.rb +27 -0
  69. data/lib/lutaml/model/schema/xml_compiler/complex_content_restriction.rb +34 -0
  70. data/lib/lutaml/model/schema/xml_compiler/complex_type.rb +136 -0
  71. data/lib/lutaml/model/schema/xml_compiler/element.rb +104 -0
  72. data/lib/lutaml/model/schema/xml_compiler/group.rb +97 -0
  73. data/lib/lutaml/model/schema/xml_compiler/restriction.rb +101 -0
  74. data/lib/lutaml/model/schema/xml_compiler/sequence.rb +50 -0
  75. data/lib/lutaml/model/schema/xml_compiler/simple_content.rb +36 -0
  76. data/lib/lutaml/model/schema/xml_compiler/simple_type.rb +189 -0
  77. data/lib/lutaml/model/schema/xml_compiler.rb +231 -587
  78. data/lib/lutaml/model/schema/xsd_schema.rb +12 -8
  79. data/lib/lutaml/model/schema/yaml_schema.rb +41 -35
  80. data/lib/lutaml/model/schema.rb +1 -0
  81. data/lib/lutaml/model/sequence.rb +60 -30
  82. data/lib/lutaml/model/serialize.rb +175 -53
  83. data/lib/lutaml/model/services/base.rb +11 -0
  84. data/lib/lutaml/model/services/logger.rb +2 -2
  85. data/lib/lutaml/model/services/rule_value_extractor.rb +92 -0
  86. data/lib/lutaml/model/services/type/validator/number.rb +25 -0
  87. data/lib/lutaml/model/services/type/validator/string.rb +52 -0
  88. data/lib/lutaml/model/services/type/validator.rb +43 -0
  89. data/lib/lutaml/model/services/validator.rb +145 -0
  90. data/lib/lutaml/model/services.rb +3 -0
  91. data/lib/lutaml/model/transform/key_value_transform.rb +60 -50
  92. data/lib/lutaml/model/transform/xml_transform.rb +46 -57
  93. data/lib/lutaml/model/transform.rb +22 -8
  94. data/lib/lutaml/model/type/boolean.rb +1 -1
  95. data/lib/lutaml/model/type/date.rb +1 -1
  96. data/lib/lutaml/model/type/date_time.rb +1 -1
  97. data/lib/lutaml/model/type/decimal.rb +11 -9
  98. data/lib/lutaml/model/type/float.rb +2 -1
  99. data/lib/lutaml/model/type/integer.rb +24 -21
  100. data/lib/lutaml/model/type/string.rb +4 -2
  101. data/lib/lutaml/model/type/time.rb +1 -1
  102. data/lib/lutaml/model/type/time_without_date.rb +1 -1
  103. data/lib/lutaml/model/type/value.rb +5 -1
  104. data/lib/lutaml/model/type.rb +5 -2
  105. data/lib/lutaml/model/utils.rb +30 -8
  106. data/lib/lutaml/model/validation.rb +6 -4
  107. data/lib/lutaml/model/version.rb +1 -1
  108. data/lib/lutaml/model/xml/document.rb +37 -19
  109. data/lib/lutaml/model/xml/mapping.rb +74 -13
  110. data/lib/lutaml/model/xml/mapping_rule.rb +10 -2
  111. data/lib/lutaml/model/xml/nokogiri_adapter.rb +5 -3
  112. data/lib/lutaml/model/xml/oga/element.rb +4 -1
  113. data/lib/lutaml/model/xml/oga_adapter.rb +4 -3
  114. data/lib/lutaml/model/xml/ox_adapter.rb +20 -6
  115. data/lib/lutaml/model/xml/xml_element.rb +3 -28
  116. data/lib/lutaml/model/xml_adapter/element.rb +1 -1
  117. data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +1 -1
  118. data/lib/lutaml/model/xml_adapter/oga_adapter.rb +1 -1
  119. data/lib/lutaml/model/xml_adapter/ox_adapter.rb +1 -1
  120. data/lib/lutaml/model/yamls/document.rb +14 -0
  121. data/lib/lutaml/model/yamls/mapping.rb +19 -0
  122. data/lib/lutaml/model/yamls/mapping_rule.rb +9 -0
  123. data/lib/lutaml/model/yamls/standard_adapter.rb +34 -0
  124. data/lib/lutaml/model/yamls/transform.rb +19 -0
  125. data/lib/lutaml/model/yamls.rb +21 -0
  126. data/lib/lutaml/model.rb +7 -31
  127. data/spec/benchmarks/xml_parsing_benchmark_spec.rb +4 -5
  128. data/spec/fixtures/xml/advanced_test_schema.xsd +134 -0
  129. data/spec/fixtures/xml/examples/nested_categories.xml +55 -0
  130. data/spec/fixtures/xml/examples/valid_catalog.xml +43 -0
  131. data/spec/fixtures/xml/product_catalog.xsd +151 -0
  132. data/spec/fixtures/xml/specifications_schema.xsd +38 -0
  133. data/spec/lutaml/model/attribute_collection_spec.rb +101 -0
  134. data/spec/lutaml/model/attribute_spec.rb +41 -44
  135. data/spec/lutaml/model/choice_spec.rb +44 -0
  136. data/spec/lutaml/model/custom_collection_spec.rb +830 -0
  137. data/spec/lutaml/model/custom_model_spec.rb +15 -3
  138. data/spec/lutaml/model/defaults_spec.rb +5 -1
  139. data/spec/lutaml/model/global_register_spec.rb +108 -0
  140. data/spec/lutaml/model/group_spec.rb +9 -3
  141. data/spec/lutaml/model/jsonl/standard_adapter_spec.rb +91 -0
  142. data/spec/lutaml/model/jsonl_spec.rb +229 -0
  143. data/spec/lutaml/model/multiple_mapping_spec.rb +1 -1
  144. data/spec/lutaml/model/register/key_value_spec.rb +275 -0
  145. data/spec/lutaml/model/register/xml_spec.rb +187 -0
  146. data/spec/lutaml/model/register_spec.rb +147 -0
  147. data/spec/lutaml/model/rule_value_extractor_spec.rb +162 -0
  148. data/spec/lutaml/model/schema/generator/definitions_collection_spec.rb +120 -0
  149. data/spec/lutaml/model/schema/json_schema_spec.rb +412 -51
  150. data/spec/lutaml/model/schema/json_schema_to_models_spec.rb +383 -0
  151. data/spec/lutaml/model/schema/xml_compiler/attribute_group_spec.rb +65 -0
  152. data/spec/lutaml/model/schema/xml_compiler/attribute_spec.rb +63 -0
  153. data/spec/lutaml/model/schema/xml_compiler/choice_spec.rb +71 -0
  154. data/spec/lutaml/model/schema/xml_compiler/complex_content_restriction_spec.rb +55 -0
  155. data/spec/lutaml/model/schema/xml_compiler/complex_content_spec.rb +37 -0
  156. data/spec/lutaml/model/schema/xml_compiler/complex_type_spec.rb +173 -0
  157. data/spec/lutaml/model/schema/xml_compiler/element_spec.rb +63 -0
  158. data/spec/lutaml/model/schema/xml_compiler/group_spec.rb +86 -0
  159. data/spec/lutaml/model/schema/xml_compiler/restriction_spec.rb +76 -0
  160. data/spec/lutaml/model/schema/xml_compiler/sequence_spec.rb +59 -0
  161. data/spec/lutaml/model/schema/xml_compiler/simple_content_spec.rb +55 -0
  162. data/spec/lutaml/model/schema/xml_compiler/simple_type_spec.rb +181 -0
  163. data/spec/lutaml/model/schema/xml_compiler_spec.rb +503 -1804
  164. data/spec/lutaml/model/schema/yaml_schema_spec.rb +249 -26
  165. data/spec/lutaml/model/sequence_spec.rb +36 -0
  166. data/spec/lutaml/model/serializable_spec.rb +31 -0
  167. data/spec/lutaml/model/type_spec.rb +8 -4
  168. data/spec/lutaml/model/utils_spec.rb +3 -3
  169. data/spec/lutaml/model/xml/derived_attributes_spec.rb +1 -1
  170. data/spec/lutaml/model/xml/xml_element_spec.rb +7 -1
  171. data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +6 -6
  172. data/spec/lutaml/model/xml_adapter_spec.rb +24 -0
  173. data/spec/lutaml/model/xml_mapping_rule_spec.rb +11 -4
  174. data/spec/lutaml/model/xml_mapping_spec.rb +1 -1
  175. data/spec/lutaml/model/yamls/standard_adapter_spec.rb +183 -0
  176. data/spec/lutaml/model/yamls_spec.rb +294 -0
  177. data/spec/spec_helper.rb +1 -0
  178. metadata +105 -9
  179. data/lib/lutaml/model/schema/templates/simple_type.rb +0 -247
  180. /data/lib/lutaml/model/{hash → hash_adapter}/document.rb +0 -0
  181. /data/lib/lutaml/model/{hash → hash_adapter}/mapping.rb +0 -0
  182. /data/lib/lutaml/model/{hash → hash_adapter}/mapping_rule.rb +0 -0
  183. /data/lib/lutaml/model/{hash → hash_adapter}/standard_adapter.rb +0 -0
  184. /data/lib/lutaml/model/{hash → hash_adapter}/transform.rb +0 -0
@@ -0,0 +1,173 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Lutaml::Model::Schema::XmlCompiler::ComplexType do
4
+ let(:complex_type) { described_class.new }
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(:simple_content_class) do
13
+ Class.new do
14
+ def base_class; end
15
+ def to_attributes(indent); end
16
+ def to_xml_mapping(indent); end
17
+ def required_files; end
18
+ end
19
+ end
20
+
21
+ describe "#initialize" do
22
+ it "sets default base_class and empty instances" do
23
+ expect(complex_type.base_class).to eq(described_class::SERIALIZABLE_BASE_CLASS)
24
+ expect(complex_type.instances).to eq([])
25
+ end
26
+
27
+ it "allows custom base_class" do
28
+ ct = described_class.new(base_class: "CustomBase")
29
+ expect(ct.base_class).to eq("CustomBase")
30
+ end
31
+ end
32
+
33
+ describe "attribute accessors" do
34
+ it "allows reading and writing id, name, mixed, simple_content" do
35
+ complex_type.id = "id"
36
+ complex_type.name = "Name"
37
+ complex_type.mixed = true
38
+ complex_type.simple_content = instance_double(simple_content_class)
39
+ expect(complex_type.id).to eq("id")
40
+ expect(complex_type.name).to eq("Name")
41
+ expect(complex_type.mixed).to be true
42
+ expect(complex_type.simple_content).to be_a(RSpec::Mocks::InstanceVerifyingDouble)
43
+ end
44
+ end
45
+
46
+ describe "#<<" do
47
+ it "adds instances to the list" do
48
+ instance = instance_double(dummy_class)
49
+ expect { complex_type << instance }.to change { complex_type.instances.size }.by(1)
50
+ expect(complex_type.instances).to include(instance)
51
+ end
52
+
53
+ it "ignores nil instances" do
54
+ expect { complex_type << nil }.not_to(change { complex_type.instances.size })
55
+ end
56
+ end
57
+
58
+ describe "#simple_content?" do
59
+ it "returns false if simple_content is nil or blank" do
60
+ expect(complex_type.simple_content?).to be false
61
+ complex_type.simple_content = nil
62
+ expect(complex_type.simple_content?).to be false
63
+ end
64
+
65
+ it "returns true if simple_content is present" do
66
+ complex_type.simple_content = instance_double(simple_content_class)
67
+ expect(complex_type.simple_content?).to be true
68
+ end
69
+ end
70
+
71
+ describe "#to_class" do
72
+ it "renders a class with no instances or simple_content" do
73
+ complex_type.name = "TestClass"
74
+ code = complex_type.to_class
75
+ expect(code).to include("class TestClass < Lutaml::Model::Serializable")
76
+ expect(code).to include("def self.register_class_with_id")
77
+ end
78
+
79
+ it "renders a class with instances" do
80
+ instance = instance_double(dummy_class, to_attributes: " attribute :foo, :string\n", to_xml_mapping: " map_element 'foo', to: :foo\n", required_files: [])
81
+ complex_type.name = "TestClass"
82
+ complex_type << instance
83
+ code = complex_type.to_class
84
+ expect(code).to include("attribute :foo, :string")
85
+ expect(code).to include("map_element 'foo', to: :foo")
86
+ end
87
+
88
+ it "renders a class with simple_content" do
89
+ simple_content = instance_double(simple_content_class, base_class: "string", to_attributes: " attribute :content, :string\n", to_xml_mapping: " map_content to: :content\n", required_files: ["require 'simple_content'"])
90
+ complex_type.name = "TestClass"
91
+ complex_type.simple_content = simple_content
92
+ code = complex_type.to_class
93
+ expect(code).to include("attribute :content, :string")
94
+ expect(code).to include("map_content to: :content")
95
+ expect(code).to include("require 'simple_content'")
96
+ end
97
+
98
+ it "renders a class with mixed content" do
99
+ complex_type.name = "TestClass"
100
+ complex_type.mixed = true
101
+ code = complex_type.to_class
102
+ expect(code).to include(", mixed: true")
103
+ end
104
+
105
+ it "renders a class with namespace and prefix options" do
106
+ complex_type.name = "TestClass"
107
+ code = complex_type.to_class(options: { namespace: "http://example.com", prefix: "ex", indent: 2 })
108
+ expect(code).to include("namespace \"http://example.com\"", "\"ex\"")
109
+ end
110
+ end
111
+
112
+ describe "#required_files" do
113
+ it "returns require lutaml/model for default base_class" do
114
+ expect(complex_type.required_files).to include("require \"lutaml/model\"")
115
+ end
116
+
117
+ it "returns require_relative for custom base_class" do
118
+ ct = described_class.new(base_class: "foo:BarBase")
119
+ expect(ct.required_files).to include("require_relative \"bar_base\"")
120
+ end
121
+
122
+ it "includes required_files from instances and simple_content" do
123
+ instance = instance_double(dummy_class, required_files: ["require 'foo'"])
124
+ simple_content = instance_double(simple_content_class, required_files: ["require 'bar'"])
125
+ complex_type << instance
126
+ complex_type.simple_content = simple_content
127
+ expect(complex_type.required_files).to include("require 'foo'")
128
+ expect(complex_type.required_files).to include("require 'bar'")
129
+ end
130
+ end
131
+
132
+ describe "private methods" do
133
+ it "base_class_name returns correct value" do
134
+ expect(complex_type.send(:base_class_name)).to eq("Lutaml::Model::Serializable")
135
+ ct = described_class.new(base_class: "foo:BarBase")
136
+ expect(ct.send(:base_class_name)).to eq("BarBase")
137
+ end
138
+
139
+ it "base_class_require returns correct require line" do
140
+ expect(complex_type.send(:base_class_require)).to eq("require \"lutaml/model\"")
141
+ ct = described_class.new(base_class: "foo:BarBase")
142
+ expect(ct.send(:base_class_require)).to eq("require_relative \"bar_base\"")
143
+ end
144
+
145
+ it "last_of_split returns last part after colon" do
146
+ expect(complex_type.send(:last_of_split, "foo:BarBase")).to eq("BarBase")
147
+ expect(complex_type.send(:last_of_split, "BarBase")).to eq("BarBase")
148
+ expect(complex_type.send(:last_of_split, nil)).to be_nil
149
+ end
150
+ end
151
+
152
+ describe "edge cases" do
153
+ it "handles no instances or simple_content" do
154
+ complex_type.name = "TestClass"
155
+ expect { complex_type.to_class }.not_to raise_error
156
+ end
157
+
158
+ it "handles unusual base_class values" do
159
+ ct = described_class.new(base_class: nil)
160
+ ct.name = "TestClass"
161
+ expect { ct.to_class }.not_to raise_error
162
+ end
163
+ end
164
+
165
+ describe "integration" do
166
+ it "generates valid Ruby code for a complex type" do
167
+ complex_type.name = "TestClass"
168
+ code = complex_type.to_class
169
+ expect(code).to include("class TestClass < Lutaml::Model::Serializable")
170
+ expect(code).to include("def self.register_class_with_id")
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,63 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Lutaml::Model::Schema::XmlCompiler::Element do
4
+ let(:element) { described_class.new(name: "foo", ref: "bar:Ref") }
5
+
6
+ describe "#initialize" do
7
+ it "sets name and ref" do
8
+ e = described_class.new(name: "foo", ref: "bar")
9
+ expect(e.name).to eq("foo")
10
+ expect(e.ref).to eq("bar")
11
+ end
12
+ end
13
+
14
+ describe "#to_attributes" do
15
+ it "returns attribute line if not skippable and resolved_type present" do
16
+ allow(element).to receive_messages(resolved_name: "foo", resolved_type: "string", skippable?: false)
17
+ expect(element.to_attributes(" ")).to include("attribute :foo, :string")
18
+ end
19
+
20
+ it "returns nil if skippable" do
21
+ allow(element).to receive(:skippable?).and_return(true)
22
+ expect(element.to_attributes(" ")).to be_nil
23
+ end
24
+ end
25
+
26
+ describe "#to_xml_mapping" do
27
+ it "returns map_element line if not skippable and resolved_type present" do
28
+ allow(element).to receive_messages(resolved_name: "foo", resolved_type: "string", skippable?: false)
29
+ expect(element.to_xml_mapping(" ")).to include("map_element :foo, to: :foo")
30
+ end
31
+
32
+ it "returns nil if skippable" do
33
+ allow(element).to receive(:skippable?).and_return(true)
34
+ expect(element.to_xml_mapping(" ")).to be_nil
35
+ end
36
+ end
37
+
38
+ describe "#required_files" do
39
+ it "returns require 'bigdecimal' for decimal type" do
40
+ allow(element).to receive_messages(resolved_name: "foo", resolved_type: "decimal", skippable?: false)
41
+ expect(element.required_files).to eq("require \"bigdecimal\"")
42
+ end
43
+
44
+ it "returns require_relative for non-skippable type" do
45
+ allow(Lutaml::Model::Schema::XmlCompiler::SimpleType).to receive(:skippable?).and_return(false)
46
+ allow(element).to receive_messages(resolved_name: "foo", resolved_type: "foo")
47
+ expect(element.required_files).to eq("require_relative \"foo\"")
48
+ end
49
+
50
+ it "returns nil for skippable type" do
51
+ allow(element).to receive(:skippable?).and_return(true)
52
+ expect(element.required_files).to be_nil
53
+ end
54
+ end
55
+
56
+ describe "private methods" do
57
+ it "last_of_split returns last part after colon" do
58
+ expect(element.send(:last_of_split, "foo:Bar")).to eq("Bar")
59
+ expect(element.send(:last_of_split, "Bar")).to eq("Bar")
60
+ expect(element.send(:last_of_split, nil)).to be_nil
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,86 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Lutaml::Model::Schema::XmlCompiler::Group do
4
+ let(:group) { described_class.new("GroupName", nil) }
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
+
13
+ describe "#initialize" do
14
+ it "sets name and ref" do
15
+ g = described_class.new("foo", "bar")
16
+ expect(g.name).to eq("foo")
17
+ expect(g.ref).to eq("bar")
18
+ end
19
+ end
20
+
21
+ describe "#to_xml_mapping" do
22
+ it "returns import_model_mappings if ref is present" do
23
+ group.ref = "foo:Bar"
24
+ group.name = nil
25
+ expect(group.to_xml_mapping(" ")).to include("import_model_mappings :bar")
26
+ end
27
+
28
+ it "delegates to instance if ref is not present" do
29
+ instance = instance_double(dummy_class, to_xml_mapping: " map_element :foo, to: :foo\n")
30
+ group.instance = instance
31
+ group.ref = nil
32
+ expect(group.to_xml_mapping(" ")).to include("map_element :foo, to: :foo")
33
+ end
34
+ end
35
+
36
+ describe "#to_class" do
37
+ it "renders the group template" do
38
+ group.name = "GroupName"
39
+ group.instance = instance_double(dummy_class, to_attributes: " attribute :foo, :string\n", to_xml_mapping: " map_element :foo, to: :foo\n", required_files: [])
40
+ expect(group.to_class).to include("class GroupName")
41
+ expect(group.to_class).to include("attribute :foo, :string")
42
+ expect(group.to_class).to include("map_element :foo, to: :foo")
43
+ end
44
+ end
45
+
46
+ describe "#required_files" do
47
+ it "returns require_relative if name is blank and ref is present" do
48
+ group.name = nil
49
+ group.ref = "foo:Bar"
50
+ expect(group.required_files).to include("require_relative \"bar\"")
51
+ end
52
+
53
+ it "delegates to instance if name is present" do
54
+ instance = instance_double(dummy_class, required_files: "require 'foo'")
55
+ group.instance = instance
56
+ group.name = "GroupName"
57
+ group.ref = nil
58
+ expect(group.required_files).to eq("require 'foo'")
59
+ end
60
+ end
61
+
62
+ describe "#to_attributes" do
63
+ it "returns import_model_attributes if ref is present" do
64
+ group.ref = "foo:Bar"
65
+ group.name = nil
66
+ expect(group.to_attributes(" ")).to include("import_model_attributes :bar")
67
+ end
68
+
69
+ it "delegates to instance if ref is not present" do
70
+ instance = instance_double(dummy_class, to_attributes: " attribute :foo, :string\n")
71
+ group.instance = instance
72
+ group.ref = nil
73
+ expect(group.to_attributes(" ")).to include("attribute :foo, :string")
74
+ end
75
+ end
76
+
77
+ describe "#base_name" do
78
+ it "returns last part of name or ref" do
79
+ group.name = "foo:Bar"
80
+ expect(group.base_name).to eq("Bar")
81
+ group.name = nil
82
+ group.ref = "foo:Baz"
83
+ expect(group.base_name).to eq("Baz")
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,76 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Lutaml::Model::Schema::XmlCompiler::Restriction do
4
+ let(:restriction) { described_class.new }
5
+
6
+ describe "attribute accessors" do
7
+ it "allows reading and writing all attributes" do
8
+ restriction.min_inclusive = 1
9
+ restriction.max_inclusive = 10
10
+ restriction.min_exclusive = 2
11
+ restriction.max_exclusive = 9
12
+ restriction.enumerations = ["A", "B"]
13
+ restriction.max_length = 5
14
+ restriction.min_length = 1
15
+ restriction.base_class = "foo:Bar"
16
+ restriction.pattern = /abc/
17
+ restriction.length = 3
18
+ restriction.transform = "value.upcase"
19
+ expect(restriction.min_inclusive).to eq(1)
20
+ expect(restriction.max_inclusive).to eq(10)
21
+ expect(restriction.enumerations).to eq(["A", "B"])
22
+ expect(restriction.pattern).to eq(/abc/)
23
+ expect(restriction.transform).to eq("value.upcase")
24
+ end
25
+ end
26
+
27
+ describe "#to_method_body" do
28
+ it "returns method body for all present attributes" do
29
+ restriction.enumerations = ["A", "B"]
30
+ restriction.min_inclusive = 1
31
+ restriction.max_inclusive = 10
32
+ restriction.pattern = /abc/
33
+ restriction.transform = "value.upcase"
34
+ body = restriction.to_method_body(" ")
35
+ expect(body).to include("options[:values]")
36
+ expect(body).to include("options[:min]")
37
+ expect(body).to include("options[:max]")
38
+ expect(body).to include("options[:pattern]")
39
+ expect(body).to include("value = value.upcase")
40
+ end
41
+
42
+ it "returns empty string if no attributes are set" do
43
+ expect(restriction.to_method_body(" ")).to eq("")
44
+ end
45
+ end
46
+
47
+ describe "#required_files" do
48
+ it "returns require 'bigdecimal' for decimal base_class" do
49
+ restriction.base_class = "decimal"
50
+ expect(restriction.required_files).to eq("require \"bigdecimal\"")
51
+ end
52
+
53
+ it "returns require_relative for non-skippable base_class" do
54
+ restriction.base_class = "foo:Base"
55
+ expect(restriction.required_files).to eq("require_relative \"base\"")
56
+ end
57
+
58
+ it "returns nil for skippable base_class" do
59
+ restriction.base_class = "string"
60
+ expect(restriction.required_files).to be_nil
61
+ end
62
+ end
63
+
64
+ describe "private methods" do
65
+ it "base_class_name returns last part as symbol" do
66
+ restriction.base_class = "foo:Bar"
67
+ expect(restriction.send(:base_class_name)).to eq(:Bar)
68
+ end
69
+
70
+ it "casted_enumerations returns super calls for each enumeration" do
71
+ restriction.enumerations = ["A", "B"]
72
+ expect(restriction.send(:casted_enumerations)).to include("super(\"A\")")
73
+ expect(restriction.send(:casted_enumerations)).to include("super(\"B\")")
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,59 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Lutaml::Model::Schema::XmlCompiler::Sequence do
4
+ let(:sequence) { described_class.new }
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
+
13
+ describe "#initialize" do
14
+ it "starts with empty instances" do
15
+ expect(sequence.instances).to eq([])
16
+ end
17
+ end
18
+
19
+ describe "#<<" do
20
+ it "adds instances to the list" do
21
+ instance = instance_double(dummy_class, to_attributes: " attribute :foo, :string\n", to_xml_mapping: " map_element :foo, to: :foo\n", required_files: "require 'foo'")
22
+ expect { sequence << instance }.to change { sequence.instances.size }.by(1)
23
+ expect(sequence.instances).to include(instance)
24
+ end
25
+
26
+ it "ignores nil instances" do
27
+ expect { sequence << nil }.not_to(change { sequence.instances.size })
28
+ end
29
+ end
30
+
31
+ describe "#to_attributes" do
32
+ it "returns joined attributes from instances" do
33
+ instance = instance_double(dummy_class, to_attributes: " attribute :foo, :string\n")
34
+ sequence << instance
35
+ expect(sequence.to_attributes(" ")).to include("attribute :foo, :string")
36
+ end
37
+ end
38
+
39
+ describe "#to_xml_mapping" do
40
+ it "returns empty string if no content" do
41
+ expect(sequence.to_xml_mapping(" ")).to eq("")
42
+ end
43
+
44
+ it "returns xml mapping block if content exists" do
45
+ instance = instance_double(dummy_class, to_xml_mapping: " map_element :foo, to: :foo\n")
46
+ sequence << instance
47
+ expect(sequence.to_xml_mapping(" ")).to include("sequence do")
48
+ expect(sequence.to_xml_mapping(" ")).to include("map_element :foo, to: :foo")
49
+ end
50
+ end
51
+
52
+ describe "#required_files" do
53
+ it "collects required_files from all instances" do
54
+ instance = instance_double(dummy_class, required_files: "require 'foo'")
55
+ sequence << instance
56
+ expect(sequence.required_files).to include("require 'foo'")
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,55 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe Lutaml::Model::Schema::XmlCompiler::SimpleContent do
4
+ let(:simple_content) { described_class.new }
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
+
13
+ describe "#initialize" do
14
+ it "starts with empty instances and nil base_class" do
15
+ expect(simple_content.instances).to eq([])
16
+ expect(simple_content.base_class).to be_nil
17
+ end
18
+ end
19
+
20
+ describe "#<<" do
21
+ it "adds instances to the list" do
22
+ instance = instance_double(dummy_class, to_attributes: "attr", to_xml_mapping: "xml", required_files: "files")
23
+ expect { simple_content << instance }.to change { simple_content.instances.size }.by(1)
24
+ expect(simple_content.instances).to include(instance)
25
+ end
26
+
27
+ it "ignores nil instances" do
28
+ expect { simple_content << nil }.not_to(change { simple_content.instances.size })
29
+ end
30
+ end
31
+
32
+ describe "#to_attributes" do
33
+ it "returns joined attributes from instances" do
34
+ instance = instance_double(dummy_class, to_attributes: "attr")
35
+ simple_content << instance
36
+ expect(simple_content.to_attributes(" ")).to include("attr")
37
+ end
38
+ end
39
+
40
+ describe "#to_xml_mapping" do
41
+ it "returns joined xml mappings from instances" do
42
+ instance = instance_double(dummy_class, to_xml_mapping: "xml")
43
+ simple_content << instance
44
+ expect(simple_content.to_xml_mapping(" ")).to include("xml")
45
+ end
46
+ end
47
+
48
+ describe "#required_files" do
49
+ it "collects required_files from all instances" do
50
+ instance = instance_double(dummy_class, required_files: "files")
51
+ simple_content << instance
52
+ expect(simple_content.required_files).to include("files")
53
+ end
54
+ end
55
+ end