lutaml 0.10.8 → 0.10.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +42 -8
- data/lib/lutaml/cli/interactive_shell/command_base.rb +2 -2
- data/lib/lutaml/cli/interactive_shell/query_commands.rb +1 -1
- data/lib/lutaml/cli/interactive_shell.rb +21 -18
- data/lib/lutaml/cli/resource_registry.rb +1 -1
- data/lib/lutaml/cli/uml/inspect_command.rb +1 -1
- data/lib/lutaml/converter/dsl_to_uml.rb +8 -8
- data/lib/lutaml/converter/xmi_to_uml.rb +2 -2
- data/lib/lutaml/ea/diagram/style_parser.rb +15 -15
- data/lib/lutaml/ea/diagram/style_resolver.rb +4 -3
- data/lib/lutaml/formatter/graphviz.rb +1 -1
- data/lib/lutaml/model_transformations/parsers/qea_parser.rb +2 -4
- data/lib/lutaml/model_transformations/parsers/xmi_parser.rb +1 -6
- data/lib/lutaml/qea/factory/document_builder.rb +3 -3
- data/lib/lutaml/qea/lookup_indexes.rb +2 -2
- data/lib/lutaml/qea/models/base_model.rb +1 -1
- data/lib/lutaml/qea/repositories/base_repository.rb +7 -7
- data/lib/lutaml/qea/validation/base_validator.rb +5 -3
- data/lib/lutaml/qea/verification/element_comparator.rb +18 -47
- data/lib/lutaml/uml/association_generalization.rb +1 -0
- data/lib/lutaml/uml/class.rb +0 -1
- data/lib/lutaml/uml/classifier.rb +3 -0
- data/lib/lutaml/uml/data_type.rb +0 -1
- data/lib/lutaml/uml/has_attributes.rb +1 -1
- data/lib/lutaml/uml/has_members.rb +1 -1
- data/lib/lutaml/uml/inheritance_walker.rb +4 -4
- data/lib/lutaml/uml/model_helpers.rb +5 -62
- data/lib/lutaml/uml/operation.rb +6 -0
- data/lib/lutaml/uml/operation_parameter.rb +17 -0
- data/lib/lutaml/uml/qualified_name.rb +4 -5
- data/lib/lutaml/uml/top_element_attribute.rb +4 -0
- data/lib/lutaml/uml/validation/document_structure_validator.rb +4 -4
- data/lib/lutaml/uml_repository/class_lookup_index.rb +1 -1
- data/lib/lutaml/uml_repository/exporters/json_exporter.rb +1 -1
- data/lib/lutaml/uml_repository/exporters/markdown/class_page_builder.rb +2 -2
- data/lib/lutaml/uml_repository/index_builder.rb +15 -15
- data/lib/lutaml/uml_repository/package_exporter.rb +3 -5
- data/lib/lutaml/uml_repository/package_loader.rb +3 -3
- data/lib/lutaml/uml_repository/queries/association_query.rb +2 -2
- data/lib/lutaml/uml_repository/queries/inheritance_query.rb +9 -13
- data/lib/lutaml/uml_repository/queries/search_query.rb +7 -7
- data/lib/lutaml/uml_repository/query_dsl/conditions/hash_condition.rb +2 -2
- data/lib/lutaml/uml_repository/query_dsl/order.rb +2 -2
- data/lib/lutaml/uml_repository/query_dsl/query_builder.rb +2 -2
- data/lib/lutaml/uml_repository/repository.rb +2 -2
- data/lib/lutaml/uml_repository/repository_enhanced.rb +1 -1
- data/lib/lutaml/uml_repository/static_site/association_serialization.rb +38 -86
- data/lib/lutaml/uml_repository/static_site/data_transformer.rb +13 -39
- data/lib/lutaml/uml_repository/static_site/models/spa_association.rb +32 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_association_end.rb +28 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_attribute.rb +42 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_base.rb +12 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_cardinality.rb +21 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_class.rb +64 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_diagram.rb +33 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_document.rb +42 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_inherited_association.rb +27 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_inherited_attribute.rb +28 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_literal.rb +21 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_metadata.rb +26 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_operation.rb +37 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_package.rb +37 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_package_tree_node.rb +35 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_parameter.rb +23 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_search_entry.rb +37 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_statistics.rb +27 -0
- data/lib/lutaml/uml_repository/static_site/models/spa_tree_class_ref.rb +23 -0
- data/lib/lutaml/uml_repository/static_site/search_index_builder.rb +46 -131
- data/lib/lutaml/uml_repository/static_site/serializers/attribute_serializer.rb +11 -11
- data/lib/lutaml/uml_repository/static_site/serializers/class_serializer.rb +17 -16
- data/lib/lutaml/uml_repository/static_site/serializers/diagram_serializer.rb +8 -12
- data/lib/lutaml/uml_repository/static_site/serializers/inheritance_resolver.rb +44 -51
- data/lib/lutaml/uml_repository/static_site/serializers/metadata_builder.rb +8 -5
- data/lib/lutaml/uml_repository/static_site/serializers/operation_serializer.rb +14 -11
- data/lib/lutaml/uml_repository/static_site/serializers/package_serializer.rb +15 -17
- data/lib/lutaml/uml_repository/static_site/serializers/package_tree_builder.rb +19 -31
- data/lib/lutaml/uml_repository/statistics_calculator.rb +2 -4
- data/lib/lutaml/version.rb +1 -1
- data/lib/lutaml/xmi/liquid_drops/generalization_attribute_drop.rb +2 -2
- data/lib/lutaml/xmi/liquid_drops/package_drop.rb +11 -1
- data/lib/lutaml/xmi/parsers/xmi_base.rb +4 -4
- data/lib/lutaml/xmi/parsers/xmi_connector.rb +7 -7
- metadata +22 -2
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "top_element"
|
|
4
4
|
require_relative "association_generalization"
|
|
5
|
+
require_relative "operation"
|
|
5
6
|
|
|
6
7
|
module Lutaml
|
|
7
8
|
module Uml
|
|
@@ -9,6 +10,8 @@ module Lutaml
|
|
|
9
10
|
attribute :association_generalization,
|
|
10
11
|
::Lutaml::Uml::AssociationGeneralization,
|
|
11
12
|
collection: true, default: -> { [] }
|
|
13
|
+
attribute :operations, Operation, collection: true, default: -> { [] }
|
|
14
|
+
attribute :is_abstract, :boolean, default: false
|
|
12
15
|
|
|
13
16
|
yaml do
|
|
14
17
|
map "generalization", to: :association_generalization
|
data/lib/lutaml/uml/data_type.rb
CHANGED
|
@@ -11,7 +11,6 @@ module Lutaml
|
|
|
11
11
|
class DataType < Classifier
|
|
12
12
|
attribute :nested_classifier, :string, collection: true,
|
|
13
13
|
default: -> { [] }
|
|
14
|
-
attribute :is_abstract, :boolean, default: false
|
|
15
14
|
attribute :type, :string
|
|
16
15
|
attribute :attributes, TopElementAttribute, collection: true
|
|
17
16
|
attribute :modifier, :string
|
|
@@ -31,7 +31,7 @@ module Lutaml
|
|
|
31
31
|
# puts "#{' ' * (level - 1)}Parent #{level}: #{parent.name}"
|
|
32
32
|
# end
|
|
33
33
|
def walk(klass)
|
|
34
|
-
return [] unless klass.
|
|
34
|
+
return [] unless klass.is_a?(Lutaml::Uml::Class) && klass.generalization
|
|
35
35
|
|
|
36
36
|
ancestors = []
|
|
37
37
|
@visited.clear
|
|
@@ -69,12 +69,12 @@ module Lutaml
|
|
|
69
69
|
# Uses a trail set for cycle detection (avoids Set mutation issues across calls).
|
|
70
70
|
def collect_ancestors(klass, result, trail = [])
|
|
71
71
|
return [] if trail.include?(klass.xmi_id) # cycle guard
|
|
72
|
-
return [] unless klass.
|
|
72
|
+
return [] unless klass.is_a?(Lutaml::Uml::Class) && klass.generalization
|
|
73
73
|
|
|
74
74
|
trail = trail.dup
|
|
75
75
|
trail << klass.xmi_id
|
|
76
76
|
|
|
77
|
-
general_id = klass.generalization.
|
|
77
|
+
general_id = klass.generalization.general_id
|
|
78
78
|
parent = general_id ? find_class_by_id(general_id) : nil
|
|
79
79
|
|
|
80
80
|
return [] unless parent
|
|
@@ -85,7 +85,7 @@ module Lutaml
|
|
|
85
85
|
|
|
86
86
|
def find_class_by_id(xmi_id)
|
|
87
87
|
@repository.indexes&.dig(:qualified_names, xmi_id) ||
|
|
88
|
-
@repository.
|
|
88
|
+
@repository.classes_index&.find { |c| c.xmi_id == xmi_id }
|
|
89
89
|
end
|
|
90
90
|
end
|
|
91
91
|
end
|
|
@@ -2,20 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Lutaml
|
|
4
4
|
module Uml
|
|
5
|
-
# Shared helper methods for UML model objects.
|
|
6
|
-
# These methods are used across transformers, serializers, and presenters
|
|
7
|
-
# to avoid duplication of common model traversal and formatting logic.
|
|
8
5
|
module ModelHelpers
|
|
9
|
-
# Normalize a stereotype value to a consistent Array format.
|
|
10
|
-
#
|
|
11
|
-
# @param stereotype [String, Array, nil, Symbol] The stereotype value
|
|
12
|
-
# @return [Array<String>] Array of stereotype strings
|
|
13
|
-
#
|
|
14
|
-
# @example
|
|
15
|
-
# normalize_stereotypes(nil) # => []
|
|
16
|
-
# normalize_stereotypes("enumeration") # => ["enumeration"]
|
|
17
|
-
# normalize_stereotypes(["a", "b"]) # => ["a", "b"]
|
|
18
|
-
# normalize_stereotypes(:enumeration) # => ["enumeration"]
|
|
19
6
|
def normalize_stereotypes(stereotype)
|
|
20
7
|
return [] if stereotype.nil?
|
|
21
8
|
|
|
@@ -27,51 +14,28 @@ module Lutaml
|
|
|
27
14
|
end
|
|
28
15
|
end
|
|
29
16
|
|
|
30
|
-
# Build a fully qualified name by walking the namespace chain of a UML element.
|
|
31
|
-
#
|
|
32
|
-
# @param uml_element [Lutaml::Uml::TopElement, Lutaml::Uml::Package] Any element with a namespace
|
|
33
|
-
# @return [String] Fully qualified name joined by '::'
|
|
34
|
-
#
|
|
35
|
-
# @example
|
|
36
|
-
# qualified_name_for(class_in_package) # => "ModelName::PackageName::ClassName"
|
|
37
17
|
def qualified_name_for(uml_element)
|
|
38
|
-
return uml_element.name unless uml_element.respond_to?(:namespace)
|
|
39
|
-
|
|
40
18
|
parts = []
|
|
41
19
|
current = uml_element
|
|
42
20
|
|
|
43
21
|
while current
|
|
44
22
|
parts.unshift(current.name) if current.name
|
|
45
|
-
current =
|
|
46
|
-
current.namespace
|
|
47
|
-
else
|
|
48
|
-
break
|
|
49
|
-
end
|
|
23
|
+
current = current.namespace
|
|
50
24
|
end
|
|
51
25
|
|
|
52
26
|
parts.join("::")
|
|
53
27
|
end
|
|
54
28
|
|
|
55
|
-
# Build a package-only namespace path (no class names).
|
|
56
|
-
#
|
|
57
|
-
# @param uml_element [Lutaml::Uml::TopElement, Lutaml::Uml::Package]
|
|
58
|
-
# @return [String] Package path joined by '::'
|
|
59
|
-
#
|
|
60
|
-
# @example
|
|
61
|
-
# package_path_for(class_in_nested_package) # => "ModelName::ParentPackage::ChildPackage"
|
|
62
29
|
def package_path_for(uml_element)
|
|
63
|
-
return uml_element.name unless uml_element.respond_to?(:namespace)
|
|
64
|
-
|
|
65
30
|
parts = []
|
|
66
31
|
current = uml_element
|
|
67
32
|
|
|
68
33
|
while current
|
|
69
34
|
if current.is_a?(Lutaml::Uml::Package)
|
|
70
35
|
parts.unshift(current.name) if current.name
|
|
71
|
-
current = current.namespace
|
|
36
|
+
current = current.namespace
|
|
72
37
|
elsif current.is_a?(Lutaml::Uml::TopElement)
|
|
73
|
-
|
|
74
|
-
current = current.namespace if current.respond_to?(:namespace)
|
|
38
|
+
current = current.namespace
|
|
75
39
|
else
|
|
76
40
|
break
|
|
77
41
|
end
|
|
@@ -80,14 +44,6 @@ module Lutaml
|
|
|
80
44
|
parts.join("::")
|
|
81
45
|
end
|
|
82
46
|
|
|
83
|
-
# Extract the leaf class name from a fully-qualified class name or class object.
|
|
84
|
-
#
|
|
85
|
-
# @param uml_class [String, Class] A class name string or a Lutaml::Uml::* class instance
|
|
86
|
-
# @return [String] The leaf class name
|
|
87
|
-
#
|
|
88
|
-
# @example
|
|
89
|
-
# class_type_for("Lutaml::Uml::Class") # => "Class"
|
|
90
|
-
# class_type_for(some_enum_object) # => "Enumeration"
|
|
91
47
|
def class_type_for(uml_class)
|
|
92
48
|
case uml_class
|
|
93
49
|
when String then uml_class.split("::").last
|
|
@@ -96,19 +52,11 @@ module Lutaml
|
|
|
96
52
|
end
|
|
97
53
|
end
|
|
98
54
|
|
|
99
|
-
# Format a cardinality object as a "min..max" string.
|
|
100
|
-
#
|
|
101
|
-
# @param cardinality [Lutaml::Uml::Cardinality, Hash, nil]
|
|
102
|
-
# @return [String, nil] Formatted cardinality string or nil
|
|
103
|
-
#
|
|
104
|
-
# @example
|
|
105
|
-
# format_cardinality(Lutaml::Uml::Cardinality.new(min: 0, max: 5)) # => "0..5"
|
|
106
|
-
# format_cardinality({min: 1, max: nil}) # => "1..*"
|
|
107
55
|
def format_cardinality(cardinality)
|
|
108
56
|
return nil unless cardinality
|
|
109
57
|
|
|
110
|
-
min = cardinality.
|
|
111
|
-
max = cardinality.
|
|
58
|
+
min = cardinality.min
|
|
59
|
+
max = cardinality.max
|
|
112
60
|
return nil if min.nil? && max.nil?
|
|
113
61
|
|
|
114
62
|
min_str = min.nil? ? "0" : min.to_s
|
|
@@ -116,11 +64,6 @@ module Lutaml
|
|
|
116
64
|
"#{min_str}..#{max_str}"
|
|
117
65
|
end
|
|
118
66
|
|
|
119
|
-
# Parse a cardinality string or hash into a {min:, max:} hash.
|
|
120
|
-
#
|
|
121
|
-
# @param min [String, nil]
|
|
122
|
-
# @param max [String, nil]
|
|
123
|
-
# @return [Hash{Symbol => String, nil}] Hash with :min and :max keys
|
|
124
67
|
def parse_cardinality(min, max)
|
|
125
68
|
{ min: min, max: max }
|
|
126
69
|
end
|
data/lib/lutaml/uml/operation.rb
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require_relative "operation_parameter"
|
|
4
|
+
|
|
3
5
|
module Lutaml
|
|
4
6
|
module Uml
|
|
5
7
|
class Operation < TopElement
|
|
6
8
|
attribute :id, :string
|
|
7
9
|
attribute :return_type, :string
|
|
8
10
|
attribute :parameter_type, :string
|
|
11
|
+
attribute :is_static, :boolean, default: false
|
|
12
|
+
attribute :is_abstract, :boolean, default: false
|
|
13
|
+
attribute :owned_parameter, OperationParameter, collection: true,
|
|
14
|
+
default: -> { [] }
|
|
9
15
|
|
|
10
16
|
yaml do
|
|
11
17
|
map "id", to: :id
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Lutaml
|
|
4
|
+
module Uml
|
|
5
|
+
class OperationParameter < Lutaml::Model::Serializable
|
|
6
|
+
attribute :name, :string
|
|
7
|
+
attribute :type, :string
|
|
8
|
+
attribute :direction, :string, default: "in"
|
|
9
|
+
|
|
10
|
+
yaml do
|
|
11
|
+
map "name", to: :name
|
|
12
|
+
map "type", to: :type
|
|
13
|
+
map "direction", to: :direction
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -65,8 +65,7 @@ module Lutaml
|
|
|
65
65
|
return "" if @class_name.nil? || @class_name.empty?
|
|
66
66
|
|
|
67
67
|
# Check if package path is empty
|
|
68
|
-
if @package_path.nil? ||
|
|
69
|
-
(@package_path.respond_to?(:empty?) && @package_path.empty?)
|
|
68
|
+
if @package_path.nil? || @package_path.empty?
|
|
70
69
|
return @class_name
|
|
71
70
|
end
|
|
72
71
|
|
|
@@ -105,7 +104,7 @@ module Lutaml
|
|
|
105
104
|
# qname.matches_glob?("Package1::*::ClassName") # => true
|
|
106
105
|
def matches_glob?(pattern)
|
|
107
106
|
# Create a full path for matching (package + class)
|
|
108
|
-
full_segments = if @package_path.
|
|
107
|
+
full_segments = if @package_path.is_a?(PackagePath) &&
|
|
109
108
|
!@package_path.segments.empty?
|
|
110
109
|
@package_path.segments + [@class_name]
|
|
111
110
|
else
|
|
@@ -125,7 +124,7 @@ module Lutaml
|
|
|
125
124
|
# new_path = PackagePath.new("Package2")
|
|
126
125
|
# qname.with_package(new_path) # => QualifiedName("Package2::ClassName")
|
|
127
126
|
def with_package(new_package_path)
|
|
128
|
-
if new_package_path.
|
|
127
|
+
if new_package_path.empty?
|
|
129
128
|
self.class.new(@class_name)
|
|
130
129
|
else
|
|
131
130
|
self.class.new("#{new_package_path}#{PackagePath::SEPARATOR}#{@class_name}")
|
|
@@ -148,7 +147,7 @@ module Lutaml
|
|
|
148
147
|
return self if relative_path == @package_path
|
|
149
148
|
|
|
150
149
|
# Otherwise create new qualified name with relative path
|
|
151
|
-
if relative_path.
|
|
150
|
+
if relative_path.empty?
|
|
152
151
|
self.class.new(@class_name)
|
|
153
152
|
else
|
|
154
153
|
self.class.new("#{relative_path}#{PackagePath::SEPARATOR}#{@class_name}")
|
|
@@ -13,6 +13,10 @@ module Lutaml
|
|
|
13
13
|
attribute :cardinality, Cardinality
|
|
14
14
|
attribute :keyword, :string
|
|
15
15
|
attribute :is_derived, :boolean, default: false
|
|
16
|
+
attribute :is_static, :boolean, default: false
|
|
17
|
+
attribute :is_read_only, :boolean, default: false
|
|
18
|
+
attribute :default, :string
|
|
19
|
+
attribute :stereotype, :string, collection: true, default: -> { [] }
|
|
16
20
|
|
|
17
21
|
attribute :definition, :string
|
|
18
22
|
attribute :association, :string
|
|
@@ -75,7 +75,7 @@ module Lutaml
|
|
|
75
75
|
# @param path [String] Package path for error reporting
|
|
76
76
|
# @return [void]
|
|
77
77
|
def validate_collection(package, attribute, path) # rubocop:disable Metrics/MethodLength
|
|
78
|
-
value = package.
|
|
78
|
+
value = package.public_send(attribute)
|
|
79
79
|
unless value.nil? || value.is_a?(Array)
|
|
80
80
|
result.add_error(
|
|
81
81
|
category: :invalid_structure,
|
|
@@ -175,7 +175,7 @@ module Lutaml
|
|
|
175
175
|
name_counts = Hash.new(0)
|
|
176
176
|
|
|
177
177
|
collection.each do |entity|
|
|
178
|
-
next unless entity.
|
|
178
|
+
next unless entity.name
|
|
179
179
|
|
|
180
180
|
name_counts[entity.name] += 1
|
|
181
181
|
end
|
|
@@ -212,10 +212,10 @@ module Lutaml
|
|
|
212
212
|
|
|
213
213
|
# Check attribute type references
|
|
214
214
|
all_classes.each do |cls, path|
|
|
215
|
-
next unless cls.
|
|
215
|
+
next unless cls.is_a?(Lutaml::Uml::Class) || cls.is_a?(Lutaml::Uml::DataType)
|
|
216
216
|
|
|
217
217
|
(cls.attributes || []).each do |attr|
|
|
218
|
-
next unless attr.
|
|
218
|
+
next unless attr.type
|
|
219
219
|
next if primitive_type?(attr.type)
|
|
220
220
|
next if valid_types.include?(attr.type)
|
|
221
221
|
|
|
@@ -18,7 +18,7 @@ module Lutaml
|
|
|
18
18
|
|
|
19
19
|
classes.each do |klass|
|
|
20
20
|
@by_xmi_id[klass.xmi_id] = klass if klass.xmi_id
|
|
21
|
-
if klass.
|
|
21
|
+
if klass.class.attributes.key?(:ea_object_id) && klass.ea_object_id
|
|
22
22
|
@by_object_id[klass.ea_object_id] = klass
|
|
23
23
|
end
|
|
24
24
|
end
|
|
@@ -228,7 +228,7 @@ module Lutaml
|
|
|
228
228
|
# @param klass [Object] The class object
|
|
229
229
|
# @return [Array<Hash>] Array of operation hashes
|
|
230
230
|
def serialize_operations(klass)
|
|
231
|
-
return [] unless klass.
|
|
231
|
+
return [] unless klass.is_a?(Lutaml::Uml::Classifier) && klass.operations
|
|
232
232
|
|
|
233
233
|
klass.operations.map do |op|
|
|
234
234
|
{
|
|
@@ -55,7 +55,7 @@ module Lutaml
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def build_definition_section(klass)
|
|
58
|
-
return "" unless klass.
|
|
58
|
+
return "" unless klass.definition
|
|
59
59
|
|
|
60
60
|
"## Description\n\n#{klass.definition}\n\n"
|
|
61
61
|
end
|
|
@@ -105,7 +105,7 @@ module Lutaml
|
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
def build_operations_section(klass)
|
|
108
|
-
return "" unless klass.
|
|
108
|
+
return "" unless klass.operations&.any?
|
|
109
109
|
|
|
110
110
|
content = "## Operations\n\n"
|
|
111
111
|
content += "| Name | Return Type | Visibility |\n"
|
|
@@ -56,13 +56,13 @@ module Lutaml
|
|
|
56
56
|
def self.build_package_paths(document)
|
|
57
57
|
builder = new(document)
|
|
58
58
|
builder.build_package_path_index
|
|
59
|
-
builder.
|
|
59
|
+
builder.package_paths.freeze
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
def self.build_package_to_path(document)
|
|
63
63
|
builder = new(document)
|
|
64
64
|
builder.build_package_path_index
|
|
65
|
-
builder.
|
|
65
|
+
builder.package_to_path.freeze
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
# Build qualified names index
|
|
@@ -72,19 +72,19 @@ module Lutaml
|
|
|
72
72
|
def self.build_qualified_names(document)
|
|
73
73
|
builder = new(document)
|
|
74
74
|
builder.build_qualified_name_index
|
|
75
|
-
builder.
|
|
75
|
+
builder.qualified_names.freeze
|
|
76
76
|
end
|
|
77
77
|
|
|
78
78
|
def self.build_class_to_qname(document)
|
|
79
79
|
builder = new(document)
|
|
80
80
|
builder.build_qualified_name_index
|
|
81
|
-
builder.
|
|
81
|
+
builder.class_to_qname.freeze
|
|
82
82
|
end
|
|
83
83
|
|
|
84
84
|
def self.build_classes(document)
|
|
85
85
|
builder = new(document)
|
|
86
86
|
builder.build_qualified_name_index
|
|
87
|
-
builder.
|
|
87
|
+
builder.classes.freeze
|
|
88
88
|
end
|
|
89
89
|
|
|
90
90
|
def self.build_associations(document)
|
|
@@ -93,7 +93,7 @@ module Lutaml
|
|
|
93
93
|
# class-level associations
|
|
94
94
|
builder.build_qualified_name_index
|
|
95
95
|
builder.build_association_index
|
|
96
|
-
builder.
|
|
96
|
+
builder.associations.freeze
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
# Build stereotypes index
|
|
@@ -103,7 +103,7 @@ module Lutaml
|
|
|
103
103
|
def self.build_stereotypes(document)
|
|
104
104
|
builder = new(document)
|
|
105
105
|
builder.build_stereotype_index
|
|
106
|
-
builder.
|
|
106
|
+
builder.stereotypes.freeze
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
# Build inheritance graph index
|
|
@@ -113,15 +113,13 @@ module Lutaml
|
|
|
113
113
|
# @return [Hash] Frozen hash mapping parent qnames to child qnames
|
|
114
114
|
def self.build_inheritance_graph(document, indexes)
|
|
115
115
|
builder = new(document)
|
|
116
|
-
# If qualified_names index is provided, use it
|
|
117
116
|
if indexes && indexes[:qualified_names]
|
|
118
|
-
builder.
|
|
119
|
-
indexes[:qualified_names])
|
|
117
|
+
builder.qualified_names = indexes[:qualified_names]
|
|
120
118
|
else
|
|
121
119
|
builder.build_qualified_name_index
|
|
122
120
|
end
|
|
123
121
|
builder.build_inheritance_graph_index
|
|
124
|
-
builder.
|
|
122
|
+
builder.inheritance_graph.freeze
|
|
125
123
|
end
|
|
126
124
|
|
|
127
125
|
# Build diagram index
|
|
@@ -131,15 +129,13 @@ module Lutaml
|
|
|
131
129
|
# @return [Hash] Frozen hash mapping package IDs to Diagram objects
|
|
132
130
|
def self.build_diagram_index(document, indexes)
|
|
133
131
|
builder = new(document)
|
|
134
|
-
# If package_paths index is provided, use it
|
|
135
132
|
if indexes && indexes[:package_paths]
|
|
136
|
-
builder.
|
|
137
|
-
indexes[:package_paths])
|
|
133
|
+
builder.package_paths = indexes[:package_paths]
|
|
138
134
|
else
|
|
139
135
|
builder.build_package_path_index
|
|
140
136
|
end
|
|
141
137
|
builder.build_diagram_index
|
|
142
|
-
builder.
|
|
138
|
+
builder.diagram_index.freeze
|
|
143
139
|
end
|
|
144
140
|
|
|
145
141
|
def initialize(document)
|
|
@@ -157,6 +153,10 @@ module Lutaml
|
|
|
157
153
|
@package_to_classes = {}
|
|
158
154
|
end
|
|
159
155
|
|
|
156
|
+
attr_accessor :package_paths, :qualified_names
|
|
157
|
+
attr_reader :package_to_path, :class_to_qname, :classes, :associations,
|
|
158
|
+
:stereotypes, :inheritance_graph, :diagram_index
|
|
159
|
+
|
|
160
160
|
# Build all indexes and return them as a frozen hash
|
|
161
161
|
#
|
|
162
162
|
# @return [Hash] Frozen hash containing all indexes
|
|
@@ -277,15 +277,13 @@ module Lutaml
|
|
|
277
277
|
# @param klass [Object] The class object
|
|
278
278
|
# @return [Array<Hash>] List of attributes
|
|
279
279
|
def build_attributes_list(klass)
|
|
280
|
-
return [] unless klass.
|
|
280
|
+
return [] unless klass.is_a?(Lutaml::Uml::Classifier) && klass.attributes
|
|
281
281
|
|
|
282
282
|
klass.attributes.map do |attr|
|
|
283
283
|
{
|
|
284
284
|
"name" => attr.name,
|
|
285
285
|
"type" => attr.type,
|
|
286
|
-
"visibility" =>
|
|
287
|
-
attr.visibility
|
|
288
|
-
end,
|
|
286
|
+
"visibility" => attr.visibility,
|
|
289
287
|
}.compact
|
|
290
288
|
end
|
|
291
289
|
end
|
|
@@ -316,7 +314,7 @@ module Lutaml
|
|
|
316
314
|
def count_all_attributes
|
|
317
315
|
total = 0
|
|
318
316
|
@repository.indexes[:qualified_names].each_value do |klass|
|
|
319
|
-
if klass.
|
|
317
|
+
if klass.is_a?(Lutaml::Uml::Classifier) && klass.attributes
|
|
320
318
|
total += klass.attributes.size
|
|
321
319
|
end
|
|
322
320
|
end
|
|
@@ -147,11 +147,11 @@ module Lutaml
|
|
|
147
147
|
# @raise [RuntimeError] If document is missing or format is unknown
|
|
148
148
|
def self.load_document(zip, metadata) # rubocop:disable Metrics/MethodLength
|
|
149
149
|
# Handle both PackageMetadata object and Hash (backward compatibility)
|
|
150
|
-
format = if metadata.
|
|
151
|
-
metadata.serialization_format
|
|
152
|
-
else
|
|
150
|
+
format = if metadata.is_a?(Hash)
|
|
153
151
|
metadata["serialization_format"] ||
|
|
154
152
|
metadata[:serialization_format]
|
|
153
|
+
else
|
|
154
|
+
metadata.serialization_format
|
|
155
155
|
end
|
|
156
156
|
|
|
157
157
|
case format.to_s
|
|
@@ -57,13 +57,13 @@ module Lutaml
|
|
|
57
57
|
results = []
|
|
58
58
|
|
|
59
59
|
# Get owned associations from the class itself
|
|
60
|
-
if klass.
|
|
60
|
+
if (klass.is_a?(Lutaml::Uml::Class) || klass.is_a?(Lutaml::Uml::DataType)) && klass.associations
|
|
61
61
|
results.concat(klass.associations)
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
# Get associations from document level unless owned_only
|
|
65
65
|
if !owned_only &&
|
|
66
|
-
document.
|
|
66
|
+
document.is_a?(Lutaml::Uml::Document) && document.associations
|
|
67
67
|
document_associations = document.associations.select do |assoc|
|
|
68
68
|
match_association?(assoc, class_name, direction)
|
|
69
69
|
end
|
|
@@ -36,7 +36,7 @@ module Lutaml
|
|
|
36
36
|
def supertype(class_or_qname) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
|
37
37
|
klass = resolve_class(class_or_qname)
|
|
38
38
|
return nil unless klass
|
|
39
|
-
return nil unless klass.
|
|
39
|
+
return nil unless klass.is_a?(Lutaml::Uml::Class)
|
|
40
40
|
return nil unless klass.generalization
|
|
41
41
|
|
|
42
42
|
parent_name = extract_parent_name(klass.generalization)
|
|
@@ -230,7 +230,7 @@ module Lutaml
|
|
|
230
230
|
|
|
231
231
|
# Try as xmi_id - search in qualified_names
|
|
232
232
|
indexes[:qualified_names].each_value do |entity|
|
|
233
|
-
next unless entity.
|
|
233
|
+
next unless entity.xmi_id
|
|
234
234
|
|
|
235
235
|
return entity if entity.xmi_id == class_or_id
|
|
236
236
|
end
|
|
@@ -280,22 +280,18 @@ module Lutaml
|
|
|
280
280
|
# @param generalization [Lutaml::Uml::Generalization]
|
|
281
281
|
# Generalization object
|
|
282
282
|
# @return [String, nil] Parent class name
|
|
283
|
-
def extract_parent_name(generalization)
|
|
283
|
+
def extract_parent_name(generalization)
|
|
284
284
|
return nil unless generalization
|
|
285
|
+
return nil unless generalization.is_a?(Lutaml::Uml::Generalization)
|
|
285
286
|
|
|
286
|
-
|
|
287
|
-
if
|
|
288
|
-
parent
|
|
289
|
-
return parent.name if parent.respond_to?(:name)
|
|
290
|
-
return parent.to_s if parent
|
|
291
|
-
end
|
|
287
|
+
parent = generalization.general
|
|
288
|
+
if parent
|
|
289
|
+
return parent.name if parent.is_a?(Lutaml::Uml::Generalization) && parent.name
|
|
292
290
|
|
|
293
|
-
|
|
294
|
-
if generalization.respond_to?(:name) && generalization.name
|
|
295
|
-
return generalization.name
|
|
291
|
+
return parent.to_s
|
|
296
292
|
end
|
|
297
293
|
|
|
298
|
-
|
|
294
|
+
generalization.name if generalization.name
|
|
299
295
|
end
|
|
300
296
|
|
|
301
297
|
# Resolve a class name to its qualified name
|
|
@@ -129,8 +129,8 @@ module Lutaml
|
|
|
129
129
|
|
|
130
130
|
# Check fields for match
|
|
131
131
|
fields.each do |field|
|
|
132
|
-
if entity.
|
|
133
|
-
entity.
|
|
132
|
+
if entity.class.attributes.key?(field) &&
|
|
133
|
+
entity.public_send(field)&.match?(pattern)
|
|
134
134
|
|
|
135
135
|
match_field = field
|
|
136
136
|
qualified_name = qname
|
|
@@ -157,7 +157,7 @@ module Lutaml
|
|
|
157
157
|
matched_entities = indexes[:stereotypes]
|
|
158
158
|
.filter_map do |_stereotype, entities|
|
|
159
159
|
entities.select do |entity|
|
|
160
|
-
entity.
|
|
160
|
+
entity.is_a?(Lutaml::Uml::Classifier) &&
|
|
161
161
|
Array(entity.stereotype).any? { |s| s&.match?(pattern) }
|
|
162
162
|
end.uniq
|
|
163
163
|
end.uniq.flatten
|
|
@@ -218,7 +218,7 @@ module Lutaml
|
|
|
218
218
|
)
|
|
219
219
|
|
|
220
220
|
indexes[:qualified_names].filter_map do |class_qname, entity| # rubocop:disable Metrics/BlockLength
|
|
221
|
-
next unless entity.
|
|
221
|
+
next unless entity.is_a?(Lutaml::Uml::Classifier) && entity.attributes
|
|
222
222
|
|
|
223
223
|
match_field = nil
|
|
224
224
|
match_attr = nil
|
|
@@ -227,8 +227,8 @@ module Lutaml
|
|
|
227
227
|
entity.attributes.each do |attr|
|
|
228
228
|
# Check attribute for match
|
|
229
229
|
fields.each do |field|
|
|
230
|
-
if attr.
|
|
231
|
-
attr.
|
|
230
|
+
if attr.class.attributes.key?(field) &&
|
|
231
|
+
attr.public_send(field)&.match?(pattern)
|
|
232
232
|
|
|
233
233
|
match_attr = attr
|
|
234
234
|
match_field = field
|
|
@@ -294,7 +294,7 @@ module Lutaml
|
|
|
294
294
|
match_field = nil
|
|
295
295
|
|
|
296
296
|
fields.each do |field|
|
|
297
|
-
if assoc.
|
|
297
|
+
if assoc.class.attributes.key?(field) && assoc.public_send(field)&.match?(pattern)
|
|
298
298
|
match_field = field
|
|
299
299
|
end
|
|
300
300
|
end
|
|
@@ -51,9 +51,9 @@ module Lutaml
|
|
|
51
51
|
# @param value [Object] The expected value
|
|
52
52
|
# @return [Boolean] true if condition matches
|
|
53
53
|
def matches_condition?(obj, key, value)
|
|
54
|
-
return false unless obj.
|
|
54
|
+
return false unless obj.class.attributes.key?(key.to_sym)
|
|
55
55
|
|
|
56
|
-
actual_value = obj.
|
|
56
|
+
actual_value = obj.public_send(key)
|
|
57
57
|
compare_values(actual_value, value)
|
|
58
58
|
end
|
|
59
59
|
|
|
@@ -64,9 +64,9 @@ module Lutaml
|
|
|
64
64
|
# @param obj [Object] The object to extract value from
|
|
65
65
|
# @return [Object] The value to use for sorting
|
|
66
66
|
def extract_sort_value(obj)
|
|
67
|
-
return "" unless obj.
|
|
67
|
+
return "" unless obj.class.attributes.key?(@field.to_sym)
|
|
68
68
|
|
|
69
|
-
value = obj.
|
|
69
|
+
value = obj.public_send(@field)
|
|
70
70
|
normalize_value(value)
|
|
71
71
|
end
|
|
72
72
|
|
|
@@ -236,7 +236,7 @@ module Lutaml
|
|
|
236
236
|
#
|
|
237
237
|
# @return [Array<Lutaml::Uml::Class>] Array of class objects
|
|
238
238
|
def fetch_classes
|
|
239
|
-
indexes = @repository.
|
|
239
|
+
indexes = @repository.indexes
|
|
240
240
|
qnames_index = indexes[:qualified_names] || {}
|
|
241
241
|
|
|
242
242
|
qnames_index.values.select do |obj|
|
|
@@ -250,7 +250,7 @@ module Lutaml
|
|
|
250
250
|
#
|
|
251
251
|
# @return [Array<Lutaml::Uml::Package>] Array of package objects
|
|
252
252
|
def fetch_packages
|
|
253
|
-
indexes = @repository.
|
|
253
|
+
indexes = @repository.indexes
|
|
254
254
|
package_paths_index = indexes[:package_paths] || {}
|
|
255
255
|
package_paths_index.values
|
|
256
256
|
end
|