lutaml-model 0.5.4 → 0.6.1

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +58 -21
  3. data/Gemfile +1 -0
  4. data/README.adoc +1112 -264
  5. data/lib/lutaml/model/attribute.rb +37 -15
  6. data/lib/lutaml/model/choice.rb +56 -0
  7. data/lib/lutaml/model/config.rb +1 -0
  8. data/lib/lutaml/model/error/choice_lower_bound_error.rb +9 -0
  9. data/lib/lutaml/model/error/choice_upper_bound_error.rb +9 -0
  10. data/lib/lutaml/model/error/import_model_with_root_error.rb +9 -0
  11. data/lib/lutaml/model/error/incorrect_sequence_error.rb +9 -0
  12. data/lib/lutaml/model/error/invalid_choice_range_error.rb +20 -0
  13. data/lib/lutaml/model/error/no_root_mapping_error.rb +9 -0
  14. data/lib/lutaml/model/error/no_root_namespace_error.rb +9 -0
  15. data/lib/lutaml/model/error/unknown_sequence_mapping_error.rb +9 -0
  16. data/lib/lutaml/model/error.rb +8 -0
  17. data/lib/lutaml/model/json_adapter/standard_json_adapter.rb +6 -1
  18. data/lib/lutaml/model/key_value_mapping.rb +3 -1
  19. data/lib/lutaml/model/key_value_mapping_rule.rb +4 -2
  20. data/lib/lutaml/model/liquefiable.rb +59 -0
  21. data/lib/lutaml/model/mapping_hash.rb +1 -1
  22. data/lib/lutaml/model/mapping_rule.rb +15 -2
  23. data/lib/lutaml/model/schema/xml_compiler.rb +68 -26
  24. data/lib/lutaml/model/schema_location.rb +7 -0
  25. data/lib/lutaml/model/sequence.rb +71 -0
  26. data/lib/lutaml/model/serialize.rb +126 -38
  27. data/lib/lutaml/model/type/decimal.rb +0 -4
  28. data/lib/lutaml/model/type/time.rb +3 -3
  29. data/lib/lutaml/model/utils.rb +19 -15
  30. data/lib/lutaml/model/validation.rb +12 -1
  31. data/lib/lutaml/model/version.rb +1 -1
  32. data/lib/lutaml/model/xml_adapter/builder/oga.rb +10 -7
  33. data/lib/lutaml/model/xml_adapter/builder/ox.rb +20 -13
  34. data/lib/lutaml/model/xml_adapter/element.rb +32 -0
  35. data/lib/lutaml/model/xml_adapter/nokogiri_adapter.rb +8 -8
  36. data/lib/lutaml/model/xml_adapter/oga/element.rb +14 -13
  37. data/lib/lutaml/model/xml_adapter/oga_adapter.rb +86 -19
  38. data/lib/lutaml/model/xml_adapter/ox_adapter.rb +19 -15
  39. data/lib/lutaml/model/xml_adapter/xml_document.rb +74 -13
  40. data/lib/lutaml/model/xml_adapter/xml_element.rb +57 -3
  41. data/lib/lutaml/model/xml_mapping.rb +49 -7
  42. data/lib/lutaml/model/xml_mapping_rule.rb +8 -3
  43. data/lib/lutaml/model.rb +1 -0
  44. data/lutaml-model.gemspec +5 -0
  45. data/spec/benchmarks/xml_parsing_benchmark_spec.rb +75 -0
  46. data/spec/ceramic_spec.rb +39 -0
  47. data/spec/fixtures/ceramic.rb +23 -0
  48. data/spec/fixtures/xml/address_example_260.xsd +9 -0
  49. data/spec/fixtures/xml/user.xsd +10 -0
  50. data/spec/lutaml/model/cdata_spec.rb +4 -5
  51. data/spec/lutaml/model/choice_spec.rb +168 -0
  52. data/spec/lutaml/model/collection_spec.rb +1 -1
  53. data/spec/lutaml/model/custom_model_spec.rb +55 -8
  54. data/spec/lutaml/model/custom_serialization_spec.rb +74 -2
  55. data/spec/lutaml/model/defaults_spec.rb +3 -1
  56. data/spec/lutaml/model/delegation_spec.rb +7 -5
  57. data/spec/lutaml/model/enum_spec.rb +35 -0
  58. data/spec/lutaml/model/group_spec.rb +160 -0
  59. data/spec/lutaml/model/inheritance_spec.rb +25 -0
  60. data/spec/lutaml/model/liquefiable_spec.rb +121 -0
  61. data/spec/lutaml/model/mixed_content_spec.rb +80 -41
  62. data/spec/lutaml/model/multiple_mapping_spec.rb +22 -10
  63. data/spec/lutaml/model/schema/xml_compiler_spec.rb +218 -25
  64. data/spec/lutaml/model/sequence_spec.rb +216 -0
  65. data/spec/lutaml/model/transformation_spec.rb +230 -0
  66. data/spec/lutaml/model/type_spec.rb +138 -31
  67. data/spec/lutaml/model/utils_spec.rb +32 -0
  68. data/spec/lutaml/model/xml_adapter/oga_adapter_spec.rb +11 -7
  69. data/spec/lutaml/model/xml_mapping_rule_spec.rb +51 -0
  70. data/spec/lutaml/model/xml_mapping_spec.rb +167 -112
  71. metadata +67 -2
@@ -10,6 +10,9 @@ module Lutaml
10
10
  collection
11
11
  values
12
12
  pattern
13
+ transform
14
+ choice
15
+ sequence
13
16
  ].freeze
14
17
 
15
18
  def initialize(name, type, options = {})
@@ -33,6 +36,10 @@ module Lutaml
33
36
  @options[:delegate]
34
37
  end
35
38
 
39
+ def transform
40
+ @options[:transform] || {}
41
+ end
42
+
36
43
  def cast_type!(type)
37
44
  case type
38
45
  when Symbol
@@ -81,15 +88,17 @@ module Lutaml
81
88
  end
82
89
 
83
90
  def default
84
- value = if delegate
85
- type.attributes[to].default
86
- elsif options[:default].is_a?(Proc)
87
- options[:default].call
88
- else
89
- options[:default]
90
- end
91
-
92
- cast_value(value)
91
+ cast_value(default_value)
92
+ end
93
+
94
+ def default_value
95
+ if delegate
96
+ type.attributes[to].default
97
+ elsif options[:default].is_a?(Proc)
98
+ options[:default].call
99
+ else
100
+ options[:default]
101
+ end
93
102
  end
94
103
 
95
104
  def pattern
@@ -100,8 +109,16 @@ module Lutaml
100
109
  @options.key?(:values) ? @options[:values] : []
101
110
  end
102
111
 
112
+ def transform_import_method
113
+ transform[:import]
114
+ end
115
+
116
+ def transform_export_method
117
+ transform[:export]
118
+ end
119
+
103
120
  def valid_value!(value)
104
- return true if value.nil? && !collection?
121
+ return true if value.nil? && singular?
105
122
  return true unless enum?
106
123
 
107
124
  unless valid_value?(value)
@@ -153,6 +170,10 @@ module Lutaml
153
170
  raise ArgumentError, "Invalid collection range: #{range}"
154
171
  end
155
172
 
173
+ validate_range!(range)
174
+ end
175
+
176
+ def validate_range!(range)
156
177
  if range.begin.nil?
157
178
  raise ArgumentError,
158
179
  "Invalid collection range: #{range}. Begin must be specified."
@@ -227,14 +248,15 @@ module Lutaml
227
248
  end
228
249
 
229
250
  def cast(value, format, options = {})
230
- value ||= [] if collection?
251
+ return value if type <= Serialize && value.is_a?(type.model)
231
252
 
253
+ value ||= [] if collection?
232
254
  if value.is_a?(Array)
233
- value.map do |v|
234
- cast(v, format, options)
235
- end
236
- elsif type <= Serialize && value.is_a?(Hash)
255
+ value.map { |v| cast(v, format, options) }
256
+ elsif type <= Serialize && (value.is_a?(Hash) || value.is_a?(Lutaml::Model::XmlAdapter::XmlElement))
237
257
  type.apply_mappings(value, format, options)
258
+ elsif !value.nil? && !value.is_a?(type)
259
+ type.send(:"from_#{format}", value)
238
260
  else
239
261
  type.cast(value)
240
262
  end
@@ -0,0 +1,56 @@
1
+ module Lutaml
2
+ module Model
3
+ class Choice
4
+ attr_reader :attributes,
5
+ :model,
6
+ :min,
7
+ :max
8
+
9
+ def initialize(model, min, max)
10
+ @attributes = []
11
+ @model = model
12
+ @min = min
13
+ @max = max
14
+
15
+ raise Lutaml::Model::InvalidChoiceRangeError.new(@min, @max) if @min.negative? || @max.negative?
16
+ end
17
+
18
+ def attribute(name, type, options = {})
19
+ options[:choice] = self
20
+ @attributes << @model.attribute(name, type, options)
21
+ end
22
+
23
+ def choice(min: 1, max: 1, &block)
24
+ @attributes << Choice.new(@model, min, max).tap do |c|
25
+ c.instance_eval(&block)
26
+ end
27
+ end
28
+
29
+ def validate_content!(object)
30
+ validated_attributes = []
31
+ valid = valid_attributes(object, validated_attributes)
32
+
33
+ raise Lutaml::Model::ChoiceUpperBoundError.new(validated_attributes, @max) if valid.count > @max
34
+ raise Lutaml::Model::ChoiceLowerBoundError.new(validated_attributes, @min) if valid.count < @min
35
+ end
36
+
37
+ private
38
+
39
+ def valid_attributes(object, validated_attributes)
40
+ @attributes.each do |attribute|
41
+ if attribute.is_a?(Choice)
42
+ begin
43
+ attribute.validate_content!(object)
44
+ validated_attributes << attribute
45
+ rescue Lutaml::Model::ChoiceLowerBoundError
46
+ end
47
+ elsif Utils.present?(object.public_send(attribute.name))
48
+ validated_attributes << attribute.name
49
+ end
50
+ end
51
+
52
+ validated_attributes
53
+ end
54
+ end
55
+ end
56
+ end
@@ -59,6 +59,7 @@ module Lutaml
59
59
  cause: nil,
60
60
  )
61
61
  end
62
+ Moxml::Adapter.load(type_name) unless KEY_VALUE_FORMATS.include?(adapter_name)
62
63
 
63
64
  instance_variable_set(
64
65
  :"@#{adapter}",
@@ -0,0 +1,9 @@
1
+ module Lutaml
2
+ module Model
3
+ class ChoiceLowerBoundError < Error
4
+ def initialize(validated_attributes, min)
5
+ super("Attributes `#{validated_attributes}` count is less than the lower bound `#{min}`")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Lutaml
2
+ module Model
3
+ class ChoiceUpperBoundError < Error
4
+ def initialize(validated_attributes, max)
5
+ super("Attributes `#{validated_attributes}` count exceeds the upper bound `#{max}`")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Lutaml
2
+ module Model
3
+ class ImportModelWithRootError < Error
4
+ def initialize(model)
5
+ super("Cannot import a model `#{model}` with a root element")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Lutaml
2
+ module Model
3
+ class IncorrectSequenceError < Error
4
+ def initialize(defined_order_element, expected_order_element)
5
+ super("Element `#{expected_order_element}` does not match the expected sequence order element `#{defined_order_element}`")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ module Lutaml
2
+ module Model
3
+ class InvalidChoiceRangeError < Error
4
+ def initialize(min, max)
5
+ @min = min
6
+ @max = max
7
+
8
+ super()
9
+ end
10
+
11
+ def to_s
12
+ if @min.negative?
13
+ "Choice lower bound `#{@min}` must be positive"
14
+ else
15
+ "Choice upper bound `#{@max}` must be positive"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ module Lutaml
2
+ module Model
3
+ class NoRootMappingError < Error
4
+ def initialize(model)
5
+ super("#{model} has `no_root`, it allowed only for reusable models")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Lutaml
2
+ module Model
3
+ class NoRootNamespaceError < Error
4
+ def to_s
5
+ "Cannot assign namespace to `no_root`"
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Lutaml
2
+ module Model
3
+ class UnknownSequenceMappingError < Error
4
+ def initialize(method_name)
5
+ super("#{method_name} is not allowed in sequence")
6
+ end
7
+ end
8
+ end
9
+ end
@@ -17,3 +17,11 @@ require_relative "error/unknown_type_error"
17
17
  require_relative "error/multiple_mappings_error"
18
18
  require_relative "error/collection_true_missing_error"
19
19
  require_relative "error/type/invalid_value_error"
20
+ require_relative "error/incorrect_sequence_error"
21
+ require_relative "error/choice_upper_bound_error"
22
+ require_relative "error/no_root_mapping_error"
23
+ require_relative "error/import_model_with_root_error"
24
+ require_relative "error/invalid_choice_range_error"
25
+ require_relative "error/unknown_sequence_mapping_error"
26
+ require_relative "error/choice_lower_bound_error"
27
+ require_relative "error/no_root_namespace_error"
@@ -10,7 +10,12 @@ module Lutaml
10
10
  end
11
11
 
12
12
  def to_json(*args)
13
- JSON.generate(@attributes, *args)
13
+ options = args.first || {}
14
+ if options[:pretty]
15
+ JSON.pretty_generate(@attributes, *args)
16
+ else
17
+ JSON.generate(@attributes, *args)
18
+ end
14
19
  end
15
20
  end
16
21
  end
@@ -17,7 +17,8 @@ module Lutaml
17
17
  with: {},
18
18
  delegate: nil,
19
19
  child_mappings: nil,
20
- root_mappings: nil
20
+ root_mappings: nil,
21
+ transform: {}
21
22
  )
22
23
  mapping_name = name_for_mapping(root_mappings, name)
23
24
  validate!(mapping_name, to, with)
@@ -31,6 +32,7 @@ module Lutaml
31
32
  delegate: delegate,
32
33
  child_mappings: child_mappings,
33
34
  root_mappings: root_mappings,
35
+ transform: transform,
34
36
  )
35
37
  end
36
38
 
@@ -14,7 +14,8 @@ module Lutaml
14
14
  with: {},
15
15
  delegate: nil,
16
16
  child_mappings: nil,
17
- root_mappings: nil
17
+ root_mappings: nil,
18
+ transform: {}
18
19
  )
19
20
  super(
20
21
  name,
@@ -22,7 +23,8 @@ module Lutaml
22
23
  render_nil: render_nil,
23
24
  render_default: render_default,
24
25
  with: with,
25
- delegate: delegate
26
+ delegate: delegate,
27
+ transform: transform
26
28
  )
27
29
 
28
30
  @child_mappings = child_mappings
@@ -0,0 +1,59 @@
1
+ require "liquid"
2
+
3
+ module Lutaml
4
+ module Model
5
+ module Liquefiable
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ def register_liquid_drop_class
12
+ if drop_class
13
+ raise "#{drop_class_name} Already exists!"
14
+ end
15
+
16
+ const_set(drop_class_name,
17
+ Class.new(Liquid::Drop) do
18
+ def initialize(object)
19
+ super()
20
+ @object = object
21
+ end
22
+ end)
23
+ end
24
+
25
+ def drop_class_name
26
+ @drop_class_name ||= if name
27
+ "#{to_s.split('::').last}Drop"
28
+ else
29
+ "Drop"
30
+ end
31
+ end
32
+
33
+ def drop_class
34
+ const_get(drop_class_name)
35
+ rescue StandardError
36
+ nil
37
+ end
38
+
39
+ def register_drop_method(method_name)
40
+ register_liquid_drop_class unless drop_class
41
+
42
+ drop_class.define_method(method_name) do
43
+ value = @object.public_send(method_name)
44
+
45
+ if value.is_a?(Array)
46
+ value.map(&:to_liquid)
47
+ else
48
+ value.to_liquid
49
+ end
50
+ end
51
+ end
52
+ end
53
+
54
+ def to_liquid
55
+ self.class.drop_class.new(self)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -11,7 +11,7 @@ module Lutaml
11
11
  end
12
12
 
13
13
  def item_order
14
- @item_order&.map { |key| normalize(key) } || keys
14
+ @item_order
15
15
  end
16
16
 
17
17
  def fetch(key)
@@ -7,7 +7,8 @@ module Lutaml
7
7
  :render_default,
8
8
  :attribute,
9
9
  :custom_methods,
10
- :delegate
10
+ :delegate,
11
+ :transform
11
12
 
12
13
  def initialize(
13
14
  name,
@@ -17,7 +18,8 @@ module Lutaml
17
18
  with: {},
18
19
  attribute: false,
19
20
  delegate: nil,
20
- root_mappings: nil
21
+ root_mappings: nil,
22
+ transform: {}
21
23
  )
22
24
  @name = name
23
25
  @to = to
@@ -27,6 +29,7 @@ module Lutaml
27
29
  @attribute = attribute
28
30
  @delegate = delegate
29
31
  @root_mappings = root_mappings
32
+ @transform = transform
30
33
  end
31
34
 
32
35
  alias from name
@@ -71,6 +74,8 @@ module Lutaml
71
74
  end
72
75
 
73
76
  model.public_send(delegate).public_send(:"#{to}=", value)
77
+ elsif transform_method = transform[:import] || attributes[to].transform_import_method
78
+ model.public_send(:"#{to}=", transform_method.call(value))
74
79
  else
75
80
  model.public_send(:"#{to}=", value)
76
81
  end
@@ -88,6 +93,14 @@ module Lutaml
88
93
  name == Constants::RAW_MAPPING_KEY
89
94
  end
90
95
 
96
+ def eql?(other)
97
+ other.class == self.class &&
98
+ instance_variables.all? do |var|
99
+ instance_variable_get(var) == other.instance_variable_get(var)
100
+ end
101
+ end
102
+ alias == eql?
103
+
91
104
  def deep_dup
92
105
  raise NotImplementedError, "Subclasses must implement `deep_dup`."
93
106
  end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "erb"
4
+ require "tmpdir"
4
5
  require "lutaml/xsd"
5
6
  require_relative "templates/simple_type"
6
7
 
@@ -37,7 +38,7 @@ module Lutaml
37
38
  if content&.key_exist?(:sequence) || content&.key_exist?(:choice) || content&.key_exist?(:group)
38
39
  output = resolve_content(content).map do |element_name, element|
39
40
  element = @elements[element.ref_class.split(":")&.last] if element&.key_exist?(:ref_class)
40
- " attribute :\#{Utils.snake_case(element_name)}, \#{Utils.camel_case(element.type_name.split(":").last)}\#{resolve_occurs(element.arguments) if element.key_exist?(:arguments)}"
41
+ " attribute :\#{Utils.snake_case(element_name)}, \#{resolve_element_class(element)}\#{resolve_occurs(element.arguments) if element.key_exist?(:arguments)}"
41
42
  end.join("\n")
42
43
  output + "\n" if output && !output&.empty?
43
44
  end
@@ -49,13 +50,13 @@ module Lutaml
49
50
  element.map { |attribute| " attribute :\#{Utils.snake_case(attribute.name)}, \#{resolve_attribute_class(attribute)}\#{resolve_attribute_default(attribute.default) if attribute.key_exist?(:default)}" }.join("\n")
50
51
  else
51
52
  element = @elements[element.ref_class.split(":")&.last] if element&.key_exist?(:ref_class)
52
- " attribute :\#{Utils.snake_case(element_name)}, \#{Utils.camel_case(element.type_name.split(":").last)}\#{resolve_occurs(element.arguments) if element.key_exist?(:arguments)}"
53
+ " attribute :\#{Utils.snake_case(element_name)}, \#{resolve_element_class(element)}\#{resolve_occurs(element.arguments) if element.key_exist?(:arguments)}"
53
54
  end
54
55
  end.join("\n")
55
56
  output + "\n" if output && !output&.empty?
56
57
  end
57
58
  -%>
58
- <%= " attribute :content, \#{content.simple_content.extension_base}" if content_exist = content.key_exist?(:simple_content) && content.simple_content.key_exist?(:extension_base) -%>
59
+ <%= " attribute :content, \#{content[:mixed] ? ':string' : content.simple_content.extension_base}" if content_exist = (content.key_exist?(:simple_content) && content.simple_content.key_exist?(:extension_base)) || content[:mixed] -%>
59
60
 
60
61
  xml do
61
62
  root "<%= name %>", mixed: true
@@ -107,13 +108,28 @@ module Lutaml
107
108
 
108
109
  def to_models(schema, options = {})
109
110
  as_models(schema, options: options)
110
- dir = options.fetch(:output_dir, "lutaml_models_#{Time.now.to_i}")
111
- FileUtils.mkdir_p(dir)
112
-
113
111
  @data_types_classes = Templates::SimpleType.create_simple_types(@simple_types)
114
- @data_types_classes.each { |name, content| create_file(name, content, dir) }
115
- @complex_types.each { |name, content| create_file(name, MODEL_TEMPLATE.result(binding), dir) }
116
- nil
112
+ if options[:create_files]
113
+ dir = options.fetch(:output_dir, "lutaml_models_#{Time.now.to_i}")
114
+ FileUtils.mkdir_p(dir)
115
+ @data_types_classes.each do |name, content|
116
+ create_file(name, content, dir)
117
+ end
118
+ @complex_types.each do |name, content|
119
+ create_file(name, MODEL_TEMPLATE.result(binding), dir)
120
+ end
121
+ nil
122
+ else
123
+ simple_types = @data_types_classes.transform_keys do |key|
124
+ Utils.camel_case(key.to_s)
125
+ end
126
+ complex_types = @complex_types.to_h do |name, content|
127
+ [Utils.camel_case(name), MODEL_TEMPLATE.result(binding)]
128
+ end
129
+ classes_hash = simple_types.merge(complex_types)
130
+ require_classes(classes_hash) if options[:load_classes]
131
+ classes_hash
132
+ end
117
133
  end
118
134
 
119
135
  private
@@ -122,6 +138,15 @@ module Lutaml
122
138
  File.write("#{dir}/#{Utils.snake_case(name)}.rb", content)
123
139
  end
124
140
 
141
+ def require_classes(classes_hash)
142
+ Dir.mktmpdir do |dir|
143
+ classes_hash.each do |name, klass|
144
+ create_file(name, klass, dir)
145
+ require "#{dir}/#{Utils.snake_case(name)}"
146
+ end
147
+ end
148
+ end
149
+
125
150
  # START: STRUCTURE SETUP METHODS
126
151
 
127
152
  def as_models(schema, options: {})
@@ -136,7 +161,7 @@ module Lutaml
136
161
  @complex_types = MappingHash.new
137
162
  @attribute_groups = MappingHash.new
138
163
 
139
- schema_to_models([parsed_schema])
164
+ schema_to_models(Array(parsed_schema))
140
165
  end
141
166
 
142
167
  def schema_to_models(schemas)
@@ -196,6 +221,7 @@ module Lutaml
196
221
  MappingHash.new.tap do |hash|
197
222
  hash[:attributes] = [] if complex_type.attribute.any?
198
223
  hash[:attribute_groups] = [] if complex_type.attribute_group.any?
224
+ hash[:mixed] = complex_type.mixed
199
225
  resolved_element_order(complex_type).each do |element|
200
226
  case element
201
227
  when Xsd::Attribute
@@ -237,18 +263,18 @@ module Lutaml
237
263
  hash[:sequences] << setup_sequence(instance)
238
264
  when Xsd::Element
239
265
  hash[:elements] << if instance.name
240
- setup_element(instance)
241
- else
242
- create_mapping_hash(instance.ref, hash_key: :ref_class)
243
- end
266
+ setup_element(instance)
267
+ else
268
+ create_mapping_hash(instance.ref, hash_key: :ref_class)
269
+ end
244
270
  when Xsd::Choice
245
271
  hash[:choice] << setup_choice(instance)
246
272
  when Xsd::Group
247
273
  hash[:groups] << if instance.name
248
- setup_group_type(instance)
249
- else
250
- create_mapping_hash(instance.ref, hash_key: :ref_class)
251
- end
274
+ setup_group_type(instance)
275
+ else
276
+ create_mapping_hash(instance.ref, hash_key: :ref_class)
277
+ end
252
278
  when Xsd::Any
253
279
  # No implementation yet!
254
280
  end
@@ -363,7 +389,7 @@ module Lutaml
363
389
  def restriction_patterns(patterns, hash)
364
390
  return if patterns.empty?
365
391
 
366
- hash[:pattern] = patterns.map { |pattern| "(#{pattern.value})" }.join("|")
392
+ hash[:pattern] = patterns.map { |p| "(#{p.value})" }.join("|")
367
393
  hash
368
394
  end
369
395
 
@@ -404,22 +430,23 @@ module Lutaml
404
430
  end
405
431
  end
406
432
 
407
- def resolved_element_order(object, ignore_text: true)
433
+ def resolved_element_order(object)
408
434
  return [] if object.element_order.nil?
409
435
 
410
- object.element_order.each_with_object(object.element_order.dup) do |name, array|
411
- next array.delete(name) if name == "text" && (ignore_text || !object.respond_to?(:text))
412
- next array.delete(name) if ELEMENT_ORDER_IGNORABLE.include?(name)
436
+ object.element_order.each_with_object(object.element_order.dup) do |builder_instance, array|
437
+ next array.delete(builder_instance) if builder_instance.text?
438
+ next array.delete(builder_instance) if ELEMENT_ORDER_IGNORABLE.include?(builder_instance.name)
413
439
 
414
440
  index = 0
415
441
  array.each_with_index do |element, i|
416
- next unless element == name
442
+ next unless element == builder_instance
417
443
 
418
- array[i] = Array(object.send(Utils.snake_case(name)))[index]
444
+ array[i] = Array(object.send(Utils.snake_case(builder_instance.name)))[index]
419
445
  index += 1
420
446
  end
421
447
  end
422
448
  end
449
+
423
450
  # END: STRUCTURE SETUP METHODS
424
451
 
425
452
  # START: TEMPLATE RESOLVER METHODS
@@ -439,6 +466,16 @@ module Lutaml
439
466
  end
440
467
  end
441
468
 
469
+ def resolve_element_class(element)
470
+ element_class = element.type_name.split(":").last
471
+ case element_class
472
+ when *DEFAULT_CLASSES
473
+ ":#{element_class}"
474
+ else
475
+ Utils.camel_case(element_class)
476
+ end
477
+ end
478
+
442
479
  def resolve_occurs(arguments)
443
480
  min_occurs = arguments[:min_occurs]
444
481
  max_occurs = arguments[:max_occurs]
@@ -583,6 +620,7 @@ module Lutaml
583
620
  end
584
621
  @required_files.uniq.sort_by(&:length)
585
622
  end
623
+
586
624
  # END: TEMPLATE RESOLVER METHODS
587
625
 
588
626
  # START: REQUIRED FILES LIST COMPILER METHODS
@@ -710,9 +748,13 @@ module Lutaml
710
748
  def required_files_elements(elements)
711
749
  elements.each do |element|
712
750
  element = @elements[element.ref_class.split(":").last] if element.key_exist?(:ref_class)
713
- @required_files << Utils.snake_case(element.type_name.split(":").last)
751
+ element_class = element.type_name.split(":").last
752
+ next if DEFAULT_CLASSES.include?(element_class)
753
+
754
+ @required_files << Utils.snake_case(element_class)
714
755
  end
715
756
  end
757
+
716
758
  # END: REQUIRED FILES LIST COMPILER METHODS
717
759
  end
718
760
  end
@@ -11,6 +11,13 @@ module Lutaml
11
11
  def to_xml_attribute
12
12
  "#{@namespace} #{@location}".strip
13
13
  end
14
+
15
+ def eql?(other)
16
+ other.class == self.class &&
17
+ namespace == other.namespace &&
18
+ location == other.location
19
+ end
20
+ alias == eql?
14
21
  end
15
22
 
16
23
  class SchemaLocation