lutaml-model 0.7.1 → 0.7.7

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 (259) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +1 -0
  3. data/.github/workflows/dependent-tests.yml +4 -0
  4. data/.github/workflows/rake.yml +12 -0
  5. data/.github/workflows/release.yml +3 -0
  6. data/.gitignore +6 -1
  7. data/.irbrc +1 -0
  8. data/.pryrc +1 -0
  9. data/.rubocop.yml +1 -1
  10. data/.rubocop_todo.yml +58 -84
  11. data/Gemfile +4 -1
  12. data/README.adoc +3115 -365
  13. data/RELEASE_NOTES.adoc +346 -0
  14. data/docs/custom_adapters.adoc +144 -0
  15. data/docs/custom_registers.adoc +228 -0
  16. data/docs/schema_generation.adoc +898 -0
  17. data/docs/schema_import.adoc +364 -0
  18. data/flake.lock +114 -0
  19. data/flake.nix +103 -0
  20. data/lib/lutaml/model/attribute.rb +242 -100
  21. data/lib/lutaml/model/choice.rb +30 -0
  22. data/lib/lutaml/model/collection.rb +212 -0
  23. data/lib/lutaml/model/comparable_model.rb +3 -3
  24. data/lib/lutaml/model/config.rb +71 -42
  25. data/lib/lutaml/model/constants.rb +2 -0
  26. data/lib/lutaml/model/error/element_count_out_of_range_error.rb +29 -0
  27. data/lib/lutaml/model/error/invalid_attribute_name_error.rb +15 -0
  28. data/lib/lutaml/model/error/invalid_attribute_options_error.rb +16 -0
  29. data/lib/lutaml/model/error/invalid_choice_range_error.rb +3 -5
  30. data/lib/lutaml/model/error/polymorphic_error.rb +7 -2
  31. data/lib/lutaml/model/error/register/not_registrable_class_error.rb +11 -0
  32. data/lib/lutaml/model/error/type/invalid_value_error.rb +5 -3
  33. data/lib/lutaml/model/error/type/max_bound_error.rb +20 -0
  34. data/lib/lutaml/model/error/type/max_length_error.rb +20 -0
  35. data/lib/lutaml/model/error/type/min_bound_error.rb +20 -0
  36. data/lib/lutaml/model/error/type/min_length_error.rb +20 -0
  37. data/lib/lutaml/model/error/type/pattern_not_matched_error.rb +18 -0
  38. data/lib/lutaml/model/error/validation_failed_error.rb +9 -0
  39. data/lib/lutaml/model/error.rb +10 -0
  40. data/lib/lutaml/model/errors.rb +36 -0
  41. data/lib/lutaml/model/format_registry.rb +44 -0
  42. data/lib/lutaml/model/global_register.rb +41 -0
  43. data/lib/lutaml/model/hash_adapter/document.rb +11 -0
  44. data/lib/lutaml/model/hash_adapter/mapping.rb +19 -0
  45. data/lib/lutaml/model/hash_adapter/mapping_rule.rb +9 -0
  46. data/lib/lutaml/model/hash_adapter/standard_adapter.rb +17 -0
  47. data/lib/lutaml/model/hash_adapter/transform.rb +8 -0
  48. data/lib/lutaml/model/hash_adapter.rb +21 -0
  49. data/lib/lutaml/model/json/document.rb +11 -0
  50. data/lib/lutaml/model/json/mapping.rb +19 -0
  51. data/lib/lutaml/model/json/mapping_rule.rb +9 -0
  52. data/lib/lutaml/model/{json_adapter → json}/multi_json_adapter.rb +4 -5
  53. data/lib/lutaml/model/{json_adapter/standard_json_adapter.rb → json/standard_adapter.rb} +5 -3
  54. data/lib/lutaml/model/json/transform.rb +8 -0
  55. data/lib/lutaml/model/json.rb +21 -0
  56. data/lib/lutaml/model/jsonl/document.rb +14 -0
  57. data/lib/lutaml/model/jsonl/mapping.rb +19 -0
  58. data/lib/lutaml/model/jsonl/mapping_rule.rb +9 -0
  59. data/lib/lutaml/model/jsonl/standard_adapter.rb +33 -0
  60. data/lib/lutaml/model/jsonl/transform.rb +19 -0
  61. data/lib/lutaml/model/jsonl.rb +21 -0
  62. data/lib/lutaml/model/key_value_document.rb +28 -0
  63. data/lib/lutaml/model/mapping/key_value_mapping.rb +85 -13
  64. data/lib/lutaml/model/mapping/key_value_mapping_rule.rb +5 -0
  65. data/lib/lutaml/model/mapping/mapping.rb +13 -0
  66. data/lib/lutaml/model/mapping/mapping_rule.rb +15 -9
  67. data/lib/lutaml/model/register.rb +105 -0
  68. data/lib/lutaml/model/{toml_adapter.rb → registrable.rb} +1 -1
  69. data/lib/lutaml/model/schema/base_schema.rb +64 -0
  70. data/lib/lutaml/model/schema/decorators/attribute.rb +114 -0
  71. data/lib/lutaml/model/schema/decorators/choices.rb +31 -0
  72. data/lib/lutaml/model/schema/decorators/class_definition.rb +85 -0
  73. data/lib/lutaml/model/schema/decorators/definition_collection.rb +97 -0
  74. data/lib/lutaml/model/schema/generator/definition.rb +53 -0
  75. data/lib/lutaml/model/schema/generator/definitions_collection.rb +81 -0
  76. data/lib/lutaml/model/schema/generator/properties_collection.rb +63 -0
  77. data/lib/lutaml/model/schema/generator/property.rb +110 -0
  78. data/lib/lutaml/model/schema/generator/ref.rb +24 -0
  79. data/lib/lutaml/model/schema/helpers/template_helper.rb +49 -0
  80. data/lib/lutaml/model/schema/json_schema.rb +42 -49
  81. data/lib/lutaml/model/schema/relaxng_schema.rb +14 -10
  82. data/lib/lutaml/model/schema/renderer.rb +36 -0
  83. data/lib/lutaml/model/schema/shared_methods.rb +24 -0
  84. data/lib/lutaml/model/schema/templates/model.erb +9 -0
  85. data/lib/lutaml/model/schema/xml_compiler/attribute.rb +85 -0
  86. data/lib/lutaml/model/schema/xml_compiler/attribute_group.rb +45 -0
  87. data/lib/lutaml/model/schema/xml_compiler/choice.rb +65 -0
  88. data/lib/lutaml/model/schema/xml_compiler/complex_content.rb +27 -0
  89. data/lib/lutaml/model/schema/xml_compiler/complex_content_restriction.rb +34 -0
  90. data/lib/lutaml/model/schema/xml_compiler/complex_type.rb +136 -0
  91. data/lib/lutaml/model/schema/xml_compiler/element.rb +104 -0
  92. data/lib/lutaml/model/schema/xml_compiler/group.rb +97 -0
  93. data/lib/lutaml/model/schema/xml_compiler/restriction.rb +101 -0
  94. data/lib/lutaml/model/schema/xml_compiler/sequence.rb +50 -0
  95. data/lib/lutaml/model/schema/xml_compiler/simple_content.rb +36 -0
  96. data/lib/lutaml/model/schema/xml_compiler/simple_type.rb +189 -0
  97. data/lib/lutaml/model/schema/xml_compiler.rb +231 -587
  98. data/lib/lutaml/model/schema/xsd_schema.rb +12 -8
  99. data/lib/lutaml/model/schema/yaml_schema.rb +41 -35
  100. data/lib/lutaml/model/schema.rb +1 -0
  101. data/lib/lutaml/model/sequence.rb +60 -30
  102. data/lib/lutaml/model/serialization_adapter.rb +22 -0
  103. data/lib/lutaml/model/serialize.rb +296 -548
  104. data/lib/lutaml/model/services/base.rb +11 -0
  105. data/lib/lutaml/model/services/logger.rb +54 -0
  106. data/lib/lutaml/model/services/rule_value_extractor.rb +92 -0
  107. data/lib/lutaml/model/services/transformer.rb +48 -0
  108. data/lib/lutaml/model/services/type/validator/number.rb +25 -0
  109. data/lib/lutaml/model/services/type/validator/string.rb +52 -0
  110. data/lib/lutaml/model/services/type/validator.rb +43 -0
  111. data/lib/lutaml/model/services/validator.rb +145 -0
  112. data/lib/lutaml/model/services.rb +5 -0
  113. data/lib/lutaml/model/toml/document.rb +11 -0
  114. data/lib/lutaml/model/toml/mapping.rb +27 -0
  115. data/lib/lutaml/model/toml/mapping_rule.rb +9 -0
  116. data/lib/lutaml/model/{toml_adapter → toml}/toml_rb_adapter.rb +3 -3
  117. data/lib/lutaml/model/toml/tomlib_adapter.rb +19 -0
  118. data/lib/lutaml/model/toml/transform.rb +8 -0
  119. data/lib/lutaml/model/toml.rb +30 -0
  120. data/lib/lutaml/model/transform/key_value_transform.rb +297 -0
  121. data/lib/lutaml/model/transform/xml_transform.rb +228 -0
  122. data/lib/lutaml/model/transform.rb +93 -0
  123. data/lib/lutaml/model/type/boolean.rb +1 -1
  124. data/lib/lutaml/model/type/date.rb +1 -1
  125. data/lib/lutaml/model/type/date_time.rb +1 -1
  126. data/lib/lutaml/model/type/decimal.rb +11 -9
  127. data/lib/lutaml/model/type/float.rb +2 -1
  128. data/lib/lutaml/model/type/integer.rb +24 -21
  129. data/lib/lutaml/model/type/string.rb +4 -2
  130. data/lib/lutaml/model/type/time.rb +1 -1
  131. data/lib/lutaml/model/type/time_without_date.rb +1 -1
  132. data/lib/lutaml/model/type/value.rb +11 -10
  133. data/lib/lutaml/model/type.rb +5 -2
  134. data/lib/lutaml/model/uninitialized_class.rb +1 -1
  135. data/lib/lutaml/model/utils.rb +56 -4
  136. data/lib/lutaml/model/validation.rb +6 -4
  137. data/lib/lutaml/model/version.rb +1 -1
  138. data/lib/lutaml/model/{xml_adapter → xml}/builder/nokogiri.rb +2 -2
  139. data/lib/lutaml/model/{xml_adapter → xml}/builder/oga.rb +10 -10
  140. data/lib/lutaml/model/{xml_adapter → xml}/builder/ox.rb +1 -1
  141. data/lib/lutaml/model/{xml_adapter/xml_document.rb → xml/document.rb} +42 -25
  142. data/lib/lutaml/model/xml/element.rb +32 -0
  143. data/lib/lutaml/model/xml/mapping.rb +471 -0
  144. data/lib/lutaml/model/xml/mapping_rule.rb +149 -0
  145. data/lib/lutaml/model/xml/nokogiri_adapter.rb +234 -0
  146. data/lib/lutaml/model/{xml_adapter → xml}/oga/document.rb +1 -1
  147. data/lib/lutaml/model/{xml_adapter → xml}/oga/element.rb +7 -2
  148. data/lib/lutaml/model/xml/oga_adapter.rb +172 -0
  149. data/lib/lutaml/model/xml/ox_adapter.rb +229 -0
  150. data/lib/lutaml/model/xml/transform.rb +8 -0
  151. data/lib/lutaml/model/{xml_adapter → xml}/xml_attribute.rb +1 -1
  152. data/lib/lutaml/model/{xml_adapter → xml}/xml_element.rb +9 -31
  153. data/lib/lutaml/model/{xml_adapter → xml}/xml_namespace.rb +1 -1
  154. data/lib/lutaml/model/xml.rb +31 -0
  155. data/lib/lutaml/model/xml_adapter/element.rb +11 -25
  156. data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +6 -223
  157. data/lib/lutaml/model/xml_adapter/oga_adapter.rb +13 -163
  158. data/lib/lutaml/model/xml_adapter/ox_adapter.rb +10 -207
  159. data/lib/lutaml/model/yaml/document.rb +10 -0
  160. data/lib/lutaml/model/yaml/mapping.rb +19 -0
  161. data/lib/lutaml/model/yaml/mapping_rule.rb +9 -0
  162. data/lib/lutaml/model/{yaml_adapter/standard_yaml_adapter.rb → yaml/standard_adapter.rb} +4 -3
  163. data/lib/lutaml/model/yaml/transform.rb +8 -0
  164. data/lib/lutaml/model/yaml.rb +21 -0
  165. data/lib/lutaml/model/yamls/document.rb +14 -0
  166. data/lib/lutaml/model/yamls/mapping.rb +19 -0
  167. data/lib/lutaml/model/yamls/mapping_rule.rb +9 -0
  168. data/lib/lutaml/model/yamls/standard_adapter.rb +34 -0
  169. data/lib/lutaml/model/yamls/transform.rb +19 -0
  170. data/lib/lutaml/model/yamls.rb +21 -0
  171. data/lib/lutaml/model.rb +15 -4
  172. data/lutaml-model.gemspec +0 -4
  173. data/spec/benchmarks/xml_parsing_benchmark_spec.rb +5 -6
  174. data/spec/fixtures/xml/advanced_test_schema.xsd +134 -0
  175. data/spec/fixtures/xml/examples/nested_categories.xml +55 -0
  176. data/spec/fixtures/xml/examples/valid_catalog.xml +43 -0
  177. data/spec/fixtures/xml/product_catalog.xsd +151 -0
  178. data/spec/fixtures/xml/specifications_schema.xsd +38 -0
  179. data/spec/lutaml/model/attribute_collection_spec.rb +101 -0
  180. data/spec/lutaml/model/attribute_spec.rb +41 -44
  181. data/spec/lutaml/model/cdata_spec.rb +7 -7
  182. data/spec/lutaml/model/choice_spec.rb +44 -0
  183. data/spec/lutaml/model/custom_bibtex_adapter_spec.rb +598 -0
  184. data/spec/lutaml/model/custom_collection_spec.rb +830 -0
  185. data/spec/lutaml/model/custom_vobject_adapter_spec.rb +1226 -0
  186. data/spec/lutaml/model/global_register_spec.rb +108 -0
  187. data/spec/lutaml/model/group_spec.rb +27 -10
  188. data/spec/lutaml/model/hash/adapter_spec.rb +255 -0
  189. data/spec/lutaml/model/json_adapter_spec.rb +6 -6
  190. data/spec/lutaml/model/jsonl/standard_adapter_spec.rb +91 -0
  191. data/spec/lutaml/model/jsonl_spec.rb +229 -0
  192. data/spec/lutaml/model/key_value_mapping_spec.rb +25 -1
  193. data/spec/lutaml/model/mixed_content_spec.rb +24 -24
  194. data/spec/lutaml/model/multiple_mapping_spec.rb +6 -6
  195. data/spec/lutaml/model/ordered_content_spec.rb +6 -6
  196. data/spec/lutaml/model/polymorphic_spec.rb +178 -0
  197. data/spec/lutaml/model/register/key_value_spec.rb +275 -0
  198. data/spec/lutaml/model/register/xml_spec.rb +185 -0
  199. data/spec/lutaml/model/register_spec.rb +147 -0
  200. data/spec/lutaml/model/root_mappings_spec.rb +3 -3
  201. data/spec/lutaml/model/rule_value_extractor_spec.rb +162 -0
  202. data/spec/lutaml/model/schema/generator/definitions_collection_spec.rb +120 -0
  203. data/spec/lutaml/model/schema/json_schema_spec.rb +412 -51
  204. data/spec/lutaml/model/schema/json_schema_to_models_spec.rb +383 -0
  205. data/spec/lutaml/model/schema/xml_compiler/attribute_group_spec.rb +65 -0
  206. data/spec/lutaml/model/schema/xml_compiler/attribute_spec.rb +63 -0
  207. data/spec/lutaml/model/schema/xml_compiler/choice_spec.rb +71 -0
  208. data/spec/lutaml/model/schema/xml_compiler/complex_content_restriction_spec.rb +55 -0
  209. data/spec/lutaml/model/schema/xml_compiler/complex_content_spec.rb +37 -0
  210. data/spec/lutaml/model/schema/xml_compiler/complex_type_spec.rb +173 -0
  211. data/spec/lutaml/model/schema/xml_compiler/element_spec.rb +63 -0
  212. data/spec/lutaml/model/schema/xml_compiler/group_spec.rb +86 -0
  213. data/spec/lutaml/model/schema/xml_compiler/restriction_spec.rb +76 -0
  214. data/spec/lutaml/model/schema/xml_compiler/sequence_spec.rb +59 -0
  215. data/spec/lutaml/model/schema/xml_compiler/simple_content_spec.rb +55 -0
  216. data/spec/lutaml/model/schema/xml_compiler/simple_type_spec.rb +181 -0
  217. data/spec/lutaml/model/schema/xml_compiler_spec.rb +503 -1804
  218. data/spec/lutaml/model/schema/yaml_schema_spec.rb +249 -26
  219. data/spec/lutaml/model/sequence_spec.rb +36 -0
  220. data/spec/lutaml/model/serializable_spec.rb +201 -94
  221. data/spec/lutaml/model/toml_adapter_spec.rb +6 -6
  222. data/spec/lutaml/model/toml_spec.rb +51 -0
  223. data/spec/lutaml/model/transformation_spec.rb +72 -15
  224. data/spec/lutaml/model/type_spec.rb +8 -4
  225. data/spec/lutaml/model/uninitialized_class_spec.rb +96 -0
  226. data/spec/lutaml/model/utils_spec.rb +3 -3
  227. data/spec/lutaml/model/xml/derived_attributes_spec.rb +1 -1
  228. data/spec/lutaml/model/xml/namespace_spec.rb +57 -0
  229. data/spec/lutaml/model/xml/root_mappings/nested_child_mappings_spec.rb +217 -0
  230. data/spec/lutaml/model/xml/xml_element_spec.rb +7 -1
  231. data/spec/lutaml/model/xml_adapter/nokogiri_adapter_spec.rb +2 -2
  232. data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +2 -2
  233. data/spec/lutaml/model/xml_adapter/ox_adapter_spec.rb +2 -2
  234. data/spec/lutaml/model/xml_adapter/xml_namespace_spec.rb +12 -12
  235. data/spec/lutaml/model/xml_adapter_spec.rb +30 -6
  236. data/spec/lutaml/model/xml_mapping_rule_spec.rb +14 -7
  237. data/spec/lutaml/model/xml_mapping_spec.rb +27 -15
  238. data/spec/lutaml/model/xml_spec.rb +63 -0
  239. data/spec/lutaml/model/yaml_adapter_spec.rb +3 -5
  240. data/spec/lutaml/model/yamls/standard_adapter_spec.rb +183 -0
  241. data/spec/lutaml/model/yamls_spec.rb +294 -0
  242. data/spec/spec_helper.rb +4 -3
  243. metadata +162 -60
  244. data/lib/lutaml/model/json_adapter/json_document.rb +0 -20
  245. data/lib/lutaml/model/json_adapter/json_object.rb +0 -28
  246. data/lib/lutaml/model/loggable.rb +0 -15
  247. data/lib/lutaml/model/mapping/json_mapping.rb +0 -17
  248. data/lib/lutaml/model/mapping/toml_mapping.rb +0 -25
  249. data/lib/lutaml/model/mapping/xml_mapping.rb +0 -389
  250. data/lib/lutaml/model/mapping/xml_mapping_rule.rb +0 -139
  251. data/lib/lutaml/model/mapping/yaml_mapping.rb +0 -17
  252. data/lib/lutaml/model/mapping.rb +0 -14
  253. data/lib/lutaml/model/schema/templates/simple_type.rb +0 -247
  254. data/lib/lutaml/model/toml_adapter/toml_document.rb +0 -20
  255. data/lib/lutaml/model/toml_adapter/toml_object.rb +0 -28
  256. data/lib/lutaml/model/toml_adapter/tomlib_adapter.rb +0 -20
  257. data/lib/lutaml/model/yaml_adapter/yaml_document.rb +0 -20
  258. data/lib/lutaml/model/yaml_adapter/yaml_object.rb +0 -28
  259. data/lib/lutaml/model/yaml_adapter.rb +0 -8
@@ -1,214 +1,17 @@
1
- require "ox"
2
- require_relative "xml_document"
3
- require_relative "builder/ox"
1
+ # require "ox"
2
+ # require_relative "xml_document"
3
+ # require_relative "builder/ox"
4
+
5
+ require_relative "../xml/ox_adapter"
4
6
 
5
7
  module Lutaml
6
8
  module Model
7
9
  module XmlAdapter
8
- class OxAdapter < XmlDocument
9
- def self.parse(xml, options = {})
10
- Ox.default_options = Ox.default_options.merge(encoding: encoding(xml, options))
11
-
12
- parsed = Ox.parse(xml)
13
- @root = OxElement.new(parsed)
14
- new(@root, Ox.default_options[:encoding])
15
- end
16
-
17
- def to_xml(options = {})
18
- builder_options = { version: options[:version] }
19
-
20
- builder_options[:encoding] = if options.key?(:encoding)
21
- options[:encoding] unless options[:encoding].nil?
22
- elsif options.key?(:parse_encoding)
23
- options[:parse_encoding]
24
- else
25
- "UTF-8"
26
- end
27
-
28
- builder = Builder::Ox.build(builder_options)
29
- builder.xml.instruct(:xml, encoding: builder_options[:encoding])
30
-
31
- if @root.is_a?(Lutaml::Model::XmlAdapter::OxElement)
32
- @root.build_xml(builder)
33
- elsif ordered?(@root, options)
34
- build_ordered_element(builder, @root, options)
35
- else
36
- mapper_class = options[:mapper_class] || @root.class
37
- options[:xml_attributes] = build_namespace_attributes(mapper_class)
38
- build_element(builder, @root, options)
39
- end
40
-
41
- xml_data = builder.xml.to_s
42
- stripped_data = xml_data.lines.drop(1).join
43
- options[:declaration] ? declaration(options) + stripped_data : stripped_data
44
- end
45
-
46
- private
47
-
48
- def build_ordered_element(builder, element, options = {})
49
- mapper_class = determine_mapper_class(element, options)
50
- xml_mapping = mapper_class.mappings_for(:xml)
51
- return xml unless xml_mapping
52
-
53
- attributes = build_attributes(element, xml_mapping).compact
54
-
55
- tag_name = options[:tag_name] || xml_mapping.root_element
56
- builder.create_and_add_element(tag_name,
57
- attributes: attributes) do |el|
58
- index_hash = {}
59
- content = []
60
-
61
- element.element_order.each do |object|
62
- index_hash[object.name] ||= -1
63
- curr_index = index_hash[object.name] += 1
64
-
65
- element_rule = xml_mapping.find_by_name(object.name)
66
- next if element_rule.nil?
67
-
68
- attribute_def = attribute_definition_for(element, element_rule,
69
- mapper_class: mapper_class)
70
- value = attribute_value_for(element, element_rule)
71
-
72
- next if element_rule == xml_mapping.content_mapping && element_rule.cdata && object.text?
73
-
74
- if element_rule == xml_mapping.content_mapping
75
- text = element.send(xml_mapping.content_mapping.to)
76
- text = text[curr_index] if text.is_a?(Array)
77
-
78
- next el.add_text(el, text, cdata: element_rule.cdata) if element.mixed?
79
-
80
- content << text
81
- elsif !value.nil? || element_rule.render_nil?
82
- value = value[curr_index] if attribute_def.collection?
83
-
84
- add_to_xml(
85
- el,
86
- element,
87
- nil,
88
- value,
89
- options.merge(
90
- attribute: attribute_def,
91
- rule: element_rule,
92
- ),
93
- )
94
- end
95
- end
96
-
97
- el.add_text(el, content.join)
98
- end
99
- end
100
- end
101
-
102
- class OxElement < XmlElement
103
- def initialize(node, root_node: nil)
104
- case node
105
- when String
106
- super("text", {}, [], node, parent_document: root_node)
107
- when Ox::Comment
108
- super("comment", {}, [], node.value, parent_document: root_node)
109
- when Ox::CData
110
- super("#cdata-section", {}, [], node.value, parent_document: root_node)
111
- else
112
- namespace_attributes(node.attributes).each do |(name, value)|
113
- if root_node
114
- root_node.add_namespace(XmlNamespace.new(value, name))
115
- else
116
- add_namespace(XmlNamespace.new(value, name))
117
- end
118
- end
119
-
120
- attributes = node.attributes.each_with_object({}) do |(name, value), hash|
121
- next if attribute_is_namespace?(name)
122
-
123
- namespace_prefix = name.to_s.split(":").first
124
- if (n = name.to_s.split(":")).length > 1
125
- namespace = (root_node || self).namespaces[namespace_prefix]&.uri
126
- namespace ||= XML_NAMESPACE_URI
127
- prefix = n.first
128
- end
129
-
130
- hash[name.to_s] = XmlAttribute.new(
131
- name.to_s,
132
- value,
133
- namespace: namespace,
134
- namespace_prefix: prefix,
135
- )
136
- end
137
-
138
- super(
139
- node,
140
- attributes,
141
- parse_children(node, root_node: root_node || self),
142
- node.text,
143
- parent_document: root_node,
144
- )
145
- end
146
- end
147
-
148
- def to_xml
149
- return text if text?
150
-
151
- build_xml.xml.to_s
152
- end
153
-
154
- def inner_xml
155
- # Ox builder by default, adds a newline at the end, so `chomp` is used
156
- children.map { |child| child.to_xml.chomp }.join
157
- end
158
-
159
- def build_xml(builder = nil)
160
- builder ||= Builder::Ox.build
161
- attrs = build_attributes(self)
162
-
163
- if text?
164
- builder.add_text(builder, text)
165
- else
166
- builder.create_and_add_element(name, attributes: attrs) do |el|
167
- children.each { |child| child.build_xml(el) }
168
- end
169
- end
170
-
171
- builder
172
- end
173
-
174
- def namespace_attributes(attributes)
175
- attributes.select { |attr| attribute_is_namespace?(attr) }
176
- end
177
-
178
- def text?
179
- # false
180
- children.empty? && text&.length&.positive?
181
- end
182
-
183
- def build_attributes(node)
184
- attrs = node.attributes.transform_values(&:value)
185
-
186
- node.own_namespaces.each_value do |namespace|
187
- attrs[namespace.attr_name] = namespace.uri
188
- end
189
-
190
- attrs
191
- end
192
-
193
- def nodes
194
- children
195
- end
196
-
197
- def cdata
198
- super || cdata_children.first&.text
199
- end
200
-
201
- def text
202
- super || cdata
203
- end
204
-
205
- private
206
-
207
- def parse_children(node, root_node: nil)
208
- node.nodes.map do |child|
209
- OxElement.new(child, root_node: root_node)
210
- end
211
- end
10
+ class OxAdapter < ::Lutaml::Model::Xml::OxAdapter
11
+ Logger.warn_future_deprecation(
12
+ old: "Lutaml::Model::XmlAdapter::OxAdapter",
13
+ replacement: "Lutaml::Model::Xml::OxAdapter",
14
+ )
212
15
  end
213
16
  end
214
17
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Yaml
6
+ # Base class for YAML documents
7
+ class Document < Lutaml::Model::KeyValueDocument; end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,19 @@
1
+ require_relative "../mapping/key_value_mapping"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Yaml
6
+ class Mapping < Lutaml::Model::KeyValueMapping
7
+ def initialize
8
+ super(:yaml)
9
+ end
10
+
11
+ def deep_dup
12
+ self.class.new.tap do |new_mapping|
13
+ new_mapping.instance_variable_set(:@mappings, duplicate_mappings)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "../mapping/key_value_mapping_rule"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Yaml
6
+ class MappingRule < Lutaml::Model::KeyValueMappingRule; end
7
+ end
8
+ end
9
+ end
@@ -1,10 +1,11 @@
1
1
  require "yaml"
2
- require_relative "yaml_document"
2
+ require_relative "document"
3
3
 
4
4
  module Lutaml
5
5
  module Model
6
- module YamlAdapter
7
- class StandardYamlAdapter < YamlDocument
6
+ module Yaml
7
+ class StandardAdapter < Document
8
+ FORMAT_SYMBOL = :yaml
8
9
  PERMITTED_CLASSES_BASE = [Date, Time, DateTime, Symbol, Hash,
9
10
  Array].freeze
10
11
 
@@ -0,0 +1,8 @@
1
+ module Lutaml
2
+ module Model
3
+ module Yaml
4
+ class Transform < Lutaml::Model::KeyValueTransform
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Yaml
6
+ end
7
+ end
8
+ end
9
+
10
+ require_relative "yaml/standard_adapter"
11
+ require_relative "yaml/document"
12
+ require_relative "yaml/mapping"
13
+ require_relative "yaml/mapping_rule"
14
+ require_relative "yaml/transform"
15
+
16
+ Lutaml::Model::FormatRegistry.register(
17
+ :yaml,
18
+ mapping_class: Lutaml::Model::Yaml::Mapping,
19
+ adapter_class: Lutaml::Model::Yaml::StandardAdapter,
20
+ transformer: Lutaml::Model::Yaml::Transform,
21
+ )
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Yamls
6
+ class Document
7
+ def initialize(yamls = [], register: nil)
8
+ @yamls = yamls
9
+ @register = register || Lutaml::Model::Config.default_register
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,19 @@
1
+ require_relative "../mapping/key_value_mapping"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Yamls
6
+ class Mapping < Lutaml::Model::KeyValueMapping
7
+ def initialize
8
+ super(:yaml)
9
+ end
10
+
11
+ def deep_dup
12
+ self.class.new.tap do |new_mapping|
13
+ new_mapping.instance_variable_set(:@mappings, duplicate_mappings)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "../mapping/key_value_mapping_rule"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Yamls
6
+ class MappingRule < Lutaml::Model::KeyValueMappingRule; end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,34 @@
1
+ require "yaml"
2
+ require_relative "document"
3
+
4
+ module Lutaml
5
+ module Model
6
+ module Yamls
7
+ class StandardAdapter < Document
8
+ FORMAT_SYMBOL = :yaml
9
+
10
+ def self.parse(yamls, _options = {})
11
+ results = []
12
+
13
+ yamls.split(/^---\n/).each do |yaml|
14
+ next if yaml.strip.empty?
15
+
16
+ begin
17
+ results << YAML.safe_load(yaml, aliases: true)
18
+ rescue Psych::SyntaxError => e
19
+ warn "Skipping invalid yaml: #{e.message}"
20
+ end
21
+ end
22
+
23
+ results
24
+ end
25
+
26
+ def to_yamls(*_args)
27
+ @yamls.map do |yaml|
28
+ YAML.dump(yaml).strip
29
+ end.join("\n")
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ module Lutaml
2
+ module Model
3
+ module Yamls
4
+ class Transform < Lutaml::Model::KeyValueTransform
5
+ def data_to_model(data, format, options = {})
6
+ mappings = defined_mappings_for(:yamls) || mappings_for(:yaml)
7
+
8
+ super(data, format, options.merge(mappings: mappings))
9
+ end
10
+
11
+ def model_to_data(instance, format, options = {})
12
+ mappings = defined_mappings_for(:yamls) || mappings_for(:yaml)
13
+
14
+ super(instance, format, options.merge(mappings: mappings))
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Yamls
6
+ end
7
+ end
8
+ end
9
+
10
+ require_relative "yamls/standard_adapter"
11
+ require_relative "yamls/document"
12
+ require_relative "yamls/mapping"
13
+ require_relative "yamls/mapping_rule"
14
+ require_relative "yamls/transform"
15
+
16
+ Lutaml::Model::FormatRegistry.register(
17
+ :yamls,
18
+ mapping_class: Lutaml::Model::Yamls::Mapping,
19
+ adapter_class: Lutaml::Model::Yamls::StandardAdapter,
20
+ transformer: Lutaml::Model::Yamls::Transform,
21
+ )
data/lib/lutaml/model.rb CHANGED
@@ -2,17 +2,28 @@
2
2
 
3
3
  require "moxml"
4
4
  require_relative "model/uninitialized_class"
5
+ require_relative "model/errors"
6
+ require_relative "model/services"
5
7
  require_relative "model/version"
6
- require_relative "model/loggable"
7
8
  require_relative "model/type"
8
9
  require_relative "model/utils"
9
10
  require_relative "model/serializable"
10
- require_relative "model/json_adapter/standard_json_adapter"
11
- require_relative "model/yaml_adapter/standard_yaml_adapter"
12
11
  require_relative "model/xml_adapter"
13
- require_relative "model/toml_adapter"
14
12
  require_relative "model/error"
15
13
  require_relative "model/constants"
14
+ require_relative "model/config"
15
+ require_relative "model/global_register"
16
+ require_relative "model/register"
17
+ require_relative "model/format_registry"
18
+ require_relative "model/collection"
19
+ require_relative "model/key_value_document"
20
+ require_relative "model/yaml"
21
+ require_relative "model/yamls"
22
+ require_relative "model/json"
23
+ require_relative "model/jsonl"
24
+ require_relative "model/toml"
25
+ require_relative "model/hash_adapter"
26
+ require_relative "model/xml"
16
27
 
17
28
  module Lutaml
18
29
  module Model
data/lutaml-model.gemspec CHANGED
@@ -30,10 +30,6 @@ Gem::Specification.new do |spec|
30
30
  end
31
31
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
32
 
33
- # TODO: remove once https://github.com/Shopify/liquid/issues/1772 is fixed
34
- # needed for liquid with ruby 3.4
35
- spec.add_dependency "base64"
36
- spec.add_dependency "liquid", "~> 5"
37
33
  spec.add_dependency "moxml", ">= 0.1.2"
38
34
  spec.add_dependency "thor"
39
35
  spec.metadata["rubygems_mfa_required"] = "true"
@@ -1,11 +1,11 @@
1
1
  require "benchmark"
2
2
  require "benchmark/ips"
3
3
  require "lutaml/model"
4
- require "lutaml/model/xml_adapter/oga_adapter"
4
+ require "lutaml/model/xml/oga_adapter"
5
5
 
6
6
  RSpec.describe "LutaML Model Performance" do
7
7
  after do
8
- Lutaml::Model::Config.xml_adapter = Lutaml::Model::XmlAdapter::NokogiriAdapter
8
+ Lutaml::Model::Config.xml_adapter_type = :nokogiri
9
9
  end
10
10
 
11
11
  let(:large_xml) do
@@ -26,7 +26,6 @@ RSpec.describe "LutaML Model Performance" do
26
26
  map_attribute "id", to: :id
27
27
  map_element "value", to: :value
28
28
  map_element "name", to: :name
29
- map_element "value", to: :value
30
29
  end
31
30
  end
32
31
 
@@ -48,12 +47,12 @@ RSpec.describe "LutaML Model Performance" do
48
47
  end
49
48
 
50
49
  x.report("Ox Adapter") do
51
- Lutaml::Model::Config.xml_adapter = Lutaml::Model::XmlAdapter::OxAdapter
50
+ Lutaml::Model::Config.xml_adapter_type = :ox
52
51
  Deserializer.from_xml(large_xml)
53
52
  end
54
53
 
55
54
  x.report("Oga Adapter") do
56
- Lutaml::Model::Config.xml_adapter = Lutaml::Model::XmlAdapter::OgaAdapter
55
+ Lutaml::Model::Config.xml_adapter_type = :oga
57
56
  Deserializer.from_xml(large_xml)
58
57
  end
59
58
 
@@ -62,7 +61,7 @@ RSpec.describe "LutaML Model Performance" do
62
61
 
63
62
  thresholds = {
64
63
  "Nokogiri Adapter" => 3,
65
- "Ox Adapter" => 7,
64
+ "Ox Adapter" => 6,
66
65
  "Oga Adapter" => 3,
67
66
  }
68
67
 
@@ -0,0 +1,134 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
3
+ xmlns:test="http://www.example.com/test" targetNamespace="http://www.example.com/test" elementFormDefault="qualified">
4
+
5
+ <!-- Advanced Simple Types -->
6
+ <xs:simpleType name="StringOrInteger">
7
+ <xs:union memberTypes="xs:string xs:integer"/>
8
+ </xs:simpleType>
9
+
10
+ <xs:simpleType name="ColorList">
11
+ <xs:list itemType="xs:string"/>
12
+ </xs:simpleType>
13
+
14
+ <xs:simpleType name="RestrictedString">
15
+ <xs:restriction base="xs:string">
16
+ <xs:pattern value="[A-Z][a-z]+"/>
17
+ <xs:minLength value="2"/>
18
+ <xs:maxLength value="20"/>
19
+ </xs:restriction>
20
+ </xs:simpleType>
21
+
22
+ <!-- Base Complex Types -->
23
+ <xs:complexType name="BaseType">
24
+ <xs:sequence>
25
+ <xs:element name="id" type="xs:integer"/>
26
+ <xs:element name="name" type="test:RestrictedString"/>
27
+ </xs:sequence>
28
+ <xs:attribute name="version" type="xs:string" use="optional"/>
29
+ </xs:complexType>
30
+
31
+ <!-- Extension using complexContent -->
32
+ <xs:complexType name="ExtendedType">
33
+ <xs:complexContent>
34
+ <xs:extension base="test:BaseType">
35
+ <xs:sequence>
36
+ <xs:element name="description" type="xs:string"/>
37
+ <xs:element name="tags" type="test:ColorList"/>
38
+ </xs:sequence>
39
+ <xs:attribute name="priority" type="xs:integer" use="required"/>
40
+ </xs:extension>
41
+ </xs:complexContent>
42
+ </xs:complexType>
43
+
44
+ <!-- Restriction using complexContent -->
45
+ <xs:complexType name="RestrictedType">
46
+ <xs:complexContent>
47
+ <xs:restriction base="test:BaseType">
48
+ <xs:sequence>
49
+ <xs:element name="id" type="xs:positiveInteger"/>
50
+ <xs:element name="name" type="test:RestrictedString"/>
51
+ </xs:sequence>
52
+ <xs:attribute name="version" type="xs:string" fixed="1.0"/>
53
+ </xs:restriction>
54
+ </xs:complexContent>
55
+ </xs:complexType>
56
+
57
+ <!-- Mixed Content Type -->
58
+ <xs:complexType name="MixedContentType" mixed="true">
59
+ <xs:sequence>
60
+ <xs:element name="bold" type="xs:string" minOccurs="0"/>
61
+ <xs:element name="italic" type="xs:string" minOccurs="0"/>
62
+ </xs:sequence>
63
+ </xs:complexType>
64
+
65
+ <!-- Group Definitions -->
66
+ <xs:group name="CommonElements">
67
+ <xs:sequence>
68
+ <xs:element name="created" type="xs:dateTime"/>
69
+ <xs:element name="modified" type="xs:dateTime"/>
70
+ </xs:sequence>
71
+ </xs:group>
72
+
73
+ <!-- Attribute Group -->
74
+ <xs:attributeGroup name="CommonAttributes">
75
+ <xs:attribute name="id" type="xs:ID" use="required"/>
76
+ <xs:attribute name="type" type="xs:string" use="optional"/>
77
+ </xs:attributeGroup>
78
+
79
+ <!-- Complex Type with Groups -->
80
+ <xs:complexType name="GroupedType">
81
+ <xs:sequence>
82
+ <xs:group ref="test:CommonElements"/>
83
+ <xs:element name="content" type="xs:string"/>
84
+ </xs:sequence>
85
+ <xs:attributeGroup ref="test:CommonAttributes"/>
86
+ </xs:complexType>
87
+
88
+ <!-- Choice Element -->
89
+ <xs:complexType name="ChoiceType">
90
+ <xs:choice minOccurs="1" maxOccurs="unbounded">
91
+ <xs:element name="text" type="xs:string"/>
92
+ <xs:element name="number" type="xs:integer"/>
93
+ <xs:element name="date" type="xs:date"/>
94
+ </xs:choice>
95
+ </xs:complexType>
96
+
97
+ <!-- All Element -->
98
+ <xs:complexType name="AllType">
99
+ <xs:all>
100
+ <xs:element name="first" type="xs:string"/>
101
+ <xs:element name="second" type="xs:integer"/>
102
+ <xs:element name="third" type="xs:boolean"/>
103
+ </xs:all>
104
+ </xs:complexType>
105
+
106
+ <!-- Root Elements -->
107
+ <xs:element name="TestDocument">
108
+ <xs:complexType>
109
+ <xs:sequence>
110
+ <xs:element name="base" type="test:BaseType"/>
111
+ <xs:element name="extended" type="test:ExtendedType"/>
112
+ <xs:element name="restricted" type="test:RestrictedType"/>
113
+ <xs:element name="mixed" type="test:MixedContentType"/>
114
+ <xs:element name="grouped" type="test:GroupedType"/>
115
+ <xs:element name="choice" type="test:ChoiceType"/>
116
+ <xs:element name="all" type="test:AllType"/>
117
+ </xs:sequence>
118
+ </xs:complexType>
119
+ </xs:element>
120
+
121
+ <!-- Alternative Root with Substitution Group -->
122
+ <xs:element name="AlternativeDocument" substitutionGroup="test:TestDocument">
123
+ <xs:complexType>
124
+ <xs:complexContent>
125
+ <xs:extension base="test:TestDocument">
126
+ <xs:sequence>
127
+ <xs:element name="additional" type="xs:string"/>
128
+ </xs:sequence>
129
+ </xs:extension>
130
+ </xs:complexContent>
131
+ </xs:complexType>
132
+ </xs:element>
133
+
134
+ </xs:schema>