Module: Uniword::Ooxml::ElementOrder

Defined in:
lib/uniword/ooxml/element_order.rb

Overview

Safe mutation of lutaml-model element_order arrays.

lutaml-model freezes element_order on parsed models; mutating it raises FrozenError. These helpers thaw on demand (dup + assign back) and insert entries in schema position — the single mechanism for the whole library, not a monkey-patch.

Examples:

Thaw and append

order = Ooxml::ElementOrder.mutable_order(footnotes)
order << Lutaml::Xml::Element.new("Element", "footnote")

Idempotent singleton insert

Ooxml::ElementOrder.insert_once(settings, "updateFields",
                                 after: "characterSpacingControl")

Class Method Summary collapse

Class Method Details

.append(model, entry) ⇒ Array?

Append an entry (repeatable elements allowed).

Parameters:

  • model (Lutaml::Model::Serializable)

    model to mutate

  • entry (Lutaml::Xml::Element)

    entry to append

Returns:

  • (Array, nil)

    the mutated order



43
44
45
# File 'lib/uniword/ooxml/element_order.rb', line 43

def append(model, entry)
  mutable_order(model)&.<<(entry)
end

.insert_at(model, position, entry) ⇒ Array?

Insert an entry at an index (repeatable elements allowed).

Parameters:

  • model (Lutaml::Model::Serializable)

    model to mutate

  • position (Integer)

    insertion index

  • entry (Lutaml::Xml::Element)

    entry to insert

Returns:

  • (Array, nil)

    the mutated order



54
55
56
# File 'lib/uniword/ooxml/element_order.rb', line 54

def insert_at(model, position, entry)
  mutable_order(model)&.insert(position, entry)
end

.insert_once(model, name, after: nil, before: nil, position: nil) ⇒ Array?

Insert a singleton element in schema position, by name. Idempotent: no-op when an entry of that name already exists. Missing anchors fall back to end (after:) or start (before:).

Parameters:

  • model (Lutaml::Model::Serializable)

    model to mutate

  • name (String)

    element name to insert

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

    insert after this element name

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

    insert before this element name

  • position (Integer, nil) (defaults to: nil)

    explicit index (when neither after nor before is given; defaults to end)

Returns:

  • (Array, nil)

    the mutated order



70
71
72
73
74
75
76
77
# File 'lib/uniword/ooxml/element_order.rb', line 70

def insert_once(model, name, after: nil, before: nil, position: nil)
  order = mutable_order(model)
  return unless order
  return if order.any? { |e| e.name == name }

  idx = insertion_index(order, after, before, position)
  order.insert(idx, Lutaml::Xml::Element.new("Element", name))
end

.insertion_index(order, after, before, position) ⇒ Integer

Returns index for the insert.

Returns:

  • (Integer)

    index for the insert



81
82
83
84
85
86
87
88
89
90
# File 'lib/uniword/ooxml/element_order.rb', line 81

def insertion_index(order, after, before, position)
  if after
    anchor = order.index { |e| e.name == after }
    anchor ? anchor + 1 : order.size
  elsif before
    order.index { |e| e.name == before } || 0
  else
    position || order.size
  end
end

.mutable_order(model) ⇒ Array?

Return the model's element_order as a mutable array.

The frozen parsed array is replaced by a dup assigned back to the model; already-mutable arrays are returned as-is (so repeated calls keep mutating the same registered array).

Parameters:

  • model (Lutaml::Model::Serializable)

    model to thaw

Returns:

  • (Array, nil)

    mutable element_order, or nil when the model carries none



29
30
31
32
33
34
35
# File 'lib/uniword/ooxml/element_order.rb', line 29

def mutable_order(model)
  order = model.element_order
  return unless order
  return order unless order.frozen?

  model.element_order = order.dup
end