Class: Lutaml::Xml::ParseSession

Inherits:
Object
  • Object
show all
Defined in:
lib/lutaml/xml/parse_session.rb

Overview

Per-parse context threaded through ModelTransform's mapping passes.

Bundles everything one data_to_model call needs — the parsed doc, the instance under construction, the effective register, and the flags derived from them — so apply_xml_mapping and value_for_rule take one object instead of a growing positional parameter list. Memoizes the per-parse lookups (mapping, namespace class, adopted document namespace) that every rule would otherwise recompute.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(doc, instance, options, register) ⇒ ParseSession

Returns a new instance of ParseSession.



16
17
18
19
20
21
# File 'lib/lutaml/xml/parse_session.rb', line 16

def initialize(doc, instance, options, register)
  @doc = doc
  @instance = instance
  @options = options
  @register = register
end

Instance Attribute Details

#docObject (readonly)

Returns the value of attribute doc.



14
15
16
# File 'lib/lutaml/xml/parse_session.rb', line 14

def doc
  @doc
end

#instanceObject (readonly)

Returns the value of attribute instance.



14
15
16
# File 'lib/lutaml/xml/parse_session.rb', line 14

def instance
  @instance
end

#optionsObject (readonly)

Returns the value of attribute options.



14
15
16
# File 'lib/lutaml/xml/parse_session.rb', line 14

def options
  @options
end

#registerObject (readonly)

Returns the value of attribute register.



14
15
16
# File 'lib/lutaml/xml/parse_session.rb', line 14

def register
  @register
end

Instance Method Details

#adopted_namespace_uriObject

The document's own namespace when it differs from the model's bound namespace (lenient, out-of-namespace documents). Adopted as an implicit alias for element matching (lutaml-model#754).



101
102
103
104
# File 'lib/lutaml/xml/parse_session.rb', line 101

def adopted_namespace_uri
  @adopted_namespace_uri ||=
    instance_is_serialize ? instance.original_namespace_uri : nil
end

#element_local_attribute_index(element) ⇒ Object

Local-name -> [attributes] index over one element's attributes, built on first lenient lookup (TODO.max-perf/08) and memoized per element for the life of the session. The URI-form attribute conversion and the lenient fallback used to rescan every attribute per rule per element (the ISO-13849 pathology); elements are parse-frozen, so each index builds at most once.



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/lutaml/xml/parse_session.rb', line 51

def element_local_attribute_index(element)
  @element_local_attribute_index ||= {}.compare_by_identity
  @element_local_attribute_index[element] ||= begin
    # Plain hash: a miss must stay a nil lookup, not allocate an
    # empty default array — misses dominate (the ISO-13849 shape
    # resolves ~390k lenient lookups that match nothing).
    index = {}
    element.attributes.each_value do |attr|
      local_names(attr).each do |key|
        entries = (index[key] ||= [])
        entries << attr unless entries.include?(attr)
      end
    end
    index
  end
end

#instance_is_serializeObject



23
24
25
# File 'lib/lutaml/xml/parse_session.rb', line 23

def instance_is_serialize
  @instance_is_serialize ||= instance.is_a?(::Lutaml::Model::Serialize)
end

#lenient_local_matches(element, flexible_local) ⇒ Object

Lenient local-name fallback matches, per (element, flexible_local): spelling -> matched attribute VALUE. Same purity argument as rule_name_resolution — elements are parse-frozen.



40
41
42
43
# File 'lib/lutaml/xml/parse_session.rb', line 40

def lenient_local_matches(element, flexible_local)
  @lenient_local_matches ||= {}.compare_by_identity
  (@lenient_local_matches[element] ||= {})[flexible_local] ||= {}
end

#model_classObject



90
91
92
# File 'lib/lutaml/xml/parse_session.rb', line 90

def model_class
  @model_class ||= instance.class
end

#model_namespace_urisObject

Namespace URIs accepted for children of this model: the model's namespace URIs plus the adopted document namespace when present.



108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/lutaml/xml/parse_session.rb', line 108

def model_namespace_uris
  @model_namespace_uris ||=
    begin
      ns_class = instance_is_serialize ? xml_mapping&.namespace_class : nil
      uris = ns_class&.all_uris
      adopted = adopted_namespace_uri
      if ns_class && adopted && !uris&.include?(adopted)
        uris = (uris || []) + [adopted]
      end
      uris
    end
end

#rule_name_resolution(element) ⇒ Object

(element, rule name) -> resolved attribute name / matched attribute VALUE for the lenient lookup paths. Both are pure functions of the element and the name; ISO-13849-shaped documents repeat the same resolutions per rule application, so the computed answer is memoized per element for the parse.



32
33
34
35
# File 'lib/lutaml/xml/parse_session.rb', line 32

def rule_name_resolution(element)
  @rule_name_resolution ||= {}.compare_by_identity
  @rule_name_resolution[element] ||= {}
end

#when_attribute_siblings_by_nameObject

lutaml-model#88: element wire names partitioned by when_attribute rules, as name -> discriminator rules. A plain rule on a partitioned name captures only occurrences no discriminator claimed — the mirror of ordered-serialization routing, so each occurrence is captured exactly once instead of double-captured by the plain rule and its discriminator sibling. Empty unless the mapping uses when_attribute at all; non-Serialize custom models have no mappings to partition.



76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/lutaml/xml/parse_session.rb', line 76

def when_attribute_siblings_by_name
  @when_attribute_siblings_by_name ||=
    if instance_is_serialize && (mapping = xml_mapping)
      mapping.mappings.each_with_object({}) do |rule, index|
        pairs = rule.when_attribute
        next if pairs.nil? || pairs.empty?

        (index[rule.name.to_s] ||= []) << rule
      end
    else
      {}
    end
end

#xml_mappingObject



94
95
96
# File 'lib/lutaml/xml/parse_session.rb', line 94

def xml_mapping
  @xml_mapping ||= model_class.mappings_for(:xml, register)
end