lutaml 0.10.14 → 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 +23 -67
- data/lib/lutaml/cli/interactive_shell/export_handler.rb +16 -10
- data/lib/lutaml/cli/interactive_shell/navigation_commands.rb +11 -7
- data/lib/lutaml/cli/interactive_shell/query_commands.rb +11 -1
- data/lib/lutaml/cli/interactive_shell.rb +11 -3
- 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 +50 -22
- data/lib/lutaml/qea/factory/class_transformer.rb +24 -10
- data/lib/lutaml/qea/factory/ea_to_uml_factory.rb +11 -22
- data/lib/lutaml/qea/factory/enum_transformer.rb +20 -9
- data/lib/lutaml/qea/factory/generalization_builder.rb +12 -12
- data/lib/lutaml/qea/lookup_indexes.rb +23 -12
- data/lib/lutaml/uml/inheritance_walker.rb +11 -7
- 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 +20 -10
- data/lib/lutaml/uml_repository/index_builders/class_index.rb +5 -1
- data/lib/lutaml/uml_repository/queries/class_query.rb +15 -10
- 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 +17 -8
- data/lib/lutaml/uml_repository/static_site/serializers/class_serializer.rb +19 -13
- data/lib/lutaml/uml_repository/static_site/serializers/inheritance_resolver.rb +68 -66
- 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 +7 -2
- 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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cb62e96e62545c49b005e89cc972bc7dfb9510dbd9867831db9b6f4ab0bbcc40
|
|
4
|
+
data.tar.gz: 3975abff3b9a8e54714a76209d5917ed1bcf291baf9dcdf405c658d211934714
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a09b2b6074e7fb3fa04d2084b16c35ac5f9c115708ac8f50efaac08b5999cd21613053df9eebe487a714c361317e4411de2ecc8d2286b8100e3fe23102854265
|
|
7
|
+
data.tar.gz: 6d6c1dd06afac86c94ba1047087914b59b95d09e11308482f90bb3b99b4b65633eb443a565200842f07ce51064b14e2441a4406f408697a8fe55ef67ce33c9eb
|
data/.rubocop_todo.yml
CHANGED
|
@@ -1,41 +1,18 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on 2026-05-
|
|
3
|
+
# on 2026-05-13 02:18:49 UTC using RuboCop version 1.86.1.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
|
8
8
|
|
|
9
|
-
# Offense count:
|
|
10
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
11
|
-
# Configuration parameters: EnforcedStyle, IndentationWidth.
|
|
12
|
-
# SupportedStyles: with_first_argument, with_fixed_indentation
|
|
13
|
-
Layout/ArgumentAlignment:
|
|
14
|
-
Exclude:
|
|
15
|
-
- 'lib/lutaml/qea/factory/association_builder.rb'
|
|
16
|
-
- 'lib/lutaml/qea/factory/generalization_builder.rb'
|
|
17
|
-
- 'lib/lutaml/uml_repository/index_builders/class_index.rb'
|
|
18
|
-
- 'lib/lutaml/uml_repository/static_site/serializers/class_serializer.rb'
|
|
19
|
-
- 'lib/lutaml/uml_repository/static_site/serializers/inheritance_resolver.rb'
|
|
20
|
-
|
|
21
|
-
# Offense count: 158
|
|
9
|
+
# Offense count: 155
|
|
22
10
|
# This cop supports safe autocorrection (--autocorrect).
|
|
23
11
|
# Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
|
|
24
12
|
# URISchemes: http, https
|
|
25
13
|
Layout/LineLength:
|
|
26
14
|
Enabled: false
|
|
27
15
|
|
|
28
|
-
# Offense count: 7
|
|
29
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
30
|
-
# Configuration parameters: AllowInHeredoc.
|
|
31
|
-
Layout/TrailingWhitespace:
|
|
32
|
-
Exclude:
|
|
33
|
-
- 'lib/lutaml/qea/factory/generalization_builder.rb'
|
|
34
|
-
- 'lib/lutaml/uml_repository/index_builders/class_index.rb'
|
|
35
|
-
- 'lib/lutaml/uml_repository/queries/inheritance_query.rb'
|
|
36
|
-
- 'lib/lutaml/uml_repository/static_site/serializers/class_serializer.rb'
|
|
37
|
-
- 'lib/lutaml/uml_repository/static_site/serializers/inheritance_resolver.rb'
|
|
38
|
-
|
|
39
16
|
# Offense count: 1
|
|
40
17
|
Lint/BinaryOperatorWithIdenticalOperands:
|
|
41
18
|
Exclude:
|
|
@@ -95,46 +72,48 @@ Lint/UnusedMethodArgument:
|
|
|
95
72
|
Exclude:
|
|
96
73
|
- 'lib/lutaml/cli/uml/export_command.rb'
|
|
97
74
|
|
|
98
|
-
# Offense count:
|
|
75
|
+
# Offense count: 3
|
|
99
76
|
Lint/UselessConstantScoping:
|
|
100
77
|
Exclude:
|
|
101
78
|
- 'lib/lutaml/cli/interactive_shell.rb'
|
|
79
|
+
- 'lib/lutaml/qea/factory/ea_to_uml_factory.rb'
|
|
102
80
|
|
|
103
|
-
# Offense count:
|
|
81
|
+
# Offense count: 8
|
|
104
82
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
|
105
83
|
Metrics/AbcSize:
|
|
106
|
-
|
|
84
|
+
Exclude:
|
|
85
|
+
- 'lib/lutaml/cli/interactive_shell/query_commands.rb'
|
|
86
|
+
- 'lib/lutaml/qea/factory/generalization_builder.rb'
|
|
87
|
+
- 'lib/lutaml/uml_repository/exporters/markdown/class_page_builder.rb'
|
|
88
|
+
- 'lib/lutaml/uml_repository/queries/search_query.rb'
|
|
89
|
+
- 'lib/lutaml/uml_repository/static_site/serializers/class_serializer.rb'
|
|
90
|
+
- 'lib/lutaml/xmi/liquid_drops/klass_drop.rb'
|
|
107
91
|
|
|
108
|
-
# Offense count:
|
|
92
|
+
# Offense count: 4
|
|
109
93
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
110
94
|
Metrics/CyclomaticComplexity:
|
|
111
|
-
|
|
95
|
+
Exclude:
|
|
96
|
+
- 'lib/lutaml/qea/factory/generalization_builder.rb'
|
|
97
|
+
- 'lib/lutaml/uml_repository/index_builders/association_index.rb'
|
|
98
|
+
- 'lib/lutaml/uml_repository/queries/search_query.rb'
|
|
99
|
+
- 'lib/lutaml/uml_repository/static_site/serializers/class_serializer.rb'
|
|
112
100
|
|
|
113
|
-
# Offense count:
|
|
101
|
+
# Offense count: 48
|
|
114
102
|
# Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
|
|
115
103
|
Metrics/MethodLength:
|
|
116
|
-
Max:
|
|
104
|
+
Max: 18
|
|
117
105
|
|
|
118
|
-
# Offense count:
|
|
106
|
+
# Offense count: 4
|
|
119
107
|
# Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
|
|
120
108
|
Metrics/ParameterLists:
|
|
121
109
|
Max: 7
|
|
122
110
|
|
|
123
|
-
# Offense count:
|
|
111
|
+
# Offense count: 2
|
|
124
112
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
|
125
113
|
Metrics/PerceivedComplexity:
|
|
126
114
|
Exclude:
|
|
127
|
-
- 'lib/lutaml/cli/interactive_shell/navigation_commands.rb'
|
|
128
|
-
- 'lib/lutaml/converter/xmi_to_uml.rb'
|
|
129
|
-
- 'lib/lutaml/qea/factory/association_builder.rb'
|
|
130
115
|
- 'lib/lutaml/qea/factory/ea_to_uml_factory.rb'
|
|
131
|
-
- 'lib/lutaml/qea/lookup_indexes.rb'
|
|
132
|
-
- 'lib/lutaml/uml_repository/index_builders/association_index.rb'
|
|
133
|
-
- 'lib/lutaml/uml_repository/repository/loader.rb'
|
|
134
|
-
- 'lib/lutaml/uml_repository/static_site/data_transformer.rb'
|
|
135
116
|
- 'lib/lutaml/uml_repository/static_site/serializers/class_serializer.rb'
|
|
136
|
-
- 'lib/lutaml/uml_repository/static_site/serializers/inheritance_resolver.rb'
|
|
137
|
-
- 'lib/lutaml/xmi/parsers/xmi_connector.rb'
|
|
138
117
|
|
|
139
118
|
# Offense count: 3
|
|
140
119
|
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
|
@@ -154,11 +133,10 @@ Naming/PredicateMethod:
|
|
|
154
133
|
- 'lib/lutaml/qea/factory/document_builder.rb'
|
|
155
134
|
- 'spec/lutaml/xmi/liquid_drops/nil_safety_spec.rb'
|
|
156
135
|
|
|
157
|
-
# Offense count:
|
|
136
|
+
# Offense count: 2
|
|
158
137
|
# Configuration parameters: MinSize.
|
|
159
138
|
Performance/CollectionLiteralInLoop:
|
|
160
139
|
Exclude:
|
|
161
|
-
- 'lib/lutaml/xmi/parsers/xmi_connector.rb'
|
|
162
140
|
- 'spec/lutaml/qea/infrastructure/table_reader_spec.rb'
|
|
163
141
|
- 'spec/lutaml/uml_repository/index_builder_spec.rb'
|
|
164
142
|
|
|
@@ -327,12 +305,6 @@ Style/EvalWithLocation:
|
|
|
327
305
|
Exclude:
|
|
328
306
|
- 'spec/lutaml/cli/uml/search_command_spec.rb'
|
|
329
307
|
|
|
330
|
-
# Offense count: 2
|
|
331
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
332
|
-
Style/MultilineIfModifier:
|
|
333
|
-
Exclude:
|
|
334
|
-
- 'lib/lutaml/uml_repository/index_builders/class_index.rb'
|
|
335
|
-
|
|
336
308
|
# Offense count: 1
|
|
337
309
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
338
310
|
Style/PartitionInsteadOfDoubleSelect:
|
|
@@ -345,19 +317,3 @@ Style/SafeNavigationChainLength:
|
|
|
345
317
|
Exclude:
|
|
346
318
|
- 'lib/lutaml/qea/validation/attribute_validator.rb'
|
|
347
319
|
- 'lib/lutaml/qea/validation/operation_validator.rb'
|
|
348
|
-
|
|
349
|
-
# Offense count: 8
|
|
350
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
351
|
-
# Configuration parameters: EnforcedStyle.
|
|
352
|
-
# SupportedStyles: single_quotes, double_quotes
|
|
353
|
-
Style/StringLiteralsInInterpolation:
|
|
354
|
-
Exclude:
|
|
355
|
-
- 'lib/lutaml/cli/interactive_shell/help_display.rb'
|
|
356
|
-
|
|
357
|
-
# Offense count: 1
|
|
358
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
359
|
-
# Configuration parameters: EnforcedStyle, AllowSafeAssignment.
|
|
360
|
-
# SupportedStyles: require_parentheses, require_no_parentheses, require_parentheses_when_complex
|
|
361
|
-
Style/TernaryParentheses:
|
|
362
|
-
Exclude:
|
|
363
|
-
- 'lib/lutaml/qea/factory/association_builder.rb'
|
|
@@ -13,19 +13,17 @@ module Lutaml
|
|
|
13
13
|
}.freeze
|
|
14
14
|
|
|
15
15
|
def cmd_export(args)
|
|
16
|
-
if last_results.nil? || last_results.empty?
|
|
17
|
-
|
|
18
|
-
return
|
|
19
|
-
end
|
|
16
|
+
return warn_no_results if last_results.nil? || last_results.empty?
|
|
17
|
+
return warn_export_usage unless valid_export_args?(args)
|
|
20
18
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return
|
|
24
|
-
end
|
|
19
|
+
dispatch_export(args[1].downcase, args[2])
|
|
20
|
+
end
|
|
25
21
|
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
def valid_export_args?(args)
|
|
23
|
+
args.size >= 3 && args[0] == "last"
|
|
24
|
+
end
|
|
28
25
|
|
|
26
|
+
def dispatch_export(format, file_path)
|
|
29
27
|
exporter = EXPORT_FORMATS[format]
|
|
30
28
|
if exporter
|
|
31
29
|
public_send(exporter, file_path)
|
|
@@ -34,6 +32,14 @@ module Lutaml
|
|
|
34
32
|
end
|
|
35
33
|
end
|
|
36
34
|
|
|
35
|
+
def warn_no_results
|
|
36
|
+
puts OutputFormatter.warning("No results to export")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def warn_export_usage
|
|
40
|
+
puts OutputFormatter.warning("Usage: export last FORMAT FILE")
|
|
41
|
+
end
|
|
42
|
+
|
|
37
43
|
def export_csv(file_path)
|
|
38
44
|
require "csv"
|
|
39
45
|
|
|
@@ -95,14 +95,18 @@ module Lutaml
|
|
|
95
95
|
return path if path.start_with?("ModelRoot")
|
|
96
96
|
return current_path if path == "."
|
|
97
97
|
return "ModelRoot" if path == "/"
|
|
98
|
+
return resolve_parent_path(path) if path.start_with?("../")
|
|
99
|
+
return resolve_child_path(path) if path.start_with?("./")
|
|
98
100
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
101
|
+
resolve_simple_path(path)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def resolve_child_path(path)
|
|
105
|
+
"#{current_path}::#{path[2..]}"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def resolve_simple_path(path)
|
|
109
|
+
current_path == "ModelRoot" ? path : "#{current_path}::#{path}"
|
|
106
110
|
end
|
|
107
111
|
|
|
108
112
|
private
|
|
@@ -172,8 +172,14 @@ module Lutaml
|
|
|
172
172
|
puts ""
|
|
173
173
|
puts "Name: #{cls.name}"
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
display_class_attributes(cls) if has_displayable_attributes?(cls)
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def has_displayable_attributes?(cls)
|
|
179
|
+
cls.is_a?(Lutaml::Uml::Classifier) && cls.attributes && !cls.attributes.empty?
|
|
180
|
+
end
|
|
176
181
|
|
|
182
|
+
def display_class_attributes(cls)
|
|
177
183
|
puts ""
|
|
178
184
|
puts OutputFormatter.colorize("Attributes:", :yellow)
|
|
179
185
|
cls.attributes.each do |attr|
|
|
@@ -188,6 +194,10 @@ module Lutaml
|
|
|
188
194
|
puts "Name: #{pkg.name}"
|
|
189
195
|
puts ""
|
|
190
196
|
|
|
197
|
+
display_package_classes(path)
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def display_package_classes(path)
|
|
191
201
|
classes = repository.classes_in_package(path)
|
|
192
202
|
puts OutputFormatter.colorize("Classes (#{classes.size}):", :yellow)
|
|
193
203
|
classes.each do |cls|
|
|
@@ -88,14 +88,22 @@ module Lutaml
|
|
|
88
88
|
deduplicate_history(input)
|
|
89
89
|
execute_command(input.strip)
|
|
90
90
|
rescue Interrupt
|
|
91
|
-
|
|
91
|
+
handle_interrupt
|
|
92
92
|
rescue StandardError => e
|
|
93
|
-
|
|
94
|
-
puts e.backtrace.first(3).join("\n") if ENV["DEBUG"]
|
|
93
|
+
handle_error(e)
|
|
95
94
|
end
|
|
96
95
|
end
|
|
97
96
|
end
|
|
98
97
|
|
|
98
|
+
def handle_interrupt
|
|
99
|
+
puts "\nUse 'exit' or 'quit' to exit the shell"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def handle_error(error)
|
|
103
|
+
puts OutputFormatter.error("Error: #{error.message}")
|
|
104
|
+
puts error.backtrace.first(3).join("\n") if ENV["DEBUG"]
|
|
105
|
+
end
|
|
106
|
+
|
|
99
107
|
def deduplicate_history(input)
|
|
100
108
|
if Readline::HISTORY.length > 1 && Readline::HISTORY[-2] == input
|
|
101
109
|
Readline::HISTORY.pop
|
|
@@ -275,13 +275,21 @@ module Lutaml
|
|
|
275
275
|
|
|
276
276
|
# Determine class type (class, interface, enumeration)
|
|
277
277
|
def determine_class_type(klass)
|
|
278
|
-
return :enumeration if
|
|
279
|
-
return :interface if
|
|
280
|
-
Array(klass.stereotype).any? { |s| s&.downcase == "interface" }
|
|
278
|
+
return :enumeration if enumeration?(klass)
|
|
279
|
+
return :interface if interface?(klass)
|
|
281
280
|
|
|
282
281
|
:class
|
|
283
282
|
end
|
|
284
283
|
|
|
284
|
+
def enumeration?(klass)
|
|
285
|
+
klass.class.name&.include?("Enum")
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def interface?(klass)
|
|
289
|
+
klass.is_a?(Lutaml::Uml::TopElement) &&
|
|
290
|
+
Array(klass.stereotype).any? { |s| s&.downcase == "interface" }
|
|
291
|
+
end
|
|
292
|
+
|
|
285
293
|
# Find package path for a package object
|
|
286
294
|
def find_package_path(repository, package)
|
|
287
295
|
repository.indexes[:package_paths].each do |path, pkg|
|
|
@@ -148,12 +148,17 @@ module Lutaml
|
|
|
148
148
|
# Lazy-built hash index for O(1) diagram lookups by package
|
|
149
149
|
# @return [Hash] Mapping of package_id => [diagrams]
|
|
150
150
|
def diagram_lookup
|
|
151
|
-
@diagram_lookup ||=
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
151
|
+
@diagram_lookup ||= build_diagram_index
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def build_diagram_index
|
|
155
|
+
idx = Hash.new { |h, k| h[k] = [] }
|
|
156
|
+
xmi_diagrams.each { |d| idx[d.model.package] << d if d.model&.package }
|
|
157
|
+
idx
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def xmi_diagrams
|
|
161
|
+
@xmi_root_model.extension&.diagrams&.diagram || []
|
|
157
162
|
end
|
|
158
163
|
|
|
159
164
|
def create_uml_class_attributes(klass) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength
|
|
@@ -227,50 +227,65 @@ module Lutaml
|
|
|
227
227
|
field_table
|
|
228
228
|
end
|
|
229
229
|
|
|
230
|
-
def format_class(node, hide_members) # rubocop:disable Metrics/
|
|
230
|
+
def format_class(node, hide_members) # rubocop:disable Metrics/MethodLength
|
|
231
231
|
name = ["<B>#{node.name}</B>"]
|
|
232
232
|
name.unshift("«#{node.keyword}»") if node.keyword
|
|
233
|
-
name_html =
|
|
234
|
-
<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0">
|
|
235
|
-
#{name.map { |n| %(<TR><TD ALIGN="CENTER">#{n}</TD></TR>) }.join('\n')}
|
|
236
|
-
</TABLE>
|
|
237
|
-
HEREDOC
|
|
233
|
+
name_html = build_name_table(name)
|
|
238
234
|
|
|
239
235
|
field_table = format_member_rows(node.attributes, hide_members)
|
|
240
236
|
method_table = if node.operations&.any?
|
|
241
237
|
format_member_rows(node.operations, hide_members)
|
|
242
238
|
end
|
|
243
|
-
table_body =
|
|
244
|
-
|
|
239
|
+
table_body = build_table_body(name_html, field_table, method_table)
|
|
240
|
+
|
|
241
|
+
<<~HEREDOC.chomp
|
|
242
|
+
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="10">
|
|
243
|
+
#{table_body}
|
|
244
|
+
</TABLE>
|
|
245
|
+
HEREDOC
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
def build_name_table(name_parts)
|
|
249
|
+
<<~HEREDOC
|
|
250
|
+
<TABLE BORDER="0" CELLPADDING="0" CELLSPACING="0">
|
|
251
|
+
#{name_parts.map { |n| %(<TR><TD ALIGN="CENTER">#{n}</TD></TR>) }.join('\n')}
|
|
252
|
+
</TABLE>
|
|
253
|
+
HEREDOC
|
|
254
|
+
end
|
|
245
255
|
|
|
256
|
+
def build_table_body(name_html, field_table, method_table)
|
|
257
|
+
[name_html, field_table, method_table].compact.filter_map do |type|
|
|
246
258
|
<<~TEXT
|
|
247
259
|
<TR>
|
|
248
260
|
<TD>#{type}</TD>
|
|
249
261
|
</TR>
|
|
250
262
|
TEXT
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
<<~HEREDOC.chomp
|
|
254
|
-
<TABLE BORDER="0" CELLBORDER="1" CELLSPACING="0" CELLPADDING="10">
|
|
255
|
-
#{table_body.compact.join("\n")}
|
|
256
|
-
</TABLE>
|
|
257
|
-
HEREDOC
|
|
263
|
+
end.join("\n")
|
|
258
264
|
end
|
|
259
265
|
|
|
260
|
-
def format_document(node)
|
|
266
|
+
def format_document(node)
|
|
261
267
|
@fontname = node.fontname || DEFAULT_CLASS_FONT
|
|
262
268
|
@node["fontname"] = "#{@fontname}-bold"
|
|
263
269
|
|
|
270
|
+
hide_members, hide_other_classes = extract_fidelity_options(node)
|
|
271
|
+
classes = format_all_classes(node, hide_members)
|
|
272
|
+
associations = build_associations(node, hide_other_classes)
|
|
273
|
+
|
|
274
|
+
build_digraph(classes, associations)
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def extract_fidelity_options(node)
|
|
264
278
|
if node.fidelity
|
|
265
|
-
|
|
266
|
-
|
|
279
|
+
[node.fidelity.hideMembers, node.fidelity.hideOtherClasses]
|
|
280
|
+
else
|
|
281
|
+
[nil, nil]
|
|
267
282
|
end
|
|
268
|
-
|
|
269
|
-
node.enums +
|
|
270
|
-
node.data_types +
|
|
271
|
-
node.primitives).map do |class_node|
|
|
272
|
-
graph_node_name = generate_graph_name(class_node.name)
|
|
283
|
+
end
|
|
273
284
|
|
|
285
|
+
def format_all_classes(node, hide_members)
|
|
286
|
+
all_classes = node.classes + node.enums + node.data_types + node.primitives
|
|
287
|
+
all_classes.map do |class_node|
|
|
288
|
+
graph_node_name = generate_graph_name(class_node.name)
|
|
274
289
|
<<~HEREDOC
|
|
275
290
|
#{graph_node_name} [
|
|
276
291
|
shape="plain"
|
|
@@ -278,25 +293,36 @@ module Lutaml
|
|
|
278
293
|
label=<#{format_class(class_node, hide_members)}>]
|
|
279
294
|
HEREDOC
|
|
280
295
|
end.join("\n")
|
|
281
|
-
|
|
282
|
-
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def build_associations(node, hide_other_classes)
|
|
299
|
+
associations = collect_all_associations(node)
|
|
283
300
|
if node.groups
|
|
284
301
|
associations = sort_by_document_grouping(node.groups,
|
|
285
302
|
associations)
|
|
286
303
|
end
|
|
304
|
+
|
|
287
305
|
classes_names = node.classes.map(&:name)
|
|
288
|
-
associations
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
306
|
+
format_filtered_associations(associations, classes_names,
|
|
307
|
+
hide_other_classes)
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def collect_all_associations(node)
|
|
311
|
+
node.classes.filter_map(&:associations).flatten + node.associations
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
def format_filtered_associations(associations, classes_names,
|
|
315
|
+
hide_other_classes)
|
|
316
|
+
associations.filter_map do |assoc_node|
|
|
317
|
+
next if hide_other_classes && !classes_names.include?(assoc_node.member_end)
|
|
293
318
|
|
|
294
319
|
format_relationship(assoc_node)
|
|
295
320
|
end.join("\n")
|
|
321
|
+
end
|
|
296
322
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
323
|
+
def build_digraph(classes, associations)
|
|
324
|
+
indented_classes = indent_lines(classes)
|
|
325
|
+
indented_assocs = indent_lines(associations)
|
|
300
326
|
|
|
301
327
|
<<~HEREDOC
|
|
302
328
|
digraph G {
|
|
@@ -304,13 +330,17 @@ module Lutaml
|
|
|
304
330
|
edge [#{@edge}]
|
|
305
331
|
node [#{@node}]
|
|
306
332
|
|
|
307
|
-
#{
|
|
333
|
+
#{indented_classes}
|
|
308
334
|
|
|
309
|
-
#{
|
|
335
|
+
#{indented_assocs}
|
|
310
336
|
}
|
|
311
337
|
HEREDOC
|
|
312
338
|
end
|
|
313
339
|
|
|
340
|
+
def indent_lines(text)
|
|
341
|
+
text.lines.map { |line| " #{line}" }.join.chomp
|
|
342
|
+
end
|
|
343
|
+
|
|
314
344
|
protected
|
|
315
345
|
|
|
316
346
|
def sort_by_document_grouping(groups, associations) # rubocop:disable Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
|
@@ -55,7 +55,7 @@ module Lutaml
|
|
|
55
55
|
# @param file_path [String] Path to the model file
|
|
56
56
|
# @return [Lutaml::Uml::Document] Parsed UML document
|
|
57
57
|
# @raise [ParseError] if parsing fails
|
|
58
|
-
def parse(file_path)
|
|
58
|
+
def parse(file_path)
|
|
59
59
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
60
60
|
@stats_mutex.synchronize { @parse_stats[:total_parses] += 1 }
|
|
61
61
|
parse_succeeded = false
|
|
@@ -65,37 +65,35 @@ module Lutaml
|
|
|
65
65
|
validate_file!(file_path) if should_validate_input?
|
|
66
66
|
clear_errors_and_warnings
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
parse_succeeded, result = execute_parse(file_path)
|
|
69
|
+
parse_handled = !parse_succeeded
|
|
70
|
+
result
|
|
71
|
+
ensure
|
|
72
|
+
record_parse_stats(parse_succeeded, parse_handled, start_time)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
def execute_parse(file_path)
|
|
77
|
+
before_parse(file_path)
|
|
78
|
+
document = parse_internal(file_path)
|
|
79
|
+
document = after_parse(document, file_path)
|
|
80
|
+
validate_output!(document) if should_validate_output?
|
|
77
81
|
|
|
78
|
-
|
|
79
|
-
|
|
82
|
+
@stats_mutex.synchronize { @parse_stats[:successful_parses] += 1 }
|
|
83
|
+
[true, document]
|
|
84
|
+
rescue StandardError => e
|
|
85
|
+
[false, handle_parsing_error(e, file_path)]
|
|
86
|
+
end
|
|
80
87
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
unless parse_succeeded || parse_handled
|
|
91
|
-
@stats_mutex.synchronize { @parse_stats[:failed_parses] += 1 }
|
|
92
|
-
end
|
|
93
|
-
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
|
94
|
-
@last_duration = duration
|
|
95
|
-
@stats_mutex.synchronize do
|
|
96
|
-
@parse_stats[:total_duration] += duration
|
|
97
|
-
@parse_stats[:durations] << duration
|
|
98
|
-
end
|
|
88
|
+
def record_parse_stats(succeeded, handled, start_time)
|
|
89
|
+
unless succeeded || handled
|
|
90
|
+
@stats_mutex.synchronize { @parse_stats[:failed_parses] += 1 }
|
|
91
|
+
end
|
|
92
|
+
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start_time
|
|
93
|
+
@last_duration = duration
|
|
94
|
+
@stats_mutex.synchronize do
|
|
95
|
+
@parse_stats[:total_duration] += duration
|
|
96
|
+
@parse_stats[:durations] << duration
|
|
99
97
|
end
|
|
100
98
|
end
|
|
101
99
|
|