Module: Lutaml::Model::Serialize::ValueMapping

Included in:
ClassMethods
Defined in:
lib/lutaml/model/serialize/value_mapping.rb

Overview

Handles value mapping methods for Serialize::ClassMethods

Extracted from serialize.rb to improve code organization. Provides methods for applying value maps and mappings.

Instance Method Summary collapse

Instance Method Details

#apply_mappings(doc, format, options = {}) ⇒ Object

Apply mappings from a document to create a model instance

Parameters:

  • doc (Hash, Object)

    The document to map from

  • format (Symbol)

    The format (:xml, :json, etc.)

  • options (Hash) (defaults to: {})

    Options including :register, :instance

Returns:

  • (Object)

    The model instance with mapped values



17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/lutaml/model/serialize/value_mapping.rb', line 17

def apply_mappings(doc, format, options = {})
  register = options[:register] || Lutaml::Model::Config.default_register

  # Use child's own default register if it has one
  child_register = Lutaml::Model::Register.resolve_for_child(model,
                                                             register)

  # For blank documents, return a bare instance without going
  # through data_to_model (which would create a duplicate instance).
  if Utils.blank?(doc)
    if options.key?(:instance)
      return options[:instance]
    elsif model.include?(Lutaml::Model::Serialize)
      return model.new({ lutaml_register: child_register })
    else
      object = model.new
      register_accessor_methods_for(object, child_register)
      return object
    end
  end

  mappings = mappings_for(format, register)

  if mappings.polymorphic_mapping
    instance = if model.include?(Lutaml::Model::Serialize)
                 model.new({ lutaml_register: child_register })
               else
                 model.new
               end
    return resolve_polymorphic(doc, format, mappings, instance, options)
  end

  transformer = Lutaml::Model::Config.transformer_for(format)
  transformer.data_to_model(self, doc, format, options)
end

#apply_value_map(value, value_map, attr) ⇒ Object

Apply a value map to transform a value

Handles nil, empty, and omitted values according to the value map.

Parameters:

  • value (Object)

    The value to transform

  • value_map (Hash)

    The value map configuration

  • attr (Attribute)

    The attribute definition

Returns:

  • (Object)

    The transformed value



82
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
# File 'lib/lutaml/model/serialize/value_mapping.rb', line 82

def apply_value_map(value, value_map, attr)
  if value.nil?
    value_for_option(value_map[:nil], attr)
  elsif Utils.empty?(value)
    # Check for new boolean value_map format (from: { empty: true/false })
    # Only use new format if the value is explicitly boolean (TrueClass or FalseClass)
    if value_map[:from] && (value_map[:from][:empty].is_a?(TrueClass) || value_map[:from][:empty].is_a?(FalseClass))
      return value_map[:from][:empty]
    end
    # Check for direct boolean format (rule.value_map(:from) returns { empty: true })
    # Only return directly if it's a boolean value (TrueClass/FalseClass), not a symbol
    if value_map[:empty].is_a?(TrueClass) || value_map[:empty].is_a?(FalseClass)
      return value_map[:empty]
    end

    # Fall back to legacy value_map format
    value_for_option(value_map[:empty], attr, value)
  elsif Utils.uninitialized?(value)
    # Check for new boolean value_map format (from: { omitted: true/false })
    # Only use new format if the value is explicitly boolean (TrueClass or FalseClass)
    if value_map[:from] && (value_map[:from][:omitted].is_a?(TrueClass) || value_map[:from][:omitted].is_a?(FalseClass))
      return value_map[:from][:omitted]
    end
    # Check for direct boolean format (rule.value_map(:from) returns { omitted: false })
    # Only return directly if it's a boolean value (TrueClass/FalseClass), not a symbol
    if value_map[:omitted].is_a?(TrueClass) || value_map[:omitted].is_a?(FalseClass)
      return value_map[:omitted]
    end

    # Fall back to legacy value_map format
    value_for_option(value_map[:omitted], attr)
  else
    value
  end
end

#empty_object(attr) ⇒ String, Array

Get an empty object for an attribute

Parameters:

  • attr (Attribute)

    The attribute definition

Returns:

  • (String, Array)

    Empty string or collection



135
136
137
138
139
# File 'lib/lutaml/model/serialize/value_mapping.rb', line 135

def empty_object(attr)
  return attr.build_collection if attr.collection?

  ""
end

#ensure_utf8(value) ⇒ Object

Ensure a value is UTF-8 encoded

Parameters:

  • value (Object)

    The value to encode

Returns:

  • (Object)

    The UTF-8 encoded value



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
# File 'lib/lutaml/model/serialize/value_mapping.rb', line 145

def ensure_utf8(value)
  case value
  when String
    value.encode("UTF-8", invalid: :replace, undef: :replace,
                          replace: "")
  when Array
    value.map { |v| ensure_utf8(v) }
  when ::Hash
    value.transform_keys do |k|
      ensure_utf8(k)
    end.transform_values do |v|
      ensure_utf8(v)
    end
  else
    value
  end
end

#extract_register_id(register) ⇒ Symbol?

Extract register ID from various formats

Resolution order:

  1. Explicit register parameter

  2. Class instance variable @register (set by set_register_context via registration)

  3. Class’s lutaml_default_register (for versioned schemas)

  4. Global Config.default_register

Parameters:

  • register (Symbol, Register, nil)

    The register

Returns:

  • (Symbol, nil)

    The register ID



188
189
190
191
192
193
194
195
196
# File 'lib/lutaml/model/serialize/value_mapping.rb', line 188

def extract_register_id(register)
  if register
    register.is_a?(Lutaml::Model::Register) ? register.id : register
  elsif instance_variable_defined?(:@register)
    instance_variable_get(:@register)
  else
    lutaml_default_register || Lutaml::Model::Config.default_register
  end
end

#register_accessor_methods_for(object, register) ⇒ Object

Register accessor methods on an object

Parameters:

  • object (Object)

    The object to add methods to

  • register (Symbol)

    The register ID



167
168
169
170
171
172
173
174
175
176
# File 'lib/lutaml/model/serialize/value_mapping.rb', line 167

def register_accessor_methods_for(object, register)
  Utils.add_singleton_method_if_not_defined(object, :lutaml_register) do
    @lutaml_register
  end
  Utils.add_singleton_method_if_not_defined(object,
                                            :lutaml_register=) do |value|
    @lutaml_register = value
  end
  object.lutaml_register = register
end

#resolve_polymorphic(doc, format, mappings, instance, options = {}) ⇒ Object

Resolve a polymorphic type from a document

Parameters:

  • doc (Hash)

    The document to resolve from

  • format (Symbol)

    The format

  • mappings (Mapping)

    The mappings object

  • instance (Object)

    The base instance

  • options (Hash) (defaults to: {})

    Additional options

Returns:

  • (Object)

    The resolved model instance



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/lutaml/model/serialize/value_mapping.rb', line 61

def resolve_polymorphic(doc, format, mappings, instance, options = {})
  polymorphic_mapping = mappings.polymorphic_mapping
  return instance if polymorphic_mapping.polymorphic_map.empty?

  klass_key = doc[polymorphic_mapping.name]
  klass_name = polymorphic_mapping.polymorphic_map[klass_key]
  klass = Object.const_get(klass_name)

  propagated = options.slice(*Lutaml::Model::Attribute::CHILD_PROPAGATION_KEYS)
  klass.apply_mappings(doc, format,
                       propagated.merge(register: instance.lutaml_register))
end

#value_for_option(option, attr, empty_value = nil) ⇒ Object, ...

Get the value for a specific option in a value map

Parameters:

  • option (Symbol)

    The option (:nil, :empty, etc.)

  • attr (Attribute)

    The attribute definition

  • empty_value (Object) (defaults to: nil)

    The empty value to use (optional)

Returns:



124
125
126
127
128
129
# File 'lib/lutaml/model/serialize/value_mapping.rb', line 124

def value_for_option(option, attr, empty_value = nil)
  return nil if option == :nil
  return empty_value || empty_object(attr) if option == :empty

  Lutaml::Model::UninitializedClass.instance
end