Module: Lutaml::Model::Serialize::FormatConversion
- Included in:
- ClassMethods
- Defined in:
- lib/lutaml/model/serialize/format_conversion.rb
Overview
Handles format conversion methods for Serialize::ClassMethods
Extracted from serialize.rb to improve code organization. Provides methods for serializing/deserializing between formats.
Instance Method Summary collapse
-
#as(format, instance, options = {}) ⇒ Object
Convert a model instance to format-specific data structure.
-
#default_mappings(format) ⇒ Mapping
Generate default mappings for a format.
-
#format_error_types ⇒ Array<Class>
Get list of error types that can be raised during format parsing.
-
#from(format, data, options = {}) ⇒ Object
Deserialize from a format.
-
#key_value(&block) ⇒ Object
Define key-value mappings for multiple formats.
-
#mappings_for(format, register = nil) ⇒ Mapping?
Get resolved mapping for a format.
-
#of(format, doc, options = {}) ⇒ Object
Create a model instance from a parsed document.
-
#post_process_mapping(_format) ⇒ Object
Hook for format-specific post-processing after mapping DSL evaluation.
-
#pre_deserialize_hook(_format, _register) ⇒ Object
Hook for format-specific pre-deserialization logic.
-
#pre_serialize_hook(_format, _register) ⇒ Object
Hook for format-specific pre-serialization logic.
-
#prepare_to_options(_format, _instance, options) ⇒ Hash
Hook for format-specific options preparation before serialization.
-
#process_mapping(format, *_args) ⇒ Object
Process mapping DSL for a format.
-
#reset_format_error_types_cache! ⇒ Object
Reset cached error types (for test isolation).
-
#to(format, instance, options = {}) ⇒ String
Serialize a model instance to a format.
-
#validate_document(_format, _doc, _options, _register) ⇒ Object
Hook for format-specific document validation.
Instance Method Details
#as(format, instance, options = {}) ⇒ Object
Convert a model instance to format-specific data structure
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 203 def as(format, instance, = {}) if instance.is_a?(Array) return instance.map { |item| public_send(:"as_#{format}", item) } end unless instance.is_a?(model) msg = "argument is a '#{instance.class}' but should be a '#{model}'" raise Lutaml::Model::IncorrectModelError, msg end # Resolve imports at the start of serialization register = [:register] || Lutaml::Model::Config.default_register # Hook for format-specific pre-serialization (e.g., XML mapping import resolution) pre_serialize_hook(format, register) # Recursively resolve child model imports ensure_child_imports_resolved!(register) transformer = Lutaml::Model::Config.transformer_for(format) transformer.model_to_data(self, instance, format, ) end |
#default_mappings(format) ⇒ Mapping
Generate default mappings for a format
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 278 def default_mappings(format) klass = ::Lutaml::Model::Config.mappings_class_for(format) mappings = klass.new mappings.tap do |mapping| attributes&.each_key do |name| mapping.map_element( name.to_s, to: name, ) end # DO NOT auto-generate root element for XML # Models without an explicit xml block should be type-only models # If a root element is needed, declare it explicitly in xml block end end |
#format_error_types ⇒ Array<Class>
Get list of error types that can be raised during format parsing. Core errors are always included; format-specific errors come from FormatRegistry registrations.
Performance: Cached base types + lazy TOML lookup. Tomlib::ParseError is lazily loaded, so we check for it on each call rather than caching a stale nil reference.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 83 def format_error_types @format_error_types_base ||= begin errors = [ Lutaml::Model::RuntimeCompatibility.safe_constantize("Psych::SyntaxError"), Lutaml::Model::RuntimeCompatibility.safe_constantize("JSON::ParserError"), NoMethodError, TypeError, ArgumentError, ] # Collect format-specific error types from FormatRegistry compatibility = Lutaml::Model::RuntimeCompatibility FormatRegistry.all.each_value do |info| next unless info[:error_types] info[:error_types].each do |error_class| cls = if error_class.is_a?(String) compatibility.safe_constantize(error_class) else error_class end errors << cls end end errors.compact.freeze end # Legacy TOML error types are lazy, so check them on each call. compatibility = Lutaml::Model::RuntimeCompatibility toml_errors = compatibility.safe_constantize("TomlRB::ParseError") toml_errors = Array(toml_errors) tomllib_err = compatibility.safe_constantize("Tomlib::ParseError") toml_errors << tomllib_err if tomllib_err @format_error_types_base + toml_errors end |
#from(format, data, options = {}) ⇒ Object
Deserialize from a format
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 42 def from(format, data, = {}) Instrumentation.instrument(:from, model: name, format: format) do adapter = Lutaml::Model::Config.adapter_for(format) raise Lutaml::Model::FormatAdapterNotSpecifiedError.new(format) if adapter.nil? # Resolve imports at the entry point of deserialization register = [:register] || Lutaml::Model::Config.default_register # Hook for format-specific pre-deserialization (e.g., XML mapping import resolution) pre_deserialize_hook(format, register) # Recursively resolve child model imports # This ensures the entire model tree is finalized before parsing ensure_child_imports_resolved!(register) doc = adapter.parse(data, ) send("of_#{format}", doc, ) end rescue *format_error_types => e raise Lutaml::Model::InvalidFormatError.new(format, e.) end |
#key_value(&block) ⇒ Object
Define key-value mappings for multiple formats. Uses FormatRegistry to discover key-value formats dynamically, falling back to Config::KEY_VALUE_FORMATS for bootstrap.
240 241 242 243 244 245 246 247 248 249 250 251 252 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 240 def key_value(&block) formats = if FormatRegistry.formats.any? FormatRegistry.key_value_formats else Lutaml::Model::Config::KEY_VALUE_FORMATS end formats.each do |format| mappings[format] ||= Lutaml::KeyValue::Mapping.new(format) mappings[format].instance_eval(&block) mappings[format].finalize(self) end end |
#mappings_for(format, register = nil) ⇒ Mapping?
Get resolved mapping for a format
Delegates to TransformationRegistry for centralized caching (Single Source of Truth - Phase 11.5).
Register resolution: If the caller passes a parent register (e.g., :default) but this class declares its own ‘lutaml_default_register`, the child’s register takes precedence. This ensures mappings are resolved in the correct context for cross-register embedding.
267 268 269 270 271 272 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 267 def mappings_for(format, register = nil) resolved_register = Lutaml::Model::Register.resolve_for_child(self, register) TransformationRegistry.instance.get_or_build_mapping(self, format, resolved_register) end |
#of(format, doc, options = {}) ⇒ Object
Create a model instance from a parsed document
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 132 def of(format, doc, = {}) if doc.is_a?(Array) && format != :jsonl return doc.map { |item| send(:"of_#{format}", item) } end register = extract_register_id([:register]) # Hook for format-specific document validation (e.g., XML root/encoding/doctype) validate_document(format, doc, , register) [:register] = register transformer = Lutaml::Model::Config.transformer_for(format) transformer.data_to_model(self, doc, format, ) end |
#post_process_mapping(_format) ⇒ Object
Hook for format-specific post-processing after mapping DSL evaluation. XML overrides this to call check_sort_configs!.
32 33 34 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 32 def post_process_mapping(_format) # No-op by default; XML overrides via prepend end |
#pre_deserialize_hook(_format, _register) ⇒ Object
Hook for format-specific pre-deserialization logic. XML overrides to resolve XML mapping imports.
70 71 72 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 70 def pre_deserialize_hook(_format, _register) # No-op by default; XML overrides via prepend end |
#pre_serialize_hook(_format, _register) ⇒ Object
Hook for format-specific pre-serialization logic. XML overrides to resolve XML mapping imports.
231 232 233 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 231 def pre_serialize_hook(_format, _register) # No-op by default; XML overrides via prepend end |
#prepare_to_options(_format, _instance, options) ⇒ Hash
Hook for format-specific options preparation before serialization. XML overrides to handle prefix, namespace overrides, declaration plan.
193 194 195 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 193 def (_format, _instance, ) end |
#process_mapping(format, *_args) ⇒ Object
Process mapping DSL for a format
16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 16 def process_mapping(format, *_args, &) klass = ::Lutaml::Model::Config.mappings_class_for(format) mappings[format] ||= klass.new mappings[format].instance_eval(&) if mappings[format].respond_to?(:finalize) mappings[format].finalize(self) end post_process_mapping(format) end |
#reset_format_error_types_cache! ⇒ Object
Reset cached error types (for test isolation)
122 123 124 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 122 def reset_format_error_types_cache! @format_error_types_base = nil end |
#to(format, instance, options = {}) ⇒ String
Serialize a model instance to a format
172 173 174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 172 def to(format, instance, = {}) Instrumentation.instrument(:to, model: name, format: format) do value = public_send(:"as_#{format}", instance, ) adapter = Lutaml::Model::Config.adapter_for(format) # Hook for format-specific options preparation (e.g., XML prefix/namespace/declaration) = (format, instance, ) adapter.new(value, register: [:register]).public_send( :"to_#{format}", ) end end |
#validate_document(_format, _doc, _options, _register) ⇒ Object
Hook for format-specific document validation. XML overrides to validate root mapping and extract encoding/doctype.
155 156 157 |
# File 'lib/lutaml/model/serialize/format_conversion.rb', line 155 def validate_document(_format, _doc, , _register) # No-op by default; XML overrides via prepend end |