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,228 @@
1
+ = LutaML Registers
2
+
3
+ == Introduction
4
+
5
+ There are three types of registers in Lutaml::Model:
6
+
7
+ 1. *TypeRegister*
8
+ 2. *ModelRegister*
9
+ 3. *GlobalRegister*
10
+
11
+ === TypeRegister
12
+
13
+ The TypeRegister is a registry class that registers and looks up the `Lutaml::Model::Type::Value` classes only.
14
+
15
+ ==== Register a Type::Value class
16
+
17
+ The following syntax registers a `Type::Value` class:
18
+ ```ruby
19
+ # assuming we have a `CustomString` class that inherits from Lutaml::Model::Type::Value
20
+ Lutaml::Model::Type.register(:custom_string, Lutaml::Model::Type::CustomString)
21
+ ```
22
+ NOTE: `TypeError` is raised if the class does not inherit from `Lutaml::Model::Type::Value`.
23
+
24
+ ==== Lookup a *Type::Value* class
25
+ Lookup a `Type::Value` class using the assigned name:
26
+ ```ruby
27
+ Lutaml::Model::Type.lookup(:custom_string) # returns Lutaml::Model::Type::CustomString
28
+ ```
29
+
30
+ NOTE: `Lutaml::Model::Type::UnknownTypeError` is raised if the name is not found in the registry.
31
+
32
+ When looking up a class, the class is returned without looking up in the registry.
33
+
34
+ ```ruby
35
+ Lutaml::Model::Type.lookup(Lutaml::Model::Type::CustomString) # returns Lutaml::Model::Type::CustomString even if it's not registered in the registry
36
+ ```
37
+
38
+ === ModelRegister
39
+
40
+ The *ModelRegister* is a registry class that registers and looks up the `Lutaml::Model::Registrable` classes (by default, `Lutaml::Model::Serializable` classes are `Registrable` classes). For consistency, the `Lutaml::Model::Type::Value` classes are registered similarly, but within the TypeRegister registry, as referenced in the <<TypeRegister, previous section>>.
41
+
42
+ NOTE: Make sure to register the ModelRegister in GlobalRegister before using it.
43
+
44
+ ==== Register a Class
45
+
46
+ Register a Model class using the following syntax:
47
+ ```ruby
48
+ # assuming we have a `CustomModel` class that inherits from Lutaml::Model::Serializable
49
+ Lutaml::Model::Register.register_model(Lutaml::Model::CustomModel, id: :custom_model)
50
+ ```
51
+ This method `register_model` registers the class and assigns it the passed ID, which is `:custom_model` in this case. But if a model is registered without an ID, the class name is used as the ID. For example:
52
+ ```ruby
53
+ Lutaml::Model::Register.register_model(Lutaml::Model::AnotherCustomModel)
54
+ ```
55
+
56
+ This will register the class `AnotherCustomModel` with the ID `:another_custom_model`.
57
+
58
+ ==== Register model tree
59
+
60
+ The `register_model_tree` method registers all the classes in the provided Model's hierarchy. For example:
61
+ ```ruby
62
+ register = Lutaml::Model::Register.new(:v1)
63
+
64
+ module Mathml
65
+ class Mrow < Lutaml::Model::Serializable
66
+ attribute :mstyle, Mstyle
67
+ end
68
+
69
+ class Mstyle < Lutaml::Model::Serializable
70
+ attribute :mi, :string
71
+ end
72
+
73
+ class Math < Lutaml::Model::Serializable
74
+ attribute :mrow, Mrow
75
+ attribute :mstyle, Mstyle
76
+ end
77
+ end
78
+
79
+ register.register_model_tree(Mathml::Math) # registers all the classes in the Mathml::Math model tree, in this case Mathml::Mstyle and Mathml::Mrow
80
+ ```
81
+
82
+ ==== Lookup a Class
83
+
84
+ Lookup a Model class using the assigned name:
85
+ ```ruby
86
+ register = Lutaml::Model::Register.new(:v1)
87
+ register.get_class(:custom_model) # returns Lutaml::Model::CustomModel
88
+ ```
89
+ The class returned from the `get_class` method is also aware of the *ModelRegister* it was registered in. This is useful when you want to use the class directly. For example:
90
+
91
+ ```ruby
92
+ register = Lutaml::Model::Register.new(:v1)
93
+ json_hash = {
94
+ "mstyle": {
95
+ "mrow": {
96
+ "mi": "x",
97
+ "mo": "+"
98
+ }
99
+ },
100
+ "mrow": {
101
+ "mi": "z",
102
+ }
103
+ }
104
+ module Mathml
105
+ class Mrow < Lutaml::Model::Serializable
106
+ attribute :mi, :string
107
+ attribute :mo, :string
108
+ end
109
+ class Mstyle < Lutaml::Model::Serializable
110
+ attribute :mrow, Mrow
111
+ attribute :mi, :string
112
+ attribute :mo, :string
113
+ end
114
+ class Math < Lutaml::Model::Serializable
115
+ attribute :mrow, Mrow
116
+ attribute :mstyle, Mstyle
117
+ end
118
+ end
119
+ register.register_model_tree(Mathml::Math) # registers all the classes in the Mathml::Math model tree, in this case Mstyle and Mrow
120
+ # lookup the class and call the desired method, in current case from_json
121
+ register.get_class(:math).from_json(json_hash.to_json)
122
+ > #<Testing::Math:0x00000002ccd5a678
123
+ @mrow=#<Testing::Mrow:0x00000002cc50a1f8 @mi="z", @mo=nil>,
124
+ @mstyle=#<Testing::Mstyle:0x00000002cc50a108 @mi=nil, @mo=nil, @mrow=#<Testing::Mrow:0x00000002cc509fc8 @mi="x", @mo="+">>>
125
+ ```
126
+
127
+ NOTE: If the class is not found in either the `ModelRegister` or the `TypeRegister`, a `Lutaml::Model::UnknownTypeError` is raised.
128
+
129
+ ==== Global Type substitution
130
+
131
+ The `Lutaml::Model::Register` class also provides a method to substitute a type globally. This is useful when you want to replace a type with another type in the entire model tree. For example:
132
+
133
+ ```ruby
134
+ register = Lutaml::Model::Register.new(:v1)
135
+ json_hash = {
136
+ "mstyle": {
137
+ "mrow": {
138
+ "mi": "x",
139
+ "mo": "+"
140
+ }
141
+ },
142
+ "mrow": {
143
+ "mi": "z",
144
+ "mstyle": {
145
+ "mrow": {
146
+ "mi": "x",
147
+ "mo": "+"
148
+ }
149
+ }
150
+ }
151
+ }
152
+ module Mathml
153
+ class String < Lutaml::Model::Type::Value
154
+ def to_json(*args)
155
+ "custom-string: #{super(*args).to_json}"
156
+ end
157
+ end
158
+
159
+ class Mrow < Lutaml::Model::Serializable
160
+ attribute :mi, :string
161
+ attribute :mo, :string
162
+ end
163
+ class Mstyle < Lutaml::Model::Serializable
164
+ attribute :mrow, Mrow
165
+ attribute :mi, :string
166
+ attribute :mo, :string
167
+ end
168
+ class Math < Lutaml::Model::Serializable
169
+ attribute :mrow, Mrow
170
+ attribute :mstyle, Mstyle
171
+ end
172
+
173
+ class ExtendedMrow < Mrow
174
+ attribute :mstyle, :mstyle
175
+ end
176
+ end
177
+ register.register_model_tree(Mathml::Math) # registers all the classes in the Mathml::Math model tree, in this case Mstyle and Mrow
178
+ # Substitute the Mrow class with the ExtendedMrow class globally
179
+ register.register_global_type_substitution(
180
+ from_type: Mathml::Mrow,
181
+ to_type: Mathml::ExtendedMrow
182
+ ) # this will replace all instances of Mrow with ExtendedMrow in the entire model tree for this register
183
+ register.register_global_type_substitution(
184
+ from_type: Lutaml::Model::Type::String,
185
+ to_type: Mathml::String
186
+ )
187
+ # lookup the class and call the desired method, in current case from_json
188
+ models = register.get_class(:math).from_json(json_hash.to_json)
189
+ models.to_json
190
+ > "{\"mrow\":{\"mi\":\"custom-string: \\\"z\\\"\",\"mstyle\":{\"mrow\":{\"mi\":\"custom-string: \\\"x\\\"\",\"mo\":\"custom-string: \\\"+\\\"\"}}},\"mstyle\":{\"mrow\":{\"mi\":\"custom-string: \\\"x\\\"\",\"mo\":\"custom-string: \\\"+\\\"\"}}}"
191
+ ```
192
+
193
+ ==== Resolve a class
194
+
195
+ The `resolve` method resolves a class passed as a string if registered in the ModelRegister. For example:
196
+
197
+ ```ruby
198
+ register = Lutaml::Model::Register.new(:v1)
199
+ register.register_model(Mathml::Math, id: :math)
200
+ register.resolve("Mathml::Math") # returns Lutaml::Model::Math
201
+ ```
202
+
203
+ === GlobalRegister
204
+
205
+ The GlobalRegister is a singleton that registers all the ModelRegisters.
206
+ Model registers can be registered using the following syntax:
207
+
208
+ ```ruby
209
+ v1_register = Lutaml::Model::Register.new(:v1)
210
+ global_register = Lutaml::Model::GlobalRegister
211
+ global_register.register(v1_register) # register a Model register
212
+ # OR
213
+ global_register.instance.register(v1_register) # register a Model register
214
+ ```
215
+
216
+ The `register` method registers the ModelRegister based on its ID. The ID is used to look up the ModelRegister using the following syntax:
217
+ ```ruby
218
+ global_register.lookup(:v2) # fetch a Model register
219
+ # OR
220
+ global_register.instance.lookup(:v2) # fetch a Model register
221
+ ```
222
+
223
+ If a register is not needed anymore, it can be removed using the following syntax:
224
+ ```ruby
225
+ global_register.remove(:v1) # remove a ModelRegister using the its ID
226
+ # OR
227
+ global_register.instance.remove(:v1) # remove a ModelRegister using the it's ID
228
+ ```