lutaml-model 0.8.9 → 0.8.11

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 (108) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependent-repos.json +1 -0
  3. data/.rubocop_todo.yml +52 -22
  4. data/README.adoc +43 -0
  5. data/docs/_guides/jsonld-serialization.adoc +3 -1
  6. data/docs/_guides/rdf-serialization.adoc +94 -8
  7. data/docs/_guides/turtle-serialization.adoc +17 -4
  8. data/lib/lutaml/jsonld/transform.rb +70 -24
  9. data/lib/lutaml/key_value/transform.rb +5 -5
  10. data/lib/lutaml/key_value/transformation/collection_serializer.rb +25 -11
  11. data/lib/lutaml/key_value/transformation/value_serializer.rb +7 -7
  12. data/lib/lutaml/key_value/transformation.rb +27 -17
  13. data/lib/lutaml/model/adapter_resolver.rb +4 -6
  14. data/lib/lutaml/model/attribute.rb +26 -23
  15. data/lib/lutaml/model/cached_type_resolver.rb +10 -9
  16. data/lib/lutaml/model/cli.rb +1 -1
  17. data/lib/lutaml/model/collection.rb +4 -4
  18. data/lib/lutaml/model/comparable_model.rb +11 -11
  19. data/lib/lutaml/model/config.rb +1 -1
  20. data/lib/lutaml/model/consolidation/dispatcher.rb +1 -1
  21. data/lib/lutaml/model/consolidation/pattern_chunker.rb +3 -3
  22. data/lib/lutaml/model/format_registry.rb +6 -4
  23. data/lib/lutaml/model/global_context.rb +2 -2
  24. data/lib/lutaml/model/global_register.rb +1 -1
  25. data/lib/lutaml/model/instrumentation.rb +1 -1
  26. data/lib/lutaml/model/mapping/mapping_rule.rb +3 -3
  27. data/lib/lutaml/model/mapping/model_mapping.rb +1 -1
  28. data/lib/lutaml/model/mapping/model_mapping_rule.rb +1 -1
  29. data/lib/lutaml/model/register.rb +3 -3
  30. data/lib/lutaml/model/render_policy.rb +11 -17
  31. data/lib/lutaml/model/runtime_compatibility.rb +0 -1
  32. data/lib/lutaml/model/schema/xml_compiler/group.rb +1 -1
  33. data/lib/lutaml/model/schema/xml_compiler/registry_generator.rb +1 -1
  34. data/lib/lutaml/model/schema/xml_compiler/sequence.rb +0 -2
  35. data/lib/lutaml/model/schema/xml_compiler.rb +14 -14
  36. data/lib/lutaml/model/serialize/attribute_definition.rb +1 -1
  37. data/lib/lutaml/model/serialize/deserialization_context.rb +50 -0
  38. data/lib/lutaml/model/serialize/format_conversion.rb +2 -2
  39. data/lib/lutaml/model/serialize/initialization.rb +44 -7
  40. data/lib/lutaml/model/serialize/model_import.rb +1 -1
  41. data/lib/lutaml/model/serialize.rb +8 -1
  42. data/lib/lutaml/model/services/rule_value_extractor.rb +2 -1
  43. data/lib/lutaml/model/store.rb +77 -24
  44. data/lib/lutaml/model/transformation_registry.rb +1 -1
  45. data/lib/lutaml/model/type_context.rb +7 -1
  46. data/lib/lutaml/model/type_resolver.rb +1 -6
  47. data/lib/lutaml/model/utils.rb +19 -6
  48. data/lib/lutaml/model/validation_framework.rb +1 -1
  49. data/lib/lutaml/model/value_transformer.rb +2 -2
  50. data/lib/lutaml/model/version.rb +1 -1
  51. data/lib/lutaml/rdf/mapping.rb +19 -13
  52. data/lib/lutaml/rdf/mapping_rule.rb +19 -2
  53. data/lib/lutaml/rdf/member_rule.rb +19 -2
  54. data/lib/lutaml/rdf/transform.rb +20 -11
  55. data/lib/lutaml/turtle/transform.rb +125 -53
  56. data/lib/lutaml/xml/adapter/adapter_helpers.rb +1 -1
  57. data/lib/lutaml/xml/adapter/base_adapter.rb +10 -14
  58. data/lib/lutaml/xml/adapter/namespace_uri_collector.rb +3 -3
  59. data/lib/lutaml/xml/adapter/plan_based_builder.rb +14 -14
  60. data/lib/lutaml/xml/adapter/xml_serializer.rb +3 -3
  61. data/lib/lutaml/xml/configurable.rb +2 -1
  62. data/lib/lutaml/xml/data_model.rb +2 -2
  63. data/lib/lutaml/xml/decisions/decision_context.rb +3 -3
  64. data/lib/lutaml/xml/decisions/rules/element_form_default_unqualified_rule.rb +1 -1
  65. data/lib/lutaml/xml/decisions/rules/element_form_option_rule.rb +1 -1
  66. data/lib/lutaml/xml/decisions/rules/used_prefix_rule.rb +1 -1
  67. data/lib/lutaml/xml/declaration_plan.rb +2 -2
  68. data/lib/lutaml/xml/declaration_planner.rb +12 -13
  69. data/lib/lutaml/xml/document.rb +13 -13
  70. data/lib/lutaml/xml/format_chooser.rb +3 -3
  71. data/lib/lutaml/xml/hoisting_algorithm.rb +1 -1
  72. data/lib/lutaml/xml/mapping.rb +2 -2
  73. data/lib/lutaml/xml/mapping_rule.rb +16 -3
  74. data/lib/lutaml/xml/model_transform.rb +17 -19
  75. data/lib/lutaml/xml/namespace_collector.rb +10 -10
  76. data/lib/lutaml/xml/namespace_declaration.rb +2 -2
  77. data/lib/lutaml/xml/namespace_declaration_data.rb +5 -8
  78. data/lib/lutaml/xml/namespace_scope_config.rb +3 -2
  79. data/lib/lutaml/xml/namespace_type_resolver.rb +4 -4
  80. data/lib/lutaml/xml/nokogiri/element.rb +2 -2
  81. data/lib/lutaml/xml/polymorphic_value_handler.rb +1 -1
  82. data/lib/lutaml/xml/schema/xsd/base.rb +7 -7
  83. data/lib/lutaml/xml/schema/xsd/choice.rb +2 -2
  84. data/lib/lutaml/xml/schema/xsd/complex_type.rb +5 -5
  85. data/lib/lutaml/xml/schema/xsd/errors/message_builder.rb +3 -3
  86. data/lib/lutaml/xml/schema/xsd/group.rb +2 -2
  87. data/lib/lutaml/xml/schema/xsd/sequence.rb +2 -2
  88. data/lib/lutaml/xml/schema/xsd_schema.rb +5 -5
  89. data/lib/lutaml/xml/serialization/format_conversion.rb +4 -3
  90. data/lib/lutaml/xml/transformation/element_builder.rb +4 -2
  91. data/lib/lutaml/xml/transformation/rule_applier.rb +2 -2
  92. data/lib/lutaml/xml/transformation/value_serializer.rb +4 -6
  93. data/lib/lutaml/xml/transformation.rb +4 -4
  94. data/lib/lutaml/xml/type/configurable.rb +0 -4
  95. data/lib/lutaml/xml/xml_element.rb +21 -13
  96. data/lutaml-model.gemspec +1 -1
  97. data/spec/lutaml/jsonld/transform_spec.rb +239 -0
  98. data/spec/lutaml/model/cached_type_resolver_spec.rb +3 -3
  99. data/spec/lutaml/model/optimization_spec.rb +228 -0
  100. data/spec/lutaml/model/store_spec.rb +195 -0
  101. data/spec/lutaml/rdf/mapping_rule_spec.rb +97 -0
  102. data/spec/lutaml/rdf/mapping_spec.rb +74 -4
  103. data/spec/lutaml/rdf/member_rule_spec.rb +41 -0
  104. data/spec/lutaml/rdf/rdf_transform_spec.rb +95 -29
  105. data/spec/lutaml/turtle/mapping_spec.rb +2 -2
  106. data/spec/lutaml/turtle/transform_spec.rb +315 -0
  107. data/spec/lutaml/xml/data_model_spec.rb +10 -28
  108. metadata +7 -4
@@ -46,56 +46,101 @@ module Lutaml
46
46
  def build_graph(mapping, instance)
47
47
  graph = RDF::Graph.new
48
48
 
49
- has_predicates_or_type = mapping.rdf_type || mapping.rdf_predicates.any?
50
-
51
- if has_predicates_or_type
52
- subject_uri = if mapping.rdf_subject
53
- RDF::URI(resolve_subject_uri(mapping, instance))
54
- else
55
- RDF::Node.new
56
- end
57
-
58
- if mapping.rdf_type
59
- type_uri = RDF::URI(resolve_type_uri(mapping))
60
- graph << RDF::Statement.new(subject_uri, RDF.type, type_uri)
49
+ has_resource_data =
50
+ mapping.rdf_type.any? ||
51
+ mapping.rdf_predicates.any? ||
52
+ mapping.rdf_members.any?(&:linked?)
53
+
54
+ if has_resource_data
55
+ subject_uri = resolve_subject(mapping, instance)
56
+ build_resource_triples(graph, mapping, instance, subject_uri)
57
+ end
58
+
59
+ build_member_subgraphs(graph, mapping, instance)
60
+
61
+ graph
62
+ end
63
+
64
+ def resolve_subject(mapping, instance)
65
+ if mapping.rdf_subject
66
+ RDF::URI(resolve_subject_uri(mapping, instance))
67
+ else
68
+ RDF::Node.new
69
+ end
70
+ end
71
+
72
+ def build_resource_triples(graph, mapping, instance, subject_uri)
73
+ mapping.rdf_type.each do |type_value|
74
+ type_uri = RDF::URI(resolve_single_type_uri(mapping, type_value))
75
+ graph << RDF::Statement.new(subject_uri, RDF.type, type_uri)
76
+ end
77
+
78
+ mapping.rdf_predicates.each do |rule|
79
+ value = instance.public_send(rule.to)
80
+ next if value.nil?
81
+
82
+ Array(value).each do |v|
83
+ object = build_rdf_object(v, rule, mapping.namespace_set)
84
+ graph << RDF::Statement.new(subject_uri, RDF::URI(rule.uri), object)
61
85
  end
86
+ end
87
+
88
+ mapping.rdf_members.each do |member_rule|
89
+ next unless member_rule.linked?
62
90
 
63
- mapping.rdf_predicates.each do |rule|
64
- value = instance.public_send(rule.to)
65
- next if value.nil?
91
+ each_member(instance, member_rule) do |member|
92
+ member_mapping = member_mapping_for(member, :turtle)
93
+ next unless member_mapping
66
94
 
67
- Array(value).each do |v|
68
- object = build_rdf_object(v, rule)
69
- graph << RDF::Statement.new(subject_uri, RDF::URI(rule.uri),
70
- object)
71
- end
95
+ member_subject = RDF::URI(resolve_subject_uri(member_mapping,
96
+ member))
97
+ graph << RDF::Statement.new(
98
+ subject_uri,
99
+ RDF::URI(member_rule.linked_predicate_uri),
100
+ member_subject,
101
+ )
72
102
  end
73
103
  end
104
+ end
74
105
 
106
+ def build_member_subgraphs(graph, mapping, instance)
75
107
  mapping.rdf_members.each do |member_rule|
76
- collection = Array(instance.public_send(member_rule.attr_name))
77
- collection.each do |member|
78
- member_mapping = member.class.mappings[:turtle]
108
+ each_member(instance, member_rule) do |member|
109
+ member_mapping = member_mapping_for(member, :turtle)
79
110
  next unless member_mapping
80
111
 
81
112
  graph << build_graph(member_mapping, member)
82
113
  end
83
114
  end
84
-
85
- graph
86
115
  end
87
116
 
88
- def build_rdf_object(value, rule)
89
- if rule.lang_tagged
117
+ def build_rdf_object(value, rule, namespace_set)
118
+ case rule.kind
119
+ when :uri_reference
120
+ build_uri_reference_object(value, namespace_set)
121
+ when :lang_tagged
90
122
  lang = extract_language(value)
91
123
  RDF::Literal.new(value.to_s, language: lang)
92
124
  else
93
- case value
94
- when Integer then RDF::Literal.new(value, datatype: RDF::XSD.integer)
95
- when Float then RDF::Literal.new(value, datatype: RDF::XSD.double)
96
- when TrueClass, FalseClass then RDF::Literal.new(value, datatype: RDF::XSD.boolean)
97
- else RDF::Literal.new(value.to_s)
98
- end
125
+ build_plain_literal(value)
126
+ end
127
+ end
128
+
129
+ def build_uri_reference_object(value, namespace_set)
130
+ resolved = if value.to_s.include?(":")
131
+ namespace_set.resolve_compact_iri(value.to_s)
132
+ else
133
+ value.to_s
134
+ end
135
+ RDF::URI.new(resolved)
136
+ end
137
+
138
+ def build_plain_literal(value)
139
+ case value
140
+ when Integer then RDF::Literal.new(value, datatype: RDF::XSD.integer)
141
+ when Float then RDF::Literal.new(value, datatype: RDF::XSD.double)
142
+ when TrueClass, FalseClass then RDF::Literal.new(value, datatype: RDF::XSD.boolean)
143
+ else RDF::Literal.new(value.to_s)
99
144
  end
100
145
  end
101
146
 
@@ -103,13 +148,12 @@ module Lutaml
103
148
  ns_set = mapping.namespace_set
104
149
 
105
150
  mapping.rdf_members.each do |member_rule|
106
- collection = Array(instance.public_send(member_rule.attr_name))
107
- next if collection.empty?
108
-
109
- member_mapping = collection.first.class.mappings[:turtle]
110
- next unless member_mapping
151
+ each_member(instance, member_rule) do |member|
152
+ member_mapping = member_mapping_for(member, :turtle)
153
+ next unless member_mapping
111
154
 
112
- ns_set = ns_set.merge(member_mapping.namespace_set)
155
+ ns_set = ns_set.merge(member_mapping.namespace_set)
156
+ end
113
157
  end
114
158
 
115
159
  ns_set.each.with_object({}) do |ns, h|
@@ -119,38 +163,66 @@ module Lutaml
119
163
 
120
164
  def extract_attributes(graph, mapping)
121
165
  attrs = {}
122
- type_uri = resolve_type_uri(mapping)
166
+ type_uris = resolve_type_uris(mapping)
123
167
 
124
- matching_subjects = find_subjects_by_type(graph, type_uri)
168
+ matching_subjects = find_subjects_by_types(graph, type_uris)
125
169
 
126
170
  matching_subjects.each do |subject|
127
- mapping.rdf_predicates.each do |rule|
128
- stmts = graph.query([subject, RDF::URI(rule.uri), nil])
129
- next if stmts.empty?
130
-
131
- values = stmts.map { |s| literal_to_ruby(s.object) }
132
- attrs[rule.to] = values.length == 1 ? values.first : values
133
- end
171
+ attrs["id"] = subject.to_s unless subject.node?
172
+ extract_predicate_attributes(graph, subject, mapping, attrs)
134
173
  end
135
174
 
136
175
  attrs
137
176
  end
138
177
 
139
- def find_subjects_by_type(graph, type_uri)
140
- graph.query([nil, RDF.type, RDF::URI(type_uri)]).map(&:subject).uniq
178
+ def extract_predicate_attributes(graph, subject, mapping, attrs)
179
+ mapping.rdf_predicates.each do |rule|
180
+ stmts = graph.query([subject, RDF::URI(rule.uri), nil])
181
+ next if stmts.empty?
182
+
183
+ values = stmts.map do |s|
184
+ literal_to_ruby(s.object, rule, mapping.namespace_set)
185
+ end
186
+ attrs[rule.to] = values.length == 1 ? values.first : values
187
+ end
188
+ end
189
+
190
+ def find_subjects_by_types(graph, type_uris)
191
+ type_uris.flat_map do |type_uri|
192
+ graph.query([nil, RDF.type, RDF::URI(type_uri)]).map(&:subject).uniq
193
+ end.uniq
141
194
  end
142
195
 
143
- def literal_to_ruby(rdf_object)
196
+ def literal_to_ruby(rdf_object, rule, namespace_set)
144
197
  case rdf_object
198
+ when RDF::URI
199
+ uri_to_ruby(rdf_object, rule, namespace_set)
145
200
  when RDF::Literal
201
+ literal_value_to_ruby(rdf_object, rule)
202
+ else
203
+ rdf_object.to_s
204
+ end
205
+ end
206
+
207
+ def uri_to_ruby(rdf_object, rule, namespace_set)
208
+ uri_str = rdf_object.to_s
209
+ if rule.kind == :uri_reference
210
+ namespace_set.compact(uri_str) || uri_str
211
+ else
212
+ uri_str
213
+ end
214
+ end
215
+
216
+ def literal_value_to_ruby(rdf_object, rule)
217
+ if rule.kind == :lang_tagged && rdf_object.language
218
+ rdf_object.value
219
+ else
146
220
  case rdf_object.datatype
147
221
  when RDF::XSD.integer then rdf_object.value.to_i
148
222
  when RDF::XSD.double, RDF::XSD.decimal, RDF::XSD.float then rdf_object.value.to_f
149
223
  when RDF::XSD.boolean then rdf_object.value == "true"
150
224
  else rdf_object.value
151
225
  end
152
- else
153
- rdf_object.to_s
154
226
  end
155
227
  end
156
228
  end
@@ -90,7 +90,7 @@ module Lutaml
90
90
  # @param node [Moxml::Node] The XML node
91
91
  # @return [String] The namespaced name (e.g., "uri:name" or "name")
92
92
  def namespaced_name_of(node)
93
- return name_of(node) unless node.respond_to?(:namespace)
93
+ return name_of(node) unless node.is_a?(Lutaml::Xml::XmlElement)
94
94
 
95
95
  [node&.namespace&.uri, node.name].compact.join(":")
96
96
  end
@@ -126,7 +126,7 @@ module Lutaml
126
126
  # @param options [Hash] serialization options
127
127
  # @return [Boolean] true if element has ordered content
128
128
  def ordered?(element, options = {})
129
- return false unless element.respond_to?(:element_order)
129
+ return false unless element.is_a?(Lutaml::Model::Serialize)
130
130
 
131
131
  mapper_class = options[:mapper_class]
132
132
  xml_mapping = mapper_class&.mappings_for(:xml)
@@ -156,7 +156,7 @@ module Lutaml
156
156
  klass = mapper_class || element.class
157
157
  return klass.attributes[rule.to] unless rule.delegate
158
158
 
159
- delegated_obj = element.send(rule.delegate)
159
+ delegated_obj = element.public_send(rule.delegate)
160
160
  return nil if delegated_obj.nil?
161
161
 
162
162
  delegated_obj.class.attributes[rule.to]
@@ -168,12 +168,12 @@ module Lutaml
168
168
  # @param rule [MappingRule] the mapping rule
169
169
  # @return [Object, nil] the attribute value or nil if delegate is nil
170
170
  def attribute_value_for(element, rule)
171
- return element.send(rule.to) unless rule.delegate
171
+ return element.public_send(rule.to) unless rule.delegate
172
172
 
173
- delegate_obj = element.send(rule.delegate)
173
+ delegate_obj = element.public_send(rule.delegate)
174
174
  return nil if delegate_obj.nil?
175
175
 
176
- delegate_obj.send(rule.to)
176
+ delegate_obj.public_send(rule.to)
177
177
  end
178
178
 
179
179
  # Process content mapping for an element
@@ -186,7 +186,7 @@ module Lutaml
186
186
  return unless content_rule
187
187
 
188
188
  if content_rule.custom_methods[:to]
189
- mapper_class.new.send(
189
+ mapper_class.new.public_send(
190
190
  content_rule.custom_methods[:to],
191
191
  element,
192
192
  xml.parent,
@@ -225,15 +225,11 @@ module Lutaml
225
225
  private
226
226
 
227
227
  def attribute_values(element, &)
228
- if element.respond_to?(:attributes_each_value)
229
- element.attributes_each_value(&)
230
- else
231
- element.attributes.each_value(&)
232
- end
228
+ element.attributes.each_value(&)
233
229
  end
234
230
 
235
231
  def schema_location_attribute?(attr)
236
- attr_name = if attr.respond_to?(:unprefixed_name)
232
+ attr_name = if attr.is_a?(Lutaml::Xml::XmlAttribute)
237
233
  attr.unprefixed_name
238
234
  else
239
235
  attr.name
@@ -242,7 +238,7 @@ module Lutaml
242
238
  end
243
239
 
244
240
  def attribute_namespace_prefix(attr)
245
- if attr.respond_to?(:namespace_prefix)
241
+ if attr.is_a?(Lutaml::Xml::XmlAttribute)
246
242
  attr.namespace_prefix
247
243
  else
248
244
  attr.namespace&.prefix
@@ -250,7 +246,7 @@ module Lutaml
250
246
  end
251
247
 
252
248
  def attribute_hash_name(attr)
253
- if attr.respond_to?(:namespaced_name)
249
+ if attr.is_a?(Lutaml::Xml::XmlAttribute)
254
250
  attr.namespaced_name
255
251
  else
256
252
  self.class.namespaced_attr_name(attr)
@@ -29,7 +29,7 @@ module Lutaml
29
29
 
30
30
  visited.add(model.object_id)
31
31
 
32
- if model.respond_to?(:original_namespace_uri) && model.original_namespace_uri
32
+ if model.is_a?(::Lutaml::Model::Serialize) && model.class.attributes.key?(:original_namespace_uri) && model.original_namespace_uri
33
33
  original_uri = model.original_namespace_uri
34
34
  if original_uri && !original_uri.empty?
35
35
  ns_class = model.class.mappings_for(:xml)&.namespace_class
@@ -47,12 +47,12 @@ module Lutaml
47
47
  next unless attr_def
48
48
 
49
49
  child_type = attr_def.type(Lutaml::Model::Config.default_register)
50
- next unless child_type.respond_to?(:<) && child_type < ::Lutaml::Model::Serializable
50
+ next unless child_type.is_a?(Class) && child_type < ::Lutaml::Model::Serializable
51
51
 
52
52
  child_mapping = child_type.mappings_for(:xml)
53
53
  next unless child_mapping
54
54
 
55
- child_instance = model.public_send(elem_rule.to) if model.respond_to?(elem_rule.to)
55
+ child_instance = model.public_send(elem_rule.to) if model.class.attributes.key?(elem_rule.to)
56
56
 
57
57
  if child_instance.is_a?(Array) || child_instance.is_a?(::Lutaml::Model::Collection)
58
58
  instances = child_instance.is_a?(::Lutaml::Model::Collection) ? child_instance.collection : child_instance
@@ -158,8 +158,8 @@ module Lutaml
158
158
  prefix: prefix) do |inner_xml|
159
159
  # Call attribute custom methods now that element is created
160
160
  attribute_custom_methods.each do |attribute_rule|
161
- mapper_class.new.send(attribute_rule.custom_methods[:to],
162
- element, inner_xml.parent, inner_xml)
161
+ mapper_class.new.public_send(attribute_rule.custom_methods[:to],
162
+ element, inner_xml.parent, inner_xml)
163
163
  end
164
164
 
165
165
  if ordered?(element, options.merge(mapper_class: mapper_class))
@@ -292,7 +292,7 @@ module Lutaml
292
292
  end
293
293
 
294
294
  # Check if element was created from nil value with render_nil option
295
- if element.respond_to?(:xsi_nil) && element.xsi_nil
295
+ if element.is_a?(Lutaml::Xml::DataModel::XmlElement) && element.xsi_nil
296
296
  attributes["xsi:nil"] = true
297
297
  end
298
298
 
@@ -301,7 +301,7 @@ module Lutaml
301
301
  prefix: prefix) do |inner_xml|
302
302
  # Handle raw content (map_all directive)
303
303
  has_raw_content = false
304
- if element.respond_to?(:raw_content)
304
+ if element.is_a?(Lutaml::Xml::DataModel::XmlElement)
305
305
  raw_content = element.raw_content
306
306
  if raw_content && !raw_content.to_s.empty?
307
307
  inner_xml.add_xml_fragment(inner_xml, raw_content.to_s)
@@ -361,8 +361,8 @@ module Lutaml
361
361
 
362
362
  # Handle custom methods
363
363
  if element_rule.custom_methods[:to]
364
- mapper_class.new.send(element_rule.custom_methods[:to], element,
365
- xml.parent, xml)
364
+ mapper_class.new.public_send(element_rule.custom_methods[:to], element,
365
+ xml.parent, xml)
366
366
  next
367
367
  end
368
368
 
@@ -432,8 +432,8 @@ module Lutaml
432
432
 
433
433
  # Handle custom methods
434
434
  if element_rule.custom_methods[:to]
435
- mapper_class.new.send(element_rule.custom_methods[:to], element,
436
- xml.parent, xml)
435
+ mapper_class.new.public_send(element_rule.custom_methods[:to], element,
436
+ xml.parent, xml)
437
437
  next
438
438
  end
439
439
 
@@ -468,7 +468,7 @@ module Lutaml
468
468
  attribute_def = mapper_class.attributes[element_rule.to]
469
469
  next unless attribute_def
470
470
 
471
- value = element.send(element_rule.to)
471
+ value = element.public_send(element_rule.to)
472
472
  next unless element_rule.render?(value, element)
473
473
 
474
474
  # For type-only models, children plans may not be available
@@ -500,7 +500,7 @@ module Lutaml
500
500
  attribute_def = mapper_class.attributes[element_rule.to]
501
501
  next unless attribute_def
502
502
 
503
- value = element.send(element_rule.to)
503
+ value = element.public_send(element_rule.to)
504
504
  next unless element_rule.render?(value, element)
505
505
 
506
506
  child_plan = plan.child_plan(element_rule.to)
@@ -805,10 +805,10 @@ module Lutaml
805
805
  value = nil
806
806
 
807
807
  if element_rule.delegate
808
- delegate_obj = element.send(element_rule.delegate)
809
- if delegate_obj.respond_to?(element_rule.to)
808
+ delegate_obj = element.public_send(element_rule.delegate)
809
+ if delegate_obj.is_a?(Lutaml::Model::Serialize) && delegate_obj.class.attributes.key?(element_rule.to)
810
810
  attribute_def = delegate_obj.class.attributes[element_rule.to]
811
- value = delegate_obj.send(element_rule.to)
811
+ value = delegate_obj.public_send(element_rule.to)
812
812
  end
813
813
  else
814
814
  attribute_def = attribute_definition_for(element, element_rule,
@@ -828,7 +828,7 @@ module Lutaml
828
828
  # @param content [Array] accumulated content strings
829
829
  def process_ordered_content(element, xml_mapping, xml, curr_index,
830
830
  content)
831
- text = element.send(xml_mapping.content_mapping.to)
831
+ text = element.public_send(xml_mapping.content_mapping.to)
832
832
  text = text[curr_index] if text.is_a?(Array)
833
833
 
834
834
  if element.mixed?
@@ -83,7 +83,7 @@ module Lutaml
83
83
  def build_xml_element_with_plan(builder, xml_element, plan,
84
84
  options = {})
85
85
  # Add processing instructions before the root element
86
- if xml_element.respond_to?(:processing_instructions)
86
+ if xml_element.is_a?(Lutaml::Xml::DataModel::XmlElement)
87
87
  xml_element.processing_instructions.each do |pi|
88
88
  builder.add_processing_instruction(pi.target, pi.content)
89
89
  end
@@ -230,7 +230,7 @@ module Lutaml
230
230
  attributes[attr_node.qualified_name] = xml_attr.value.to_s
231
231
  end
232
232
 
233
- if xml_element.respond_to?(:xsi_nil) && xml_element.xsi_nil
233
+ if xml_element.is_a?(Lutaml::Xml::DataModel::XmlElement) && xml_element.xsi_nil
234
234
  attributes["xsi:nil"] = "true"
235
235
  end
236
236
 
@@ -240,7 +240,7 @@ module Lutaml
240
240
  attributes["xmlns"] = "" if needs_xmlns_blank
241
241
 
242
242
  xml.create_and_add_element(qualified_name, attributes: attributes) do
243
- if xml_element.respond_to?(:raw_content)
243
+ if xml_element.is_a?(Lutaml::Xml::DataModel::XmlElement)
244
244
  raw_content = xml_element.raw_content
245
245
  if raw_content && !raw_content.to_s.empty?
246
246
  xml.add_xml_fragment(xml, raw_content.to_s)
@@ -119,7 +119,8 @@ module Lutaml
119
119
  # @return [void]
120
120
  def inherit_mapping_from(mapping_class)
121
121
  # Get the parent mapping instance that has DSL already evaluated
122
- parent_mapping = if mapping_class.respond_to?(:xml_mapping_instance) &&
122
+ parent_mapping = if mapping_class.is_a?(Class) &&
123
+ (mapping_class < Lutaml::Xml::Mapping || mapping_class.include?(Lutaml::Model::Serialize)) &&
123
124
  mapping_class.xml_mapping_instance
124
125
  mapping_class.xml_mapping_instance
125
126
  else
@@ -133,7 +133,7 @@ module Lutaml
133
133
  def qualified_name(prefix = nil)
134
134
  if prefix
135
135
  "#{prefix}:#{name}"
136
- elsif namespace_class.respond_to?(:prefix_default)
136
+ elsif namespace_class.is_a?(Class) && namespace_class < Lutaml::Xml::Namespace
137
137
  ns_prefix = namespace_class.prefix_default
138
138
  ns_prefix ? "#{ns_prefix}:#{name}" : name
139
139
  else
@@ -202,7 +202,7 @@ module Lutaml
202
202
  def qualified_name(prefix = nil)
203
203
  if prefix
204
204
  "#{prefix}:#{name}"
205
- elsif namespace_class.respond_to?(:prefix_default)
205
+ elsif namespace_class.is_a?(Class) && namespace_class < Lutaml::Xml::Namespace
206
206
  ns_prefix = namespace_class.prefix_default
207
207
  ns_prefix ? "#{ns_prefix}:#{name}" : name
208
208
  else
@@ -129,7 +129,7 @@ module Lutaml
129
129
  return nil unless @element
130
130
 
131
131
  if @element.is_a?(Lutaml::Xml::XmlElement)
132
- @element.namespace_prefix if @element.respond_to?(:namespace_prefix)
132
+ @element.namespace_prefix
133
133
  else
134
134
  # For DataModel::XmlElement, check xml_namespace_prefix first
135
135
  prefix = @element.xml_namespace_prefix
@@ -137,7 +137,7 @@ module Lutaml
137
137
 
138
138
  # Fall back to original XmlElement wrapper if available
139
139
  original = @element.original_xml_element
140
- if original.respond_to?(:namespace_prefix)
140
+ if original.is_a?(Lutaml::Xml::XmlElement)
141
141
  return original.namespace_prefix
142
142
  end
143
143
 
@@ -213,7 +213,7 @@ module Lutaml
213
213
 
214
214
  # Returns all URIs for the current namespace (canonical + aliases).
215
215
  def namespace_all_uris
216
- if @namespace_class.respond_to?(:all_uris)
216
+ if @namespace_class.is_a?(Class) && @namespace_class < Lutaml::Xml::Namespace
217
217
  @namespace_class.all_uris
218
218
  else
219
219
  [@namespace_uri]
@@ -51,7 +51,7 @@ module Lutaml
51
51
 
52
52
  # Only apply if no explicit form option on the element
53
53
  # ElementFormOptionRule (Priority -0.5) handles explicit form options
54
- return false if context.element.respond_to?(:form) && !context.element.form.nil?
54
+ return false if context.element.is_a?(Lutaml::Xml::DataModel::XmlElement) && !context.element.form.nil?
55
55
 
56
56
  true
57
57
  end
@@ -30,7 +30,7 @@ module Lutaml
30
30
  def applies?(context)
31
31
  return false unless context.element
32
32
  # Check if element responds to :form before accessing it
33
- return false unless context.element.respond_to?(:form)
33
+ return false unless context.element.is_a?(Lutaml::Xml::DataModel::XmlElement)
34
34
 
35
35
  # Check if element has form attribute
36
36
  form = context.element.form
@@ -44,7 +44,7 @@ module Lutaml
44
44
  # Skip if namespace does NOT have element_form_default :qualified
45
45
  # Namespaces without explicit :qualified should use default format
46
46
  # (e.g., dcterms namespace uses default format, not prefix)
47
- return false unless ns_class.respond_to?(:element_form_default_set?) &&
47
+ return false unless ns_class.is_a?(Class) && ns_class < Lutaml::Xml::Namespace &&
48
48
  ns_class.element_form_default_set? &&
49
49
  ns_class.element_form_default == :qualified
50
50
 
@@ -441,7 +441,7 @@ module Lutaml
441
441
  ns_classes = []
442
442
  collect_ns_classes_recursive(@root_node, ns_classes)
443
443
  ns_classes.uniq.select do |ns_class|
444
- ns_class.respond_to?(:schema_location) && ns_class.schema_location
444
+ ns_class.is_a?(Class) && ns_class < Lutaml::Xml::Namespace && ns_class.schema_location
445
445
  end
446
446
  end
447
447
 
@@ -452,7 +452,7 @@ module Lutaml
452
452
  # @return [void]
453
453
  def collect_ns_classes_recursive(element_node, ns_classes)
454
454
  # Add namespace from element's own namespace_class
455
- if element_node.respond_to?(:qualified_name) && @namespace_classes
455
+ if element_node.is_a?(Lutaml::Xml::DeclarationPlan::ElementNode) && @namespace_classes
456
456
  # Try to find namespace class from namespace_classes by matching URI
457
457
  # The ElementNode itself doesn't store ns_class, but we can check if
458
458
  # any of our namespace_classes match the element's context