lutaml 0.10.13 → 0.10.15
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 +29 -33
- data/lib/lutaml/cli/interactive_shell/export_handler.rb +25 -17
- data/lib/lutaml/cli/interactive_shell/help_display.rb +39 -45
- data/lib/lutaml/cli/interactive_shell/navigation_commands.rb +45 -26
- data/lib/lutaml/cli/interactive_shell/query_commands.rb +73 -47
- data/lib/lutaml/cli/interactive_shell.rb +53 -27
- data/lib/lutaml/cli/tree_view_formatter.rb +11 -3
- data/lib/lutaml/converter/xmi_to_uml.rb +11 -6
- data/lib/lutaml/formatter/graphviz.rb +65 -35
- data/lib/lutaml/model_transformations/parsers/base_parser.rb +27 -29
- data/lib/lutaml/qea/factory/association_builder.rb +144 -127
- data/lib/lutaml/qea/factory/class_transformer.rb +91 -53
- data/lib/lutaml/qea/factory/ea_to_uml_factory.rb +11 -22
- data/lib/lutaml/qea/factory/enum_transformer.rb +41 -31
- data/lib/lutaml/qea/factory/generalization_builder.rb +155 -125
- data/lib/lutaml/qea/factory/stereotype_loader.rb +13 -7
- data/lib/lutaml/qea/lookup_indexes.rb +31 -13
- data/lib/lutaml/uml/inheritance_walker.rb +11 -7
- data/lib/lutaml/uml_repository/exporters/markdown/class_page_builder.rb +33 -25
- data/lib/lutaml/uml_repository/exporters/markdown/index_page_builder.rb +17 -9
- data/lib/lutaml/uml_repository/exporters/markdown_exporter.rb +27 -20
- data/lib/lutaml/uml_repository/index_builders/association_index.rb +60 -48
- data/lib/lutaml/uml_repository/index_builders/class_index.rb +35 -24
- data/lib/lutaml/uml_repository/queries/class_query.rb +79 -48
- data/lib/lutaml/uml_repository/queries/inheritance_query.rb +42 -32
- data/lib/lutaml/uml_repository/queries/search_query.rb +93 -85
- data/lib/lutaml/uml_repository/query_dsl/conditions/package_condition.rb +9 -2
- data/lib/lutaml/uml_repository/repository/loader.rb +14 -7
- data/lib/lutaml/uml_repository/static_site/data_transformer.rb +64 -35
- data/lib/lutaml/uml_repository/static_site/search_index_builder.rb +32 -19
- data/lib/lutaml/uml_repository/static_site/serializers/class_serializer.rb +36 -20
- data/lib/lutaml/uml_repository/static_site/serializers/inheritance_resolver.rb +131 -105
- data/lib/lutaml/uml_repository/static_site/serializers/package_serializer.rb +15 -9
- data/lib/lutaml/uml_repository/static_site/serializers/package_tree_builder.rb +38 -24
- data/lib/lutaml/version.rb +1 -1
- data/lib/lutaml/xmi/liquid_drops/klass_drop.rb +34 -18
- data/lib/lutaml/xmi/parsers/xmi_connector.rb +35 -23
- metadata +2 -9
- data/TODO.cleanups/01-resolve-production-todos.md +0 -65
- data/TODO.cleanups/02-reduce-metrics-offenses.md +0 -37
- data/TODO.cleanups/03-reduce-rspec-multiple-expectations.md +0 -54
- data/TODO.cleanups/04-reduce-rspec-example-length.md +0 -45
- data/TODO.cleanups/07-fix-lint-offenses.md +0 -74
- data/TODO.cleanups/08-reduce-memoized-helpers-and-nesting.md +0 -43
- data/TODO.cleanups/09-reduce-verified-doubles-and-rspec-style.md +0 -57
|
@@ -17,73 +17,111 @@ module Lutaml
|
|
|
17
17
|
class ClassTransformer < BaseTransformer
|
|
18
18
|
def transform(ea_object)
|
|
19
19
|
return nil if ea_object.nil?
|
|
20
|
-
|
|
21
|
-
is_class_type = ea_object.uml_class? || ea_object.interface?
|
|
22
|
-
is_proxy = ea_object.object_type == "ProxyConnector"
|
|
23
|
-
is_text_class = ea_object.object_type == "Text"
|
|
24
|
-
return nil unless is_class_type || is_proxy || is_text_class
|
|
20
|
+
return nil unless transformable?(ea_object)
|
|
25
21
|
|
|
26
22
|
Lutaml::Uml::Class.new.tap do |klass|
|
|
27
|
-
klass
|
|
28
|
-
klass
|
|
29
|
-
|
|
30
|
-
klass.is_abstract = ea_object.abstract?
|
|
31
|
-
klass.type = "Class"
|
|
32
|
-
klass.visibility = map_visibility(ea_object.visibility)
|
|
33
|
-
|
|
34
|
-
stereotypes = build_stereotypes(ea_object)
|
|
35
|
-
klass.stereotype = stereotypes unless stereotypes.empty?
|
|
36
|
-
|
|
37
|
-
klass.definition = normalize_line_endings(ea_object.note) unless
|
|
38
|
-
ea_object.note.nil? || ea_object.note.empty?
|
|
39
|
-
|
|
40
|
-
gen_builder = GeneralizationBuilder.new(database)
|
|
41
|
-
assoc_builder = AssociationBuilder.new(database)
|
|
42
|
-
|
|
43
|
-
attrs = load_attributes(ea_object.ea_object_id)
|
|
44
|
-
assoc_attrs = gen_builder.convert_to_top_element_attributes(
|
|
45
|
-
assoc_builder.load_association_attributes(ea_object.ea_object_id),
|
|
46
|
-
)
|
|
47
|
-
klass.attributes = attrs + assoc_attrs
|
|
48
|
-
|
|
49
|
-
klass.operations = load_operations(ea_object.ea_object_id)
|
|
50
|
-
klass.constraints = load_constraints(ea_object.ea_object_id)
|
|
51
|
-
klass.tagged_values = load_tagged_values(ea_object.ea_guid)
|
|
52
|
-
klass.tagged_values.concat(
|
|
53
|
-
load_object_properties(ea_object.ea_object_id),
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
klass.generalization = gen_builder.load_generalization(
|
|
57
|
-
ea_object.ea_object_id,
|
|
58
|
-
)
|
|
59
|
-
klass.association_generalization = gen_builder
|
|
60
|
-
.load_association_generalizations(ea_object.ea_object_id)
|
|
61
|
-
|
|
62
|
-
klass.associations = assoc_builder.load_class_associations(
|
|
63
|
-
ea_object.ea_object_id, ea_object.ea_guid
|
|
64
|
-
)
|
|
23
|
+
assign_basic_properties(klass, ea_object)
|
|
24
|
+
assign_features(klass, ea_object)
|
|
25
|
+
assign_relationships(klass, ea_object)
|
|
65
26
|
end
|
|
66
27
|
end
|
|
67
28
|
|
|
68
29
|
private
|
|
69
30
|
|
|
31
|
+
def transformable?(ea_object)
|
|
32
|
+
ea_object.uml_class? || ea_object.interface? ||
|
|
33
|
+
ea_object.object_type == "ProxyConnector" ||
|
|
34
|
+
ea_object.object_type == "Text"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def assign_basic_properties(klass, ea_object)
|
|
38
|
+
klass.name = ea_object.name
|
|
39
|
+
klass.xmi_id = normalize_guid_to_xmi_format(ea_object.ea_guid, "EAID")
|
|
40
|
+
klass.is_abstract = ea_object.abstract?
|
|
41
|
+
klass.type = "Class"
|
|
42
|
+
klass.visibility = map_visibility(ea_object.visibility)
|
|
43
|
+
assign_stereotypes(klass, ea_object)
|
|
44
|
+
assign_definition(klass, ea_object)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def assign_stereotypes(klass, ea_object)
|
|
48
|
+
stereotypes = build_stereotypes(ea_object)
|
|
49
|
+
klass.stereotype = stereotypes unless stereotypes.empty?
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def assign_definition(klass, ea_object)
|
|
53
|
+
return if ea_object.note.nil? || ea_object.note.empty?
|
|
54
|
+
|
|
55
|
+
klass.definition = normalize_line_endings(ea_object.note)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def assign_features(klass, ea_object)
|
|
59
|
+
klass.attributes = load_all_attributes(ea_object)
|
|
60
|
+
assign_feature_collections(klass, ea_object)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def assign_feature_collections(klass, ea_object)
|
|
64
|
+
klass.operations = load_operations(ea_object.ea_object_id)
|
|
65
|
+
klass.constraints = load_constraints(ea_object.ea_object_id)
|
|
66
|
+
klass.tagged_values = load_tagged_values(ea_object.ea_guid)
|
|
67
|
+
klass.tagged_values.concat(
|
|
68
|
+
load_object_properties(ea_object.ea_object_id),
|
|
69
|
+
)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def assign_relationships(klass, ea_object)
|
|
73
|
+
gen_builder = GeneralizationBuilder.new(database)
|
|
74
|
+
assoc_builder = AssociationBuilder.new(database)
|
|
75
|
+
|
|
76
|
+
klass.generalization = gen_builder.load_generalization(
|
|
77
|
+
ea_object.ea_object_id,
|
|
78
|
+
)
|
|
79
|
+
klass.association_generalization = gen_builder
|
|
80
|
+
.load_association_generalizations(ea_object.ea_object_id)
|
|
81
|
+
|
|
82
|
+
klass.associations = assoc_builder.load_class_associations(
|
|
83
|
+
ea_object.ea_object_id, ea_object.ea_guid
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def load_all_attributes(ea_object)
|
|
88
|
+
gen_builder = GeneralizationBuilder.new(database)
|
|
89
|
+
assoc_builder = AssociationBuilder.new(database)
|
|
90
|
+
|
|
91
|
+
attrs = load_attributes(ea_object.ea_object_id)
|
|
92
|
+
assoc_attrs = gen_builder.convert_to_top_element_attributes(
|
|
93
|
+
assoc_builder.load_association_attributes(ea_object.ea_object_id),
|
|
94
|
+
)
|
|
95
|
+
attrs + assoc_attrs
|
|
96
|
+
end
|
|
97
|
+
|
|
70
98
|
def build_stereotypes(ea_object)
|
|
71
99
|
stereotypes = []
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
100
|
+
add_direct_stereotype(stereotypes, ea_object)
|
|
101
|
+
add_xref_stereotype(stereotypes, ea_object)
|
|
102
|
+
add_interface_stereotype(stereotypes, ea_object)
|
|
103
|
+
|
|
104
|
+
stereotypes
|
|
105
|
+
end
|
|
75
106
|
|
|
107
|
+
def add_direct_stereotype(stereotypes, ea_object)
|
|
108
|
+
return unless ea_object.stereotype && !ea_object.stereotype.empty?
|
|
109
|
+
|
|
110
|
+
stereotypes << ea_object.stereotype
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def add_xref_stereotype(stereotypes, ea_object)
|
|
76
114
|
xref_stereotype = StereotypeLoader.new(database)
|
|
77
115
|
.load_from_xref(ea_object.ea_guid)
|
|
78
|
-
|
|
79
|
-
stereotypes << xref_stereotype
|
|
80
|
-
end
|
|
116
|
+
return unless xref_stereotype && !stereotypes.include?(xref_stereotype)
|
|
81
117
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
end
|
|
118
|
+
stereotypes << xref_stereotype
|
|
119
|
+
end
|
|
85
120
|
|
|
86
|
-
|
|
121
|
+
def add_interface_stereotype(stereotypes, ea_object)
|
|
122
|
+
return unless ea_object.interface? && !stereotypes.include?("interface")
|
|
123
|
+
|
|
124
|
+
stereotypes << "interface"
|
|
87
125
|
end
|
|
88
126
|
|
|
89
127
|
def load_attributes(object_id)
|
|
@@ -183,35 +183,24 @@ module Lutaml
|
|
|
183
183
|
# Register package and all its descendants in resolver
|
|
184
184
|
# @param package [Lutaml::Uml::Package] Package to register
|
|
185
185
|
# @return [void]
|
|
186
|
-
def register_package_hierarchy(package)
|
|
186
|
+
def register_package_hierarchy(package)
|
|
187
187
|
return if package.nil?
|
|
188
188
|
|
|
189
|
-
# Register the package itself
|
|
190
189
|
register_element(package)
|
|
190
|
+
register_package_members(package)
|
|
191
191
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
register_element(klass)
|
|
195
|
-
end
|
|
196
|
-
|
|
197
|
-
# Register all enums in the package
|
|
198
|
-
package.enums&.each do |enum|
|
|
199
|
-
register_element(enum)
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
# Register all data types in the package
|
|
203
|
-
package.data_types&.each do |data_type|
|
|
204
|
-
register_element(data_type)
|
|
192
|
+
package.packages&.each do |child_package|
|
|
193
|
+
register_package_hierarchy(child_package)
|
|
205
194
|
end
|
|
195
|
+
end
|
|
206
196
|
|
|
207
|
-
|
|
208
|
-
package.instances&.each do |instance|
|
|
209
|
-
register_element(instance)
|
|
210
|
-
end
|
|
197
|
+
MEMBER_COLLECTIONS = %i[classes enums data_types instances].freeze
|
|
211
198
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
199
|
+
def register_package_members(package)
|
|
200
|
+
MEMBER_COLLECTIONS.each do |collection|
|
|
201
|
+
package.public_send(collection)&.each do |elem|
|
|
202
|
+
register_element(elem)
|
|
203
|
+
end
|
|
215
204
|
end
|
|
216
205
|
end
|
|
217
206
|
|
|
@@ -13,53 +13,63 @@ module Lutaml
|
|
|
13
13
|
# Transform EA object to UML enum
|
|
14
14
|
# @param ea_object [EaObject] EA object model
|
|
15
15
|
# @return [Lutaml::Uml::Enum] UML enum
|
|
16
|
-
def transform(ea_object)
|
|
16
|
+
def transform(ea_object)
|
|
17
17
|
return nil if ea_object.nil?
|
|
18
|
-
return nil unless ea_object
|
|
19
|
-
(ea_object.stereotype && ea_object.stereotype.downcase == "enumeration")
|
|
18
|
+
return nil unless enum?(ea_object)
|
|
20
19
|
|
|
21
20
|
Lutaml::Uml::Enum.new.tap do |enum|
|
|
22
|
-
|
|
23
|
-
enum
|
|
24
|
-
enum.xmi_id = normalize_guid_to_xmi_format(ea_object.ea_guid,
|
|
25
|
-
"EAID")
|
|
26
|
-
enum.visibility = map_visibility(ea_object.visibility)
|
|
27
|
-
|
|
28
|
-
# Map stereotype
|
|
29
|
-
if ea_object.stereotype && !ea_object.stereotype.empty?
|
|
30
|
-
enum.stereotype = [ea_object.stereotype]
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Map definition/notes
|
|
34
|
-
enum.definition = ea_object.note unless
|
|
35
|
-
ea_object.note.nil? || ea_object.note.empty?
|
|
36
|
-
|
|
37
|
-
# Load enum values (stored as attributes in EA)
|
|
38
|
-
enum.values = load_enum_values(ea_object.ea_object_id)
|
|
39
|
-
|
|
40
|
-
# Load and transform tagged values
|
|
41
|
-
enum.tagged_values = load_tagged_values(ea_object.ea_guid)
|
|
21
|
+
assign_enum_basic(enum, ea_object)
|
|
22
|
+
assign_enum_features(enum, ea_object)
|
|
42
23
|
end
|
|
43
24
|
end
|
|
44
25
|
|
|
26
|
+
def assign_enum_basic(enum, ea_object)
|
|
27
|
+
enum.name = ea_object.name
|
|
28
|
+
enum.xmi_id = normalize_guid_to_xmi_format(ea_object.ea_guid,
|
|
29
|
+
"EAID")
|
|
30
|
+
enum.visibility = map_visibility(ea_object.visibility)
|
|
31
|
+
enum.stereotype = [ea_object.stereotype] if valid_stereotype?(ea_object)
|
|
32
|
+
enum.definition = ea_object.note if note_present?(ea_object)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def note_present?(ea_object)
|
|
36
|
+
ea_object.note && !ea_object.note.empty?
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def assign_enum_features(enum, ea_object)
|
|
40
|
+
enum.values = load_enum_values(ea_object.ea_object_id)
|
|
41
|
+
enum.tagged_values = load_tagged_values(ea_object.ea_guid)
|
|
42
|
+
end
|
|
43
|
+
|
|
45
44
|
private
|
|
46
45
|
|
|
46
|
+
def enum?(ea_object)
|
|
47
|
+
ea_object.enumeration? ||
|
|
48
|
+
(ea_object.stereotype && ea_object.stereotype.downcase == "enumeration")
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def valid_stereotype?(ea_object)
|
|
52
|
+
ea_object.stereotype && !ea_object.stereotype.empty?
|
|
53
|
+
end
|
|
54
|
+
|
|
47
55
|
# Load enum values (literals) from attributes
|
|
48
56
|
# @param object_id [Integer] Object ID
|
|
49
57
|
# @return [Array<Lutaml::Uml::Value>] Enum values
|
|
50
|
-
def load_enum_values(object_id)
|
|
58
|
+
def load_enum_values(object_id)
|
|
51
59
|
return [] if object_id.nil?
|
|
52
60
|
|
|
53
61
|
ea_attrs = database.attributes_for_object(object_id)
|
|
54
62
|
.sort_by { |a| a.pos || 0 }
|
|
55
63
|
|
|
56
|
-
ea_attrs.filter_map
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
ea_attrs.filter_map { |ea_attr| build_enum_value(ea_attr) }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def build_enum_value(ea_attr)
|
|
68
|
+
Lutaml::Uml::Value.new.tap do |value|
|
|
69
|
+
value.name = ea_attr.name
|
|
70
|
+
value.id = normalize_guid_to_xmi_format(ea_attr.ea_guid, "EAID")
|
|
71
|
+
value.definition = ea_attr.notes unless
|
|
72
|
+
ea_attr.notes.nil? || ea_attr.notes.empty?
|
|
63
73
|
end
|
|
64
74
|
end
|
|
65
75
|
|
|
@@ -9,78 +9,33 @@ module Lutaml
|
|
|
9
9
|
module Qea
|
|
10
10
|
module Factory
|
|
11
11
|
class GeneralizationBuilder < BaseTransformer
|
|
12
|
-
def load_generalization(object_id, visited = Set.new, is_leaf = true) # rubocop:disable
|
|
12
|
+
def load_generalization(object_id, visited = Set.new, is_leaf = true) # rubocop:disable Style/OptionalBooleanParameter
|
|
13
13
|
return nil if object_id.nil?
|
|
14
|
-
|
|
15
|
-
if visited.include?(object_id)
|
|
16
|
-
warn "Circular inheritance detected for object_id #{object_id}, " \
|
|
17
|
-
"stopping recursion"
|
|
18
|
-
return nil
|
|
19
|
-
end
|
|
14
|
+
return nil if circular_inheritance?(object_id, visited)
|
|
20
15
|
|
|
21
16
|
visited = visited.dup.add(object_id)
|
|
22
17
|
|
|
23
18
|
current_obj = find_object_by_id(object_id)
|
|
24
19
|
return nil unless current_obj
|
|
25
20
|
|
|
26
|
-
|
|
27
|
-
.find { |c| c.generalization? && c.start_object_id == object_id }
|
|
28
|
-
|
|
29
|
-
gen_transformer = GeneralizationTransformer.new(database)
|
|
30
|
-
generalization = if ea_connector.nil?
|
|
31
|
-
gen_transformer.transform(nil, current_obj)
|
|
32
|
-
else
|
|
33
|
-
gen_transformer.transform(ea_connector,
|
|
34
|
-
current_obj)
|
|
35
|
-
end
|
|
21
|
+
generalization = build_generalization(object_id, current_obj)
|
|
36
22
|
return nil unless generalization
|
|
37
23
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
general_attrs = convert_to_general_attributes(
|
|
42
|
-
current_attrs + current_assoc_attrs,
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
upper_klass = generalization.general_upper_klass
|
|
46
|
-
gen_name = generalization.general_name
|
|
47
|
-
general_attrs.each do |attr|
|
|
48
|
-
attr.gen_name = gen_name
|
|
49
|
-
name_ns = case attr.type_ns
|
|
50
|
-
when "core", "gml"
|
|
51
|
-
upper_klass
|
|
52
|
-
else
|
|
53
|
-
attr.type_ns
|
|
54
|
-
end
|
|
55
|
-
attr.name_ns = name_ns || upper_klass
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
generalization.general_attributes = general_attrs
|
|
59
|
-
.sort_by { |a| [a.name.to_s, a.id] }
|
|
24
|
+
populate_generalization_attrs(generalization, object_id)
|
|
25
|
+
populate_parent_generalization(generalization,
|
|
26
|
+
ea_connector_for(object_id), visited)
|
|
60
27
|
|
|
61
|
-
generalization
|
|
62
|
-
generalization,
|
|
63
|
-
)
|
|
28
|
+
collect_inherited_properties(generalization) if is_leaf && generalization.has_general
|
|
64
29
|
|
|
65
|
-
generalization
|
|
66
|
-
|
|
67
|
-
generalization.assoc_props = generalization.attributes
|
|
68
|
-
.select(&:has_association)
|
|
69
|
-
|
|
70
|
-
parent_object_id = ea_connector&.end_object_id
|
|
71
|
-
if parent_object_id
|
|
72
|
-
parent_gen = load_generalization(parent_object_id, visited, false)
|
|
73
|
-
if parent_gen
|
|
74
|
-
generalization.general = parent_gen
|
|
75
|
-
generalization.has_general = true
|
|
76
|
-
end
|
|
77
|
-
end
|
|
30
|
+
generalization
|
|
31
|
+
end
|
|
78
32
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
end
|
|
33
|
+
def circular_inheritance?(object_id, visited)
|
|
34
|
+
return false unless visited.include?(object_id)
|
|
82
35
|
|
|
83
|
-
|
|
36
|
+
warn "Circular inheritance detected for object_id #{object_id}, " \
|
|
37
|
+
"stopping recursion"
|
|
38
|
+
true
|
|
84
39
|
end
|
|
85
40
|
|
|
86
41
|
def load_association_generalizations(object_id)
|
|
@@ -90,55 +45,155 @@ module Lutaml
|
|
|
90
45
|
.select { |c| c.generalization? && c.start_object_id == object_id }
|
|
91
46
|
|
|
92
47
|
gen_connectors.filter_map do |ea_connector|
|
|
93
|
-
|
|
94
|
-
|
|
48
|
+
build_assoc_generalization(ea_connector)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
95
51
|
|
|
96
|
-
|
|
97
|
-
|
|
52
|
+
def convert_to_general_attributes(attributes)
|
|
53
|
+
attributes.map { |attr| to_general_attribute(attr) }
|
|
54
|
+
end
|
|
98
55
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
56
|
+
def convert_to_top_element_attributes(attributes)
|
|
57
|
+
attributes.map { |attr| to_top_element_attribute(attr) }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def to_general_attribute(attr)
|
|
61
|
+
base = base_attr_hash(attr)
|
|
62
|
+
Lutaml::Uml::GeneralAttribute.new.tap do |gen_attr|
|
|
63
|
+
base.each { |k, v| gen_attr.public_send(:"#{k}=", v) }
|
|
64
|
+
gen_attr.is_derived = !!attr.is_derived
|
|
65
|
+
gen_attr.has_association = !!attr.association
|
|
105
66
|
end
|
|
106
67
|
end
|
|
107
68
|
|
|
108
|
-
def
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
69
|
+
def to_top_element_attribute(attr)
|
|
70
|
+
base = base_attr_hash(attr)
|
|
71
|
+
Lutaml::Uml::TopElementAttribute.new.tap do |top_attr|
|
|
72
|
+
base.each { |k, v| top_attr.public_send(:"#{k}=", v) }
|
|
73
|
+
top_attr.is_derived = !!attr.is_derived
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def base_attr_hash(attr)
|
|
78
|
+
{
|
|
79
|
+
id: attr.id,
|
|
80
|
+
name: attr.name,
|
|
81
|
+
type: attr.type,
|
|
82
|
+
xmi_id: attr.xmi_id,
|
|
83
|
+
cardinality: attr.cardinality,
|
|
84
|
+
definition: attr.definition&.strip,
|
|
85
|
+
association: attr.association,
|
|
86
|
+
type_ns: attr.type_ns,
|
|
87
|
+
}
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
def tag_ancestor_attributes(gen, level)
|
|
93
|
+
[gen.general_attributes, gen.attributes].each do |attr_list|
|
|
94
|
+
attr_list&.each do |attr|
|
|
95
|
+
attr.upper_klass = gen.general_upper_klass
|
|
96
|
+
attr.level = level
|
|
121
97
|
end
|
|
122
98
|
end
|
|
123
99
|
end
|
|
124
100
|
|
|
125
|
-
def
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
101
|
+
def collect_ancestor_attrs(gen, level, inherited_props,
|
|
102
|
+
inherited_assoc_props)
|
|
103
|
+
gen.attributes.reverse_each do |attr|
|
|
104
|
+
inherited_attr = attr.dup
|
|
105
|
+
inherited_attr.upper_klass = gen.general_upper_klass
|
|
106
|
+
inherited_attr.gen_name = gen.general_name
|
|
107
|
+
inherited_attr.level = level
|
|
108
|
+
|
|
109
|
+
if attr.has_association
|
|
110
|
+
inherited_assoc_props << inherited_attr
|
|
111
|
+
else
|
|
112
|
+
inherited_props << inherited_attr
|
|
137
113
|
end
|
|
138
114
|
end
|
|
139
115
|
end
|
|
140
116
|
|
|
141
|
-
|
|
117
|
+
def build_assoc_generalization(ea_connector)
|
|
118
|
+
parent_obj = find_object_by_id(ea_connector.end_object_id)
|
|
119
|
+
return nil unless parent_obj
|
|
120
|
+
|
|
121
|
+
Lutaml::Uml::AssociationGeneralization.new.tap do |ag|
|
|
122
|
+
ag.id = normalize_guid_to_xmi_format(ea_connector.ea_guid, "EAID")
|
|
123
|
+
ag.type = "uml:Generalization"
|
|
124
|
+
ag.general = normalize_guid_to_xmi_format(parent_obj.ea_guid,
|
|
125
|
+
"EAID")
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def resolve_name_ns(type_ns, upper_klass)
|
|
130
|
+
ns = case type_ns
|
|
131
|
+
when "core", "gml"
|
|
132
|
+
upper_klass
|
|
133
|
+
else
|
|
134
|
+
type_ns
|
|
135
|
+
end
|
|
136
|
+
ns || upper_klass
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def build_generalization(object_id, current_obj)
|
|
140
|
+
ea_connector = ea_connector_for(object_id)
|
|
141
|
+
gen_transformer = GeneralizationTransformer.new(database)
|
|
142
|
+
if ea_connector.nil?
|
|
143
|
+
gen_transformer.transform(nil, current_obj)
|
|
144
|
+
else
|
|
145
|
+
gen_transformer.transform(ea_connector, current_obj)
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def ea_connector_for(object_id)
|
|
150
|
+
database.connectors_for_object(object_id)
|
|
151
|
+
.find { |c| c.generalization? && c.start_object_id == object_id }
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def populate_generalization_attrs(generalization, object_id)
|
|
155
|
+
general_attrs = build_general_attrs(object_id)
|
|
156
|
+
apply_namespace_to_attrs(general_attrs, generalization)
|
|
157
|
+
|
|
158
|
+
generalization.general_attributes = general_attrs
|
|
159
|
+
.sort_by { |a| [a.name.to_s, a.id] }
|
|
160
|
+
|
|
161
|
+
generalization.attributes = transform_general_attributes(
|
|
162
|
+
generalization,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
generalization.owned_props = generalization.attributes
|
|
166
|
+
.reject(&:has_association)
|
|
167
|
+
generalization.assoc_props = generalization.attributes
|
|
168
|
+
.select(&:has_association)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def build_general_attrs(object_id)
|
|
172
|
+
current_attrs = load_attributes(object_id)
|
|
173
|
+
current_assoc_attrs = AssociationBuilder.new(database)
|
|
174
|
+
.load_association_attributes(object_id)
|
|
175
|
+
convert_to_general_attributes(current_attrs + current_assoc_attrs)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def apply_namespace_to_attrs(general_attrs, generalization)
|
|
179
|
+
upper_klass = generalization.general_upper_klass
|
|
180
|
+
general_attrs.each do |attr|
|
|
181
|
+
attr.gen_name = generalization.general_name
|
|
182
|
+
attr.name_ns = resolve_name_ns(attr.type_ns, upper_klass)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def populate_parent_generalization(generalization, ea_connector,
|
|
187
|
+
visited)
|
|
188
|
+
parent_object_id = ea_connector&.end_object_id
|
|
189
|
+
return unless parent_object_id
|
|
190
|
+
|
|
191
|
+
parent_gen = load_generalization(parent_object_id, visited, false)
|
|
192
|
+
return unless parent_gen
|
|
193
|
+
|
|
194
|
+
generalization.general = parent_gen
|
|
195
|
+
generalization.has_general = true
|
|
196
|
+
end
|
|
142
197
|
|
|
143
198
|
def load_attributes(object_id)
|
|
144
199
|
return [] if object_id.nil?
|
|
@@ -152,18 +207,10 @@ module Lutaml
|
|
|
152
207
|
def transform_general_attributes(generalization)
|
|
153
208
|
upper_klass = generalization.general_upper_klass
|
|
154
209
|
gen_name = generalization.general_name
|
|
155
|
-
gen_attrs = generalization.general_attributes
|
|
156
210
|
|
|
157
|
-
|
|
211
|
+
generalization.general_attributes.map do |attr|
|
|
158
212
|
transformed = attr.dup
|
|
159
|
-
name_ns =
|
|
160
|
-
when "core", "gml"
|
|
161
|
-
upper_klass
|
|
162
|
-
else
|
|
163
|
-
attr.type_ns
|
|
164
|
-
end
|
|
165
|
-
name_ns = upper_klass if name_ns.nil?
|
|
166
|
-
transformed.name_ns = name_ns
|
|
213
|
+
transformed.name_ns = resolve_name_ns(attr.type_ns, upper_klass)
|
|
167
214
|
transformed.gen_name = gen_name
|
|
168
215
|
transformed.name = "" if transformed.name.nil?
|
|
169
216
|
transformed
|
|
@@ -177,26 +224,9 @@ module Lutaml
|
|
|
177
224
|
|
|
178
225
|
current_gen = generalization.general
|
|
179
226
|
while current_gen
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
attr.upper_klass = current_gen.general_upper_klass
|
|
184
|
-
attr.level = level
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
current_gen.attributes.reverse_each do |attr|
|
|
189
|
-
inherited_attr = attr.dup
|
|
190
|
-
inherited_attr.upper_klass = current_gen.general_upper_klass
|
|
191
|
-
inherited_attr.gen_name = current_gen.general_name
|
|
192
|
-
inherited_attr.level = level
|
|
193
|
-
|
|
194
|
-
if attr.has_association
|
|
195
|
-
inherited_assoc_props << inherited_attr
|
|
196
|
-
else
|
|
197
|
-
inherited_props << inherited_attr
|
|
198
|
-
end
|
|
199
|
-
end
|
|
227
|
+
tag_ancestor_attributes(current_gen, level)
|
|
228
|
+
collect_ancestor_attrs(current_gen, level, inherited_props,
|
|
229
|
+
inherited_assoc_props)
|
|
200
230
|
|
|
201
231
|
level += 1
|
|
202
232
|
current_gen = current_gen.general
|
|
@@ -12,21 +12,27 @@ module Lutaml
|
|
|
12
12
|
return nil if ea_guid.nil?
|
|
13
13
|
return nil unless @database.xrefs
|
|
14
14
|
|
|
15
|
-
xref =
|
|
15
|
+
xref = find_stereotype_xref(ea_guid)
|
|
16
|
+
return nil unless xref
|
|
17
|
+
|
|
18
|
+
extract_stereotype_name(xref.description)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def find_stereotype_xref(ea_guid)
|
|
24
|
+
@database.xrefs.find do |x|
|
|
16
25
|
x.client == ea_guid && x.name == "Stereotypes" &&
|
|
17
26
|
x.type == "element property"
|
|
18
27
|
end
|
|
28
|
+
end
|
|
19
29
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
description = xref.description
|
|
30
|
+
def extract_stereotype_name(description)
|
|
23
31
|
return nil if description.nil? || description.empty?
|
|
24
32
|
|
|
25
33
|
if description =~ /@STEREO;Name=([^;]+);/
|
|
26
|
-
|
|
34
|
+
Regexp.last_match(1)
|
|
27
35
|
end
|
|
28
|
-
|
|
29
|
-
nil
|
|
30
36
|
end
|
|
31
37
|
end
|
|
32
38
|
end
|