Class: Lutaml::KeyValue::Mapping

Inherits:
Model::Mapping
  • Object
show all
Defined in:
lib/lutaml/key_value/mapping.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(format = nil) ⇒ Mapping

Returns a new instance of Mapping.



6
7
8
9
10
11
12
13
14
# File 'lib/lutaml/key_value/mapping.rb', line 6

def initialize(format = nil)
  super()
  @mappings = {}
  @key_mapping = {}
  @value_mapping = {}
  @register_mappings = ::Hash.new { |h, k| h[k] = {} }
  @format = format
  @finalized = false
end

Instance Attribute Details

#formatObject (readonly)

Returns the value of attribute format.



4
5
6
# File 'lib/lutaml/key_value/mapping.rb', line 4

def format
  @format
end

#key_mappingObject (readonly)

Returns the value of attribute key_mapping.



4
5
6
# File 'lib/lutaml/key_value/mapping.rb', line 4

def key_mapping
  @key_mapping
end

#register_mappings=(value) ⇒ Object (writeonly)

Writers for deep_dup in subclasses



307
308
309
# File 'lib/lutaml/key_value/mapping.rb', line 307

def register_mappings=(value)
  @register_mappings = value
end

#value_mappingObject (readonly)

Returns the value of attribute value_mapping.



4
5
6
# File 'lib/lutaml/key_value/mapping.rb', line 4

def value_mapping
  @value_mapping
end

Instance Method Details

#deep_dupObject



309
310
311
312
313
314
# File 'lib/lutaml/key_value/mapping.rb', line 309

def deep_dup
  dup_instance.tap do |new_mapping|
    new_mapping.mappings = duplicate_mappings
    new_mapping.register_mappings = Lutaml::Model::Utils.deep_dup(@register_mappings)
  end
end

#dup_instanceObject



316
317
318
# File 'lib/lutaml/key_value/mapping.rb', line 316

def dup_instance
  self.class.new(@format)
end

#finalize(_mapper_class) ⇒ Object



16
17
18
# File 'lib/lutaml/key_value/mapping.rb', line 16

def finalize(_mapper_class)
  @finalized = true
end

#finalized?Boolean

Returns:

  • (Boolean)


20
21
22
# File 'lib/lutaml/key_value/mapping.rb', line 20

def finalized?
  @finalized
end

#find_by_name(name) ⇒ Object



332
333
334
# File 'lib/lutaml/key_value/mapping.rb', line 332

def find_by_name(name)
  mappings.find { |m| m.name.to_s == name.to_s }
end

#find_by_to(to) ⇒ Object



320
321
322
# File 'lib/lutaml/key_value/mapping.rb', line 320

def find_by_to(to)
  mappings.find { |m| m.to.to_s == to.to_s }
end

#find_by_to!(to) ⇒ Object



324
325
326
327
328
329
330
# File 'lib/lutaml/key_value/mapping.rb', line 324

def find_by_to!(to)
  mapping = find_by_to(to)

  return mapping if !!mapping

  raise Lutaml::Model::NoMappingFoundError.new(to.to_s)
end

#import_model_mappings(model, register_id = nil) ⇒ Object



237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/lutaml/key_value/mapping.rb', line 237

def import_model_mappings(model, register_id = nil)
  reg_id = register(register_id).id
  return import_mappings_later(model, reg_id) if model_importable?(model)

  if reg_id == :default
    @mappings.merge!(::Lutaml::Model::Utils.deep_dup(model.mappings_for(
      @format, reg_id
    ).mappings_hash))
  else
    @register_mappings[register_id].merge!(
      ::Lutaml::Model::Utils.deep_dup(model.mappings_for(@format,
                                                         register_id).mappings_hash),
    )
  end
end

#instance_mapping?Boolean

Returns:

  • (Boolean)


205
206
207
# File 'lib/lutaml/key_value/mapping.rb', line 205

def instance_mapping?
  @instance && (!@key_mapping.empty? || !@value_mapping.empty?)
end

#key(name = nil) ⇒ Object

Set the wrapper key for key-value serialization (JSON, YAML, TOML).

When set, serialized output wraps all instances under this key (e.g., key "items" produces {"items": [...]}). When not called (or called with nil), instances are serialized directly at the top level (e.g., [...]).

Parameters:

  • name (String, nil) (defaults to: nil)

    the wrapper key name



32
33
34
# File 'lib/lutaml/key_value/mapping.rb', line 32

def key(name = nil)
  @key = name
end

#key_nameObject



36
37
38
# File 'lib/lutaml/key_value/mapping.rb', line 36

def key_name
  @key
end

#map(name = nil, to: nil, render_nil: false, render_default: false, render_empty: false, treat_nil: nil, treat_empty: nil, treat_omitted: nil, with: {}, delegate: nil, child_mappings: nil, root_mappings: nil, polymorphic: {}, polymorphic_map: {}, transform: {}, value_map: {}, when_attribute: {}, unmatched: :drop, serialize: true) ⇒ Object Also known as: map_element



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/lutaml/key_value/mapping.rb', line 65

def map(
  name = nil,
  to: nil,
  render_nil: false,
  render_default: false,
  render_empty: false,
  treat_nil: nil,
  treat_empty: nil,
  treat_omitted: nil,
  with: {},
  delegate: nil,
  child_mappings: nil,
  root_mappings: nil,
  polymorphic: {},
  polymorphic_map: {},
  transform: {},
  value_map: {},
  when_attribute: {},
  unmatched: :drop,
  serialize: true
)
  mapping_name = name_for_mapping(root_mappings, name)
  validate!(mapping_name, to, with, render_nil, render_empty)

  # lutaml-model#88: grouped form — `when_attribute: "type"` plus
  # `to: { value => attribute }` expands to one rule per value at
  # DSL time; the compiled rules are identical to the per-rule
  # form, so parse/serialize behavior and speed are unchanged.
  if when_attribute.is_a?(::String) || when_attribute.is_a?(::Symbol)
    when_attribute_group(when_attribute, to).each do |value, target|
      map(
        name,
        to: target,
        render_nil: render_nil,
        render_default: render_default,
        render_empty: render_empty,
        treat_nil: treat_nil,
        treat_empty: treat_empty,
        treat_omitted: treat_omitted,
        with: with,
        delegate: delegate,
        child_mappings: child_mappings,
        root_mappings: root_mappings,
        polymorphic: polymorphic,
        polymorphic_map: polymorphic_map,
        transform: transform,
        value_map: value_map,
        when_attribute: { when_attribute.to_s => value.to_s },
        unmatched: unmatched,
        serialize: serialize,
      )
    end
    return
  end
  reject_ambiguous_when_attribute!(when_attribute, to)

  validate_when_attribute!(when_attribute) unless when_attribute.empty?
  validate_unmatched!(unmatched, when_attribute)
  if !when_attribute.empty? && (!with.empty? || delegate)
    raise Lutaml::Model::IncorrectMappingArgumentsError,
          "when_attribute cannot be combined with :with or :delegate " \
          "in key-value mappings"
  end

  rule = MappingRule.new(
    mapping_name,
    to: to,
    render_nil: render_nil,
    render_default: render_default,
    render_empty: render_empty,
    treat_nil: treat_nil,
    treat_empty: treat_empty,
    treat_omitted: treat_omitted,
    with: with,
    delegate: delegate,
    child_mappings: child_mappings,
    root_mappings: root_mappings,
    polymorphic: polymorphic,
    polymorphic_map: polymorphic_map,
    transform: transform,
    value_map: value_map,
    when_attribute: when_attribute,
    unmatched: unmatched,
    serialize: serialize,
  )
  # lutaml-model#88: rules may share a wire key (when_attribute
  # partitions) — store per-key arrays, like the XML mapping. A
  # rule redefining the same target (`to:`) replaces its
  # predecessor, so subclass and redeclaration overrides keep the
  # pre-array replace semantics.
  existing = @mappings[mapping_name]
  if existing.nil?
    @mappings[mapping_name] = [rule]
  elsif (index = existing.index { |r| r.to == rule.to })
    existing[index] = rule
  else
    existing << rule
  end
end

#map_all(to: nil, render_nil: false, render_default: false, with: {}, delegate: nil) ⇒ Object Also known as: map_all_content



167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'lib/lutaml/key_value/mapping.rb', line 167

def map_all(
  to: nil,
  render_nil: false,
  render_default: false,
  with: {},
  delegate: nil
)
  @raw_mapping = true
  validate!(Lutaml::Model::Constants::RAW_MAPPING_KEY, to, with,
            render_nil, nil)
  @mappings[Lutaml::Model::Constants::RAW_MAPPING_KEY] = [MappingRule.new(
    Lutaml::Model::Constants::RAW_MAPPING_KEY,
    to: to,
    render_nil: render_nil,
    render_default: render_default,
    with: with,
    delegate: delegate,
  )]
end

#map_instances(to:, polymorphic: {}) ⇒ Object



189
190
191
192
193
# File 'lib/lutaml/key_value/mapping.rb', line 189

def map_instances(to:, polymorphic: {})
  @instance = to
  map(key_name || to, to: to, polymorphic: polymorphic)
  map_to_instance
end

#map_key(to_instance: nil, as_attribute: nil) ⇒ Object



195
196
197
198
# File 'lib/lutaml/key_value/mapping.rb', line 195

def map_key(to_instance: nil, as_attribute: nil)
  @key_mapping = { "#{to_instance || as_attribute}": :key }
  map_to_instance
end

#map_to_instanceObject



209
210
211
212
213
214
215
216
# File 'lib/lutaml/key_value/mapping.rb', line 209

def map_to_instance
  return if !instance_mapping?

  mapping_name = name_for_mapping(nil, key_name || @instance)
  @mappings[mapping_name].each do |rule|
    rule.child_mappings = @key_mapping.merge(@value_mapping)
  end
end

#map_value(to_instance: nil, as_attribute: nil) ⇒ Object



200
201
202
203
# File 'lib/lutaml/key_value/mapping.rb', line 200

def map_value(to_instance: nil, as_attribute: nil)
  @value_mapping = { "#{to_instance || as_attribute}": :value }
  map_to_instance
end

#mappings(register_id = nil) ⇒ Object



224
225
226
227
# File 'lib/lutaml/key_value/mapping.rb', line 224

def mappings(register_id = nil)
  ensure_mappings_imported!(register_id) if finalized?
  mappings_hash(register_id).values.flatten
end

#mappings_hash(register_id = nil) ⇒ Object



229
230
231
232
233
234
235
# File 'lib/lutaml/key_value/mapping.rb', line 229

def mappings_hash(register_id = nil)
  if register_id.nil? || register_id == :default
    @mappings
  else
    @mappings.merge(@register_mappings[register_id])
  end
end

#name_for_mapping(root_mappings, name) ⇒ Object



218
219
220
221
222
# File 'lib/lutaml/key_value/mapping.rb', line 218

def name_for_mapping(root_mappings, name)
  return "root_mapping" if root_mappings

  name
end

#no_key?Boolean

Returns true when no wrapper key is set (instances serialized at top level).

Returns:

  • (Boolean)


51
52
53
# File 'lib/lutaml/key_value/mapping.rb', line 51

def no_key?
  @key.nil?
end

#no_rootObject

Deprecated.

Omit key call instead. Not calling key means no wrapper key.



46
47
48
# File 'lib/lutaml/key_value/mapping.rb', line 46

def no_root
  @key = nil
end

#no_root?Boolean

Deprecated.

Use #no_key? instead.

Returns:

  • (Boolean)


56
57
58
# File 'lib/lutaml/key_value/mapping.rb', line 56

def no_root?
  no_key?
end

#polymorphic_mappingObject



336
337
338
# File 'lib/lutaml/key_value/mapping.rb', line 336

def polymorphic_mapping
  mappings.find(&:polymorphic_mapping?)
end

#root(name = nil) ⇒ Object

Deprecated.

Use #key instead. In key-value formats, the wrapper is a key, not a root.



41
42
43
# File 'lib/lutaml/key_value/mapping.rb', line 41

def root(name = nil)
  @key = name
end

#root_mappingObject



340
341
342
# File 'lib/lutaml/key_value/mapping.rb', line 340

def root_mapping
  mappings.find(&:root_mapping?)
end

#root_nameObject

Deprecated.

Use #key_name instead.



61
62
63
# File 'lib/lutaml/key_value/mapping.rb', line 61

def root_name
  @key
end

#validate!(key, to, with, render_nil, render_empty) ⇒ Object



253
254
255
256
257
258
259
260
# File 'lib/lutaml/key_value/mapping.rb', line 253

def validate!(key, to, with, render_nil, render_empty)
  validate_mappings!(key)
  validate_to_and_with_arguments!(key, to, with)

  # Validate `render_nil` for unsupported value
  validate_blank_mappings!(render_nil, render_empty)
  validate_root_mappings!(key)
end

#validate_blank_mappings!(render_nil, render_empty) ⇒ Object



290
291
292
293
294
295
296
297
# File 'lib/lutaml/key_value/mapping.rb', line 290

def validate_blank_mappings!(render_nil, render_empty)
  if render_nil == :as_blank || render_empty == :as_blank
    raise Lutaml::Model::IncorrectMappingArgumentsError.new(
      ":as_blank is not supported for key-value mappings. " \
      "Use :as_empty instead to create explicit empty values.",
    )
  end
end

#validate_mappings!(_type) ⇒ Object



299
300
301
302
303
304
# File 'lib/lutaml/key_value/mapping.rb', line 299

def validate_mappings!(_type)
  if (@raw_mapping && Lutaml::Model::Utils.present?(@mappings)) ||
      (!@raw_mapping && mappings.any?(&:raw_mapping?))
    raise StandardError, "map_all is not allowed with other mappings"
  end
end

#validate_root_mappings!(name) ⇒ Object



282
283
284
285
286
287
288
# File 'lib/lutaml/key_value/mapping.rb', line 282

def validate_root_mappings!(name)
  if root_mapping || (name == "root_mapping" && @mappings.any?)
    raise Lutaml::Model::MultipleMappingsError.new(
      "root_mappings cannot be used with other mappings",
    )
  end
end

#validate_to_and_with_arguments!(key, to, with) ⇒ Object



262
263
264
265
266
267
268
269
270
# File 'lib/lutaml/key_value/mapping.rb', line 262

def validate_to_and_with_arguments!(key, to, with)
  if to.nil? && with.empty? && !@raw_mapping
    raise Lutaml::Model::IncorrectMappingArgumentsError.new(
      ":to or :with argument is required for mapping '#{key}'",
    )
  end

  validate_with_options!(to, key, with)
end

#validate_with_options!(to, key, with) ⇒ Object



272
273
274
275
276
277
278
279
280
# File 'lib/lutaml/key_value/mapping.rb', line 272

def validate_with_options!(to, key, with)
  return true if to

  if !with.empty? && (with[:from].nil? || with[:to].nil?) && !@raw_mapping
    raise Lutaml::Model::IncorrectMappingArgumentsError.new(
      ":with argument for mapping '#{key}' requires :to and :from keys",
    )
  end
end