Module: Metanorma::Plugin::Lutaml::XmiCache

Included in:
LutamlEaXmiBase
Defined in:
lib/metanorma/plugin/lutaml/xmi_cache.rb

Constant Summary collapse

LUTAML_DOC_CACHE =
CacheStore.new
UML_DOC_CACHE =
CacheStore.new

Instance Method Summary collapse

Instance Method Details

#build_drop_options(parser) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/metanorma/plugin/lutaml/xmi_cache.rb', line 52

def build_drop_options(parser)
  lookup = ::Lutaml::Xmi::XmiLookupService.new(
    parser.xmi_root_model, parser.id_name_mapping
  )
  {
    xmi_root_model: parser.xmi_root_model,
    id_name_mapping: parser.id_name_mapping,
    lookup: lookup,
    with_gen: true,
    with_absolute_path: true,
  }
end

#build_uml_document(xmi_path, _document = nil) ⇒ Object



33
34
35
36
37
38
39
# File 'lib/metanorma/plugin/lutaml/xmi_cache.rb', line 33

def build_uml_document(xmi_path, _document = nil)
  UML_DOC_CACHE.fetch_or_store(xmi_path) do
    xmi_model = ::Xmi::Sparx::Root.parse_xml(File.read(xmi_path))
    parser = ::Lutaml::Xmi::Parsers::Xml.new
    [parser, parser.parse(xmi_model)]
  end
end

#find_packaged_enum(index, name) ⇒ Object



114
115
116
117
# File 'lib/metanorma/plugin/lutaml/xmi_cache.rb', line 114

def find_packaged_enum(index, name)
  index.packaged_elements_of_type("uml:Enumeration")
    .find { |e| e.name == name }
end

#find_packaged_klass(index, path, root_model_name: nil) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/metanorma/plugin/lutaml/xmi_cache.rb', line 77

def find_packaged_klass(index, path, root_model_name: nil)
  segments = path.split("::").reject(&:empty?)
  if root_model_name && segments.first == root_model_name
    segments.shift
  end
  if segments.one?
    index.find_packaged_by_name_and_types(
      segments.first, ["uml:Class", "uml:AssociationClass"]
    )
  else
    find_packaged_klass_by_path(index, segments)
  end
end

#find_packaged_klass_by_path(index, segments) ⇒ Object



91
92
93
94
95
96
97
98
99
100
101
# File 'lib/metanorma/plugin/lutaml/xmi_cache.rb', line 91

def find_packaged_klass_by_path(index, segments)
  klass_name = segments.pop

  candidates = ["uml:Class", "uml:AssociationClass"]
    .flat_map { |t| index.packaged_elements_of_type(t) }
    .select { |e| e.name == klass_name }

  candidates.find do |klass|
    match_parent_chain?(index, klass, segments)
  end
end

#find_uml_node_by_xmi_id(container, xmi_id, collection) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
# File 'lib/metanorma/plugin/lutaml/xmi_cache.rb', line 65

def find_uml_node_by_xmi_id(container, xmi_id, collection)
  found = container.public_send(collection)
    .find { |node| node.xmi_id == xmi_id }
  return found if found

  container.packages.each do |pkg|
    nested = find_uml_node_by_xmi_id(pkg, xmi_id, collection)
    return nested if nested
  end
  nil
end

#load_ea_extensions(yaml_config, yaml_config_path) ⇒ Object



41
42
43
44
45
46
47
48
49
50
# File 'lib/metanorma/plugin/lutaml/xmi_cache.rb', line 41

def load_ea_extensions(yaml_config, yaml_config_path)
  yaml_config.ea_extension&.each do |ea_extension_path|
    ea_extension_full_path = File.expand_path(
      ea_extension_path, File.dirname(yaml_config_path)
    )
    unless Xmi::EaRoot.loaded_extensions.value?(ea_extension_full_path)
      Xmi::EaRoot.load_extension(ea_extension_full_path)
    end
  end
end

#lutaml_document_from_file_or_cache(document, file_path, yaml_config, yaml_config_path = nil) ⇒ Object

rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Layout/LineLength



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/metanorma/plugin/lutaml/xmi_cache.rb', line 14

def lutaml_document_from_file_or_cache(document, file_path, yaml_config, yaml_config_path = nil) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength,Layout/LineLength
  full_path = Utils.relative_file_path(document, file_path)
  cached = document.attributes.dig("lutaml_xmi_cache", full_path)
  return cached if cached

  load_ea_extensions(yaml_config, yaml_config_path)

  guidance = get_guidance(document, yaml_config.guidance)
  cache_key = [full_path, guidance]

  result_document = LUTAML_DOC_CACHE.fetch_or_store(cache_key) do
    parse_result_document(full_path, guidance)
  end

  document.attributes["lutaml_xmi_cache"] ||= {}
  document.attributes["lutaml_xmi_cache"][full_path] = result_document
  result_document
end

#match_parent_chain?(index, element, parent_segments) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
106
107
108
109
110
111
112
# File 'lib/metanorma/plugin/lutaml/xmi_cache.rb', line 103

def match_parent_chain?(index, element, parent_segments)
  current = element
  parent_segments.reverse_each do |pkg_name|
    parent = index.find_parent(current.id)
    return false unless parent && parent.name == pkg_name

    current = parent
  end
  true
end

#serialize_enum_drop_by_name(xmi_path, name, document = nil) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
# File 'lib/metanorma/plugin/lutaml/xmi_cache.rb', line 134

def serialize_enum_drop_by_name(xmi_path, name, document = nil)
  parser, uml_doc = build_uml_document(xmi_path, document)
  raw_enum = find_packaged_enum(parser.xmi_index, name)
  warn "Enumeration not found for name: #{name}" if raw_enum.nil?
  enum = raw_enum && find_uml_node_by_xmi_id(
    uml_doc, raw_enum.id, :enums
  )
  ::Lutaml::Xmi::LiquidDrops::EnumDrop.new(
    enum, build_drop_options(parser)
  )
end

#serialize_klass_drop_by_name(xmi_path, name, document = nil, guidance = nil) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/metanorma/plugin/lutaml/xmi_cache.rb', line 119

def serialize_klass_drop_by_name(xmi_path, name, document = nil,
guidance = nil)
  parser, uml_doc = build_uml_document(xmi_path, document)
  root_model_name = parser.xmi_root_model.model.name
  raw_klass = find_packaged_klass(parser.xmi_index, name,
                                  root_model_name: root_model_name)
  warn "Class not found for name: #{name}" if raw_klass.nil?
  klass = raw_klass && find_uml_node_by_xmi_id(
    uml_doc, raw_klass.id, :classes
  )
  ::Lutaml::Xmi::LiquidDrops::KlassDrop.new(
    klass, guidance, build_drop_options(parser)
  )
end