class Lutaml::Qea::Verification::StructureMatcher
by qualified name/path
Matches corresponding elements between XMI and QEA documents
def build_class_index(document) # rubocop:disable Metrics/MethodLength
Build class index from document and packages
def build_class_index(document) # rubocop:disable Metrics/MethodLength index = {} # Index top-level classes document.classes&.each do |klass| next unless klass.name index[klass.name] = klass end # Index classes in packages if document.packages index_classes_in_packages(document.packages, "", index) end index end
def build_data_type_index(document) # rubocop:disable Metrics/MethodLength
Build data type index from document and packages
def build_data_type_index(document) # rubocop:disable Metrics/MethodLength index = {} # Index top-level data types document.data_types&.each do |dt| next unless dt.name index[dt.name] = dt end # Index data types in packages if document.packages index_data_types_in_packages(document.packages, "", index) end index end
def build_enum_index(document) # rubocop:disable Metrics/MethodLength
Build enum index from document and packages
def build_enum_index(document) # rubocop:disable Metrics/MethodLength index = {} # Index top-level enums document.enums&.each do |enum| next unless enum.name index[enum.name] = enum end # Index enums in packages if document.packages index_enums_in_packages(document.packages, "", index) end index end
def build_operation_signature(operation)
def build_operation_signature(operation) return operation.name unless operation.owned_parameter param_types = operation.owned_parameter.map do |param| param.type || "unknown" end.join(",") "#{operation.name}(#{param_types})" end
def build_package_index(packages, parent_path = "") # rubocop:disable Metrics/MethodLength
Build package index with qualified paths
def build_package_index(packages, parent_path = "") # rubocop:disable Metrics/MethodLength index = {} return index unless packages packages.each do |package| next unless package.name qualified_path = build_path(parent_path, package.name) index[qualified_path] = package # Recursively index nested packages nested = build_package_index(package.packages, qualified_path) index.merge!(nested) end index end
def build_path(parent_path, name)
def build_path(parent_path, name) return name if parent_path.empty? "#{parent_path}::#{name}" end
def build_qualified_names(document)
-
(Hash)- Hash mapping qualified names to elements
Parameters:
-
document(Lutaml::Uml::Document) -- The document
def build_qualified_names(document) { packages: build_package_index(document.packages), classes: build_class_index(document), enums: build_enum_index(document), data_types: build_data_type_index(document), } end
def index_by_name(collection)
def index_by_name(collection) index = {} collection.each do |element| next unless element.name index[element.name] = element end index end
def index_by_signature(operations)
def index_by_signature(operations) index = {} operations.each do |operation| next unless operation.name signature = build_operation_signature(operation) index[signature] = operation end index end
def index_classes_in_packages(packages, parent_path, index) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
Recursively index classes in packages
def index_classes_in_packages(packages, parent_path, index) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength return unless packages packages.each do |package| next unless package.name package_path = build_path(parent_path, package.name) package.classes&.each do |klass| next unless klass.name qualified_name = "#{package_path}::#{klass.name}" index[qualified_name] = klass end # Recurse into nested packages index_classes_in_packages(package.packages, package_path, index) end end
def index_data_types_in_packages(packages, parent_path, index) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
Recursively index data types in packages
def index_data_types_in_packages(packages, parent_path, index) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength return unless packages packages.each do |package| next unless package.name package_path = build_path(parent_path, package.name) package.data_types&.each do |dt| next unless dt.name qualified_name = "#{package_path}::#{dt.name}" index[qualified_name] = dt end # Recurse into nested packages index_data_types_in_packages(package.packages, package_path, index) end end
def index_enums_in_packages(packages, parent_path, index) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength
Recursively index enums in packages
def index_enums_in_packages(packages, parent_path, index) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength return unless packages packages.each do |package| next unless package.name package_path = build_path(parent_path, package.name) package.enums&.each do |enum| next unless enum.name qualified_name = "#{package_path}::#{enum.name}" index[qualified_name] = enum end # Recurse into nested packages index_enums_in_packages(package.packages, package_path, index) end end
def match_attributes(xmi_class, qea_class)
-
(Hash)- Hash with :matches, :xmi_only, :qea_only
Parameters:
-
qea_class(Lutaml::Uml::Class) -- QEA class -
xmi_class(Lutaml::Uml::Class) -- XMI class
def match_attributes(xmi_class, qea_class) xmi_attrs = index_by_name(xmi_class.attributes || []) qea_attrs = index_by_name(qea_class.attributes || []) match_elements(xmi_attrs, qea_attrs) end
def match_classes(xmi_doc, qea_doc)
-
(Hash)- Hash with :matches, :xmi_only, :qea_only
Parameters:
-
qea_doc(Lutaml::Uml::Document) -- QEA document -
xmi_doc(Lutaml::Uml::Document) -- XMI document
def match_classes(xmi_doc, qea_doc) xmi_classes = build_class_index(xmi_doc) qea_classes = build_class_index(qea_doc) match_elements(xmi_classes, qea_classes) end
def match_elements(xmi_index, qea_index) # rubocop:disable Metrics/MethodLength
Match elements between two indexes
def match_elements(xmi_index, qea_index) # rubocop:disable Metrics/MethodLength matches = {} xmi_only = [] qea_only = [] # Find matches and XMI-only elements xmi_index.each do |key, xmi_element| if qea_index.key?(key) matches[key] = { xmi: xmi_element, qea: qea_index[key], } else xmi_only << key end end # Find QEA-only elements qea_index.each_key do |key| qea_only << key unless xmi_index.key?(key) end { matches: matches, xmi_only: xmi_only.sort, qea_only: qea_only.sort, } end
def match_operations(xmi_class, qea_class)
-
(Hash)- Hash with :matches, :xmi_only, :qea_only
Parameters:
-
qea_class(Lutaml::Uml::Class) -- QEA class -
xmi_class(Lutaml::Uml::Class) -- XMI class
def match_operations(xmi_class, qea_class) xmi_ops = index_by_signature(xmi_class.operations || []) qea_ops = index_by_signature(qea_class.operations || []) match_elements(xmi_ops, qea_ops) end
def match_packages(xmi_doc, qea_doc)
-
(Hash)- Hash with :matches, :xmi_only, :qea_only
Parameters:
-
qea_doc(Lutaml::Uml::Document) -- QEA document -
xmi_doc(Lutaml::Uml::Document) -- XMI document
def match_packages(xmi_doc, qea_doc) xmi_packages = build_package_index(xmi_doc.packages) qea_packages = build_package_index(qea_doc.packages) match_elements(xmi_packages, qea_packages) end