Class: Ea::Xmi::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/ea/xmi/parser.rb

Overview

Parses EA XMI files into Lutaml::Uml::Document objects.

Consolidates what was previously 6 separate modules (Xml, XmiBase, XmiConnector, XmiClassMembers, XmiToUml, XmiToUmlGeneralization) into a single coherent class.

The XMI format handled here is EA/Sparx-specific.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#xmi_root_modelObject (readonly)

Public read access for collaborators (LookupService)



56
57
58
# File 'lib/ea/xmi/parser.rb', line 56

def xmi_root_model
  @xmi_root_model
end

Class Method Details

.parse(xml) ⇒ Object

Parse an XMI file into a UML Document.



18
19
20
# File 'lib/ea/xmi/parser.rb', line 18

def parse(xml)
  new.parse(get_xmi_model(xml))
end

.serialize_to_liquid(xml, guidance = nil) ⇒ Object

Parse XMI and serialize to Liquid drops for template rendering.



23
24
25
# File 'lib/ea/xmi/parser.rb', line 23

def serialize_to_liquid(xml, guidance = nil)
  new.serialize_to_liquid(get_xmi_model(xml), guidance)
end

Instance Method Details

#all_packaged_elementsObject



219
220
221
# File 'lib/ea/xmi/parser.rb', line 219

def all_packaged_elements
  xmi_index.packaged_elements
end

#doc_node_attribute_value(node_id, attr_name) ⇒ Object



170
171
172
173
174
175
176
177
# File 'lib/ea/xmi/parser.rb', line 170

def doc_node_attribute_value(node_id, attr_name)
  doc_node = fetch_element(node_id)
  return unless doc_node

  doc_node.properties&.public_send(
    Lutaml::Model::Utils.snake_case(attr_name).to_sym
  )
end

#fetch_attribute_node(xmi_id) ⇒ Object



215
216
217
# File 'lib/ea/xmi/parser.rb', line 215

def fetch_attribute_node(xmi_id)
  xmi_index.find_attribute(xmi_id)
end

#fetch_connector(link_id) ⇒ Object

Public lookup methods used by LookupService and Liquid drops



72
73
74
# File 'lib/ea/xmi/parser.rb', line 72

def fetch_connector(link_id)
  xmi_index.find_connector(link_id)
end

#fetch_definition_node_value(link_id, node_name) ⇒ Object



76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/ea/xmi/parser.rb', line 76

def fetch_definition_node_value(link_id, node_name)
  connector_node = fetch_connector(link_id)
  return nil unless connector_node

  node = connector_node.public_send(node_name.to_sym)
  return nil unless node

  documentation = node.documentation
  if documentation.is_a?(::Xmi::Sparx::Element::Documentation)
    documentation&.value
  else
    documentation
  end
end

#fetch_element(klass_id) ⇒ Object



211
212
213
# File 'lib/ea/xmi/parser.rb', line 211

def fetch_element(klass_id)
  xmi_index.find_element(klass_id)
end

#find_enum_packaged_element_by_name(name) ⇒ Object



154
155
156
# File 'lib/ea/xmi/parser.rb', line 154

def find_enum_packaged_element_by_name(name)
  xmi_index.packaged_elements_of_type("uml:Enumeration").find { |e| e.name == name }
end

#find_klass_packaged_element(path) ⇒ Object



141
142
143
144
145
146
147
148
# File 'lib/ea/xmi/parser.rb', line 141

def find_klass_packaged_element(path)
  lutaml_path = Lutaml::Path.parse(path)
  if lutaml_path.segments.one?
    return find_klass_packaged_element_by_name(path)
  end

  find_klass_packaged_element_by_path(lutaml_path)
end

#find_klass_packaged_element_by_name(name) ⇒ Object



150
151
152
# File 'lib/ea/xmi/parser.rb', line 150

def find_klass_packaged_element_by_name(name)
  xmi_index.find_packaged_by_name_and_types(name, ["uml:Class", "uml:AssociationClass"])
end

#find_packaged_element_by_id(id) ⇒ Object



102
103
104
# File 'lib/ea/xmi/parser.rb', line 102

def find_packaged_element_by_id(id)
  xmi_index.find_packaged_element(id)
end

#find_packaged_element_by_name(name) ⇒ Object



166
167
168
# File 'lib/ea/xmi/parser.rb', line 166

def find_packaged_element_by_name(name)
  xmi_index.packaged_elements.find { |e| e.name == name }
end

#find_subtype_of_from_generalization(id) ⇒ Object

rubocop:disable Metrics/AbcSize,Metrics:CyclomaticComplexity,Metrics:MethodLength,Metrics:PerceivedComplexity



127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/ea/xmi/parser.rb', line 127

def find_subtype_of_from_generalization(id) # rubocop:disable Metrics/AbcSize,Metrics:CyclomaticComplexity,Metrics:MethodLength,Metrics:PerceivedComplexity
  matched_element = xmi_index.find_element(id)
  return unless matched_element&.links&.any?

  matched_generalization = nil
  matched_element.links.each do |link|
    matched_generalization = link&.generalization&.find { |g| g.start == id }
    break if matched_generalization
  end

  return if matched_generalization&.end.nil?
  lookup_entity_name(matched_generalization.end)
end

#find_subtype_of_from_owned_attribute_type(id) ⇒ Object

rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/ea/xmi/parser.rb', line 110

def find_subtype_of_from_owned_attribute_type(id) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/PerceivedComplexity
  @pkg_elements_owned_attributes ||= begin
    cache = {}
    all_packaged_elements.each do |e|
      next unless e.owned_attribute

      e.owned_attribute.each do |oa|
        next unless oa.association && oa.uml_type && oa.uml_type.idref
        cache[oa.uml_type.idref] = e.name
      end
    end
    cache
  end

  @pkg_elements_owned_attributes[id]
end

#find_upper_level_packaged_element(klass_id) ⇒ Object



106
107
108
# File 'lib/ea/xmi/parser.rb', line 106

def find_upper_level_packaged_element(klass_id)
  xmi_index.find_parent(klass_id)
end

#get_ns_by_xmi_id(xmi_id) ⇒ Object



202
203
204
205
206
207
208
209
# File 'lib/ea/xmi/parser.rb', line 202

def get_ns_by_xmi_id(xmi_id)
  return unless xmi_id

  p = find_packaged_element_by_id(xmi_id)
  return unless p

  find_upper_level_packaged_element(p.id)&.name
end

#get_package_name(package) ⇒ Object

rubocop:disable Metrics/AbcSize



91
92
93
94
95
96
97
98
99
100
# File 'lib/ea/xmi/parser.rb', line 91

def get_package_name(package) # rubocop:disable Metrics/AbcSize
  return package.name unless package.name.nil?

  connector = fetch_connector(package.id)
  if connector.target&.model&.name
    return "#{connector.target.model.name} (#{package.type.split(':').last})"
  end

  "unnamed"
end

#id_name_mappingObject



66
67
68
# File 'lib/ea/xmi/parser.rb', line 66

def id_name_mapping
  @id_name_mapping
end

#lookup_assoc_def(association) ⇒ Object



197
198
199
200
# File 'lib/ea/xmi/parser.rb', line 197

def lookup_assoc_def(association)
  connector = fetch_connector(association)
  connector&.documentation&.value
end

#lookup_attribute_documentation(xmi_id) ⇒ Object



179
180
181
182
183
184
# File 'lib/ea/xmi/parser.rb', line 179

def lookup_attribute_documentation(xmi_id)
  attribute_node = fetch_attribute_node(xmi_id)
  return unless attribute_node&.documentation

  attribute_node.documentation.value
end

#lookup_element_prop_documentation(xmi_id) ⇒ Object



186
187
188
189
190
191
# File 'lib/ea/xmi/parser.rb', line 186

def lookup_element_prop_documentation(xmi_id)
  element_node = xmi_index.find_element(xmi_id)
  return unless element_node&.properties

  element_node.properties.documentation
end

#lookup_entity_name(xmi_id) ⇒ Object



193
194
195
# File 'lib/ea/xmi/parser.rb', line 193

def lookup_entity_name(xmi_id)
  @id_name_mapping[xmi_id]
end

#parse(xmi_model) ⇒ Object

Public instance methods



36
37
38
39
# File 'lib/ea/xmi/parser.rb', line 36

def parse(xmi_model)
  setup_model(xmi_model)
  build_document(xmi_model)
end

#select_all_packaged_elements(all_elements, model, type) ⇒ Object



223
224
225
226
# File 'lib/ea/xmi/parser.rb', line 223

def select_all_packaged_elements(all_elements, model, type)
  select_all_items(all_elements, model, type, :packaged_element)
  all_elements.delete_if { |e| !e.is_a?(::Xmi::Uml::PackagedElement) }
end

#select_dependencies_by_client(client_id) ⇒ Object



162
163
164
# File 'lib/ea/xmi/parser.rb', line 162

def select_dependencies_by_client(client_id)
  xmi_index.packaged_elements_of_type("uml:Dependency").select { |e| e.client == client_id }
end

#select_dependencies_by_supplier(supplier_id) ⇒ Object



158
159
160
# File 'lib/ea/xmi/parser.rb', line 158

def select_dependencies_by_supplier(supplier_id)
  xmi_index.packaged_elements_of_type("uml:Dependency").select { |e| e.supplier == supplier_id }
end

#serialize_to_liquid(xmi_model, guidance = nil) ⇒ Object



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/ea/xmi/parser.rb', line 41

def serialize_to_liquid(xmi_model, guidance = nil)
  setup_model(xmi_model)
  document = build_document(xmi_model)
  lookup = LookupService.new(self)
  options = {
    xmi_root_model: @xmi_root_model,
    id_name_mapping: @id_name_mapping,
    lookup: lookup,
    with_gen: true,
    with_absolute_path: true,
  }
  LiquidDrops::RootDrop.new(document, guidance, options)
end

#xmi_indexObject



58
59
60
61
62
63
64
# File 'lib/ea/xmi/parser.rb', line 58

def xmi_index
  if @xmi_index.nil? && @xmi_root_model
    @xmi_index = @xmi_root_model.index
    @id_name_mapping ||= @xmi_index.id_name_map
  end
  @xmi_index
end