lutaml 0.10.4 → 0.10.6

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.
Files changed (119) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -0
  3. data/.rubocop.yml +10 -0
  4. data/.rubocop_todo.yml +218 -94
  5. data/TODO.cleanups/01-resolve-production-todos.md +65 -0
  6. data/TODO.cleanups/02-reduce-metrics-offenses.md +37 -0
  7. data/TODO.cleanups/03-reduce-rspec-multiple-expectations.md +54 -0
  8. data/TODO.cleanups/04-reduce-rspec-example-length.md +45 -0
  9. data/TODO.cleanups/05-replace-marshal-load.md +37 -0
  10. data/TODO.cleanups/06-replace-eval-in-tests.md +41 -0
  11. data/TODO.cleanups/07-fix-lint-offenses.md +74 -0
  12. data/TODO.cleanups/08-reduce-memoized-helpers-and-nesting.md +43 -0
  13. data/TODO.cleanups/09-reduce-verified-doubles-and-rspec-style.md +57 -0
  14. data/TODO.cleanups/10-split-large-files.md +47 -0
  15. data/bin/console +0 -1
  16. data/exe/lutaml +1 -0
  17. data/lib/lutaml/cli/element_identifier.rb +3 -6
  18. data/lib/lutaml/cli/interactive_shell/bookmark_commands.rb +88 -0
  19. data/lib/lutaml/cli/interactive_shell/command_base.rb +32 -0
  20. data/lib/lutaml/cli/interactive_shell/export_handler.rb +67 -0
  21. data/lib/lutaml/cli/interactive_shell/help_display.rb +114 -0
  22. data/lib/lutaml/cli/interactive_shell/navigation_commands.rb +135 -0
  23. data/lib/lutaml/cli/interactive_shell/query_commands.rb +185 -0
  24. data/lib/lutaml/cli/interactive_shell.rb +116 -802
  25. data/lib/lutaml/cli/uml/build_command.rb +5 -5
  26. data/lib/lutaml/cli/uml/verify_command.rb +0 -1
  27. data/lib/lutaml/converter/xmi_to_uml.rb +3 -153
  28. data/lib/lutaml/converter/xmi_to_uml_generalization.rb +193 -0
  29. data/lib/lutaml/formatter/graphviz.rb +1 -2
  30. data/lib/lutaml/qea/database.rb +1 -47
  31. data/lib/lutaml/qea/factory/association_builder.rb +188 -0
  32. data/lib/lutaml/qea/factory/base_transformer.rb +0 -1
  33. data/lib/lutaml/qea/factory/class_transformer.rb +40 -590
  34. data/lib/lutaml/qea/factory/diagram_transformer.rb +0 -3
  35. data/lib/lutaml/qea/factory/generalization_builder.rb +211 -0
  36. data/lib/lutaml/qea/factory/package_transformer.rb +1 -2
  37. data/lib/lutaml/qea/factory/stereotype_loader.rb +34 -0
  38. data/lib/lutaml/qea/lookup_indexes.rb +54 -0
  39. data/lib/lutaml/qea/models/ea_datatype.rb +0 -2
  40. data/lib/lutaml/qea/validation/validation_engine.rb +0 -2
  41. data/lib/lutaml/uml/has_members.rb +0 -1
  42. data/lib/lutaml/uml/inheritance_walker.rb +92 -0
  43. data/lib/lutaml/uml/model_helpers.rb +129 -0
  44. data/lib/lutaml/uml/node/attribute.rb +3 -1
  45. data/lib/lutaml/uml/node/class_node.rb +3 -3
  46. data/lib/lutaml/uml/operation.rb +2 -0
  47. data/lib/lutaml/uml_repository/class_lookup_index.rb +40 -0
  48. data/lib/lutaml/uml_repository/exporters/markdown/class_page_builder.rb +179 -0
  49. data/lib/lutaml/uml_repository/exporters/markdown/formatting.rb +36 -0
  50. data/lib/lutaml/uml_repository/exporters/markdown/index_page_builder.rb +73 -0
  51. data/lib/lutaml/uml_repository/exporters/markdown/link_resolver.rb +40 -0
  52. data/lib/lutaml/uml_repository/exporters/markdown/package_page_builder.rb +107 -0
  53. data/lib/lutaml/uml_repository/exporters/markdown_exporter.rb +26 -538
  54. data/lib/lutaml/uml_repository/index_builder.rb +3 -271
  55. data/lib/lutaml/uml_repository/index_builders/association_index.rb +141 -0
  56. data/lib/lutaml/uml_repository/index_builders/class_index.rb +94 -0
  57. data/lib/lutaml/uml_repository/index_builders/package_index.rb +57 -0
  58. data/lib/lutaml/uml_repository/package_exporter.rb +10 -20
  59. data/lib/lutaml/uml_repository/package_loader.rb +37 -17
  60. data/lib/lutaml/uml_repository/repository/deprecated.rb +39 -0
  61. data/lib/lutaml/uml_repository/repository/loader.rb +112 -0
  62. data/lib/lutaml/uml_repository/repository.rb +7 -57
  63. data/lib/lutaml/uml_repository/static_site/association_serialization.rb +142 -0
  64. data/lib/lutaml/uml_repository/static_site/configuration.rb +0 -2
  65. data/lib/lutaml/uml_repository/static_site/data_transformer.rb +52 -873
  66. data/lib/lutaml/uml_repository/static_site/generator.rb +29 -8
  67. data/lib/lutaml/uml_repository/static_site/search_index_builder.rb +1 -4
  68. data/lib/lutaml/uml_repository/static_site/serializers/attribute_serializer.rb +78 -0
  69. data/lib/lutaml/uml_repository/static_site/serializers/class_serializer.rb +124 -0
  70. data/lib/lutaml/uml_repository/static_site/serializers/diagram_serializer.rb +60 -0
  71. data/lib/lutaml/uml_repository/static_site/serializers/inheritance_resolver.rb +258 -0
  72. data/lib/lutaml/uml_repository/static_site/serializers/metadata_builder.rb +48 -0
  73. data/lib/lutaml/uml_repository/static_site/serializers/operation_serializer.rb +57 -0
  74. data/lib/lutaml/uml_repository/static_site/serializers/package_serializer.rb +94 -0
  75. data/lib/lutaml/uml_repository/static_site/serializers/package_tree_builder.rb +93 -0
  76. data/lib/lutaml/version.rb +1 -1
  77. data/lib/lutaml/xmi/liquid_drops/association_drop.rb +13 -35
  78. data/lib/lutaml/xmi/liquid_drops/attribute_drop.rb +12 -18
  79. data/lib/lutaml/xmi/liquid_drops/cardinality_drop.rb +14 -6
  80. data/lib/lutaml/xmi/liquid_drops/connector_drop.rb +0 -3
  81. data/lib/lutaml/xmi/liquid_drops/constraint_drop.rb +1 -3
  82. data/lib/lutaml/xmi/liquid_drops/data_type_drop.rb +13 -70
  83. data/lib/lutaml/xmi/liquid_drops/dependency_drop.rb +2 -5
  84. data/lib/lutaml/xmi/liquid_drops/diagram_drop.rb +5 -11
  85. data/lib/lutaml/xmi/liquid_drops/enum_drop.rb +8 -16
  86. data/lib/lutaml/xmi/liquid_drops/enum_owned_literal_drop.rb +3 -9
  87. data/lib/lutaml/xmi/liquid_drops/generalization_attribute_drop.rb +11 -13
  88. data/lib/lutaml/xmi/liquid_drops/generalization_drop.rb +27 -85
  89. data/lib/lutaml/xmi/liquid_drops/klass_drop.rb +39 -91
  90. data/lib/lutaml/xmi/liquid_drops/operation_drop.rb +3 -9
  91. data/lib/lutaml/xmi/liquid_drops/package_drop.rb +16 -44
  92. data/lib/lutaml/xmi/liquid_drops/root_drop.rb +3 -11
  93. data/lib/lutaml/xmi/liquid_drops/source_target_drop.rb +2 -5
  94. data/lib/lutaml/xmi/parsers/xmi_base.rb +2 -749
  95. data/lib/lutaml/xmi/parsers/xmi_class_members.rb +45 -0
  96. data/lib/lutaml/xmi/parsers/xmi_connector.rb +251 -0
  97. data/lib/lutaml/xmi/parsers/xml.rb +7 -120
  98. data/lib/lutaml/xmi/xmi_lookup_service.rb +42 -0
  99. data/lib/lutaml.rb +0 -1
  100. metadata +48 -21
  101. data/lib/lutaml/cli/commands/base_command.rb +0 -118
  102. data/lib/lutaml/command_line.rb +0 -272
  103. data/lib/lutaml/sysml/allocate.rb +0 -9
  104. data/lib/lutaml/sysml/allocated.rb +0 -9
  105. data/lib/lutaml/sysml/binding_connector.rb +0 -9
  106. data/lib/lutaml/sysml/block.rb +0 -32
  107. data/lib/lutaml/sysml/constraint_block.rb +0 -14
  108. data/lib/lutaml/sysml/copy.rb +0 -8
  109. data/lib/lutaml/sysml/derive_requirement.rb +0 -9
  110. data/lib/lutaml/sysml/nested_connector_end.rb +0 -13
  111. data/lib/lutaml/sysml/refine.rb +0 -9
  112. data/lib/lutaml/sysml/requirement.rb +0 -44
  113. data/lib/lutaml/sysml/requirement_related.rb +0 -9
  114. data/lib/lutaml/sysml/satisfy.rb +0 -9
  115. data/lib/lutaml/sysml/test_case.rb +0 -25
  116. data/lib/lutaml/sysml/trace.rb +0 -9
  117. data/lib/lutaml/sysml/verify.rb +0 -8
  118. data/lib/lutaml/sysml/xmi_file.rb +0 -486
  119. data/lib/lutaml/sysml.rb +0 -11
@@ -0,0 +1,179 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module UmlRepository
5
+ module Exporters
6
+ module Markdown
7
+ class ClassPageBuilder
8
+ include Formatting
9
+
10
+ def initialize(repository, link_resolver)
11
+ @repository = repository
12
+ @link_resolver = link_resolver
13
+ end
14
+
15
+ def build(klass, qname)
16
+ type = klass.class.name.split("::").last
17
+ pkg_path = @link_resolver.extract_package_path(qname)
18
+
19
+ <<~MARKDOWN
20
+ # #{type}: #{klass.name}
21
+
22
+ **Qualified Name**: `#{qname}`
23
+
24
+ **Package**: [#{pkg_path}](#{@link_resolver.package_link(pkg_path)})
25
+
26
+ #{build_stereotypes_section(klass)}
27
+
28
+ #{build_definition_section(klass)}
29
+
30
+ #{build_inheritance_section(klass)}
31
+
32
+ #{build_attributes_section(klass)}
33
+
34
+ #{build_operations_section(klass)}
35
+
36
+ #{build_associations_section(klass)}
37
+
38
+ #{build_enum_literals_section(klass)}
39
+
40
+ ---
41
+
42
+ [Back to Package](#{@link_resolver.package_link(pkg_path)}) | [Back to Index](../index.md)
43
+ MARKDOWN
44
+ end
45
+
46
+ private
47
+
48
+ def build_stereotypes_section(klass)
49
+ stereotypes_array = normalize_stereotypes(klass.stereotype)
50
+ return "" if stereotypes_array.empty?
51
+
52
+ "**Stereotypes**: #{stereotypes_array.map do |s|
53
+ "`#{s}`"
54
+ end.join(', ')}\n\n"
55
+ end
56
+
57
+ def build_definition_section(klass)
58
+ return "" unless klass.respond_to?(:definition) && klass.definition
59
+
60
+ "## Description\n\n#{klass.definition}\n\n"
61
+ end
62
+
63
+ def build_inheritance_section(klass)
64
+ parent = @repository.supertype_of(klass)
65
+ children = @repository.subtypes_of(klass)
66
+
67
+ return "" if parent.nil? && children.empty?
68
+
69
+ content = "## Inheritance\n\n"
70
+
71
+ if parent
72
+ parent_qname = @link_resolver.qualified_name(parent)
73
+ content += "**Extends**: [#{parent.name}](#{@link_resolver.class_link(parent_qname)})\n\n"
74
+ end
75
+
76
+ if children.any?
77
+ content += "**Extended by**:\n\n"
78
+ children.each do |child|
79
+ child_qname = @link_resolver.qualified_name(child)
80
+ content += "- [#{child.name}](#{@link_resolver.class_link(child_qname)})\n"
81
+ end
82
+ content += "\n"
83
+ end
84
+
85
+ content
86
+ rescue StandardError
87
+ ""
88
+ end
89
+
90
+ def build_attributes_section(klass)
91
+ return "" unless klass.attributes&.any?
92
+
93
+ content = "## Attributes\n\n"
94
+ content += "| Name | Type | Visibility | Cardinality |\n"
95
+ content += "|------|------|------------|-------------|\n"
96
+
97
+ klass.attributes.each do |attr|
98
+ visibility = attr.visibility || ""
99
+ cardinality = format_cardinality(attr.cardinality)
100
+ content += "| #{attr.name} | `#{attr.type}` | #{visibility} | " \
101
+ "#{cardinality} |\n"
102
+ end
103
+
104
+ "#{content}\n"
105
+ end
106
+
107
+ def build_operations_section(klass)
108
+ return "" unless klass.respond_to?(:operations) && klass.operations&.any?
109
+
110
+ content = "## Operations\n\n"
111
+ content += "| Name | Return Type | Visibility |\n"
112
+ content += "|------|-------------|------------|\n"
113
+
114
+ klass.operations.each do |op|
115
+ visibility = op.visibility || ""
116
+ return_type = op.return_type || "void"
117
+ content += "| #{op.name} | `#{return_type}` | #{visibility} |\n"
118
+ end
119
+
120
+ "#{content}\n"
121
+ end
122
+
123
+ def build_associations_section(klass)
124
+ associations = @repository.associations_of(klass)
125
+ return "" if associations.empty?
126
+
127
+ content = "## Associations\n\n"
128
+ content += "| Name | Target Class | Cardinality | Navigable |\n"
129
+ content += "|------|--------------|-------------|-----------|\n"
130
+
131
+ associations.each do |assoc|
132
+ content += format_association_row(assoc, klass)
133
+ end
134
+
135
+ "#{content}\n"
136
+ rescue StandardError
137
+ ""
138
+ end
139
+
140
+ def format_association_row(association, klass)
141
+ source_end = association.member_end&.first
142
+ target_end = association.member_end&.last
143
+
144
+ end_obj = if source_end&.type&.xmi_id == klass.xmi_id
145
+ target_end
146
+ else
147
+ source_end
148
+ end
149
+
150
+ return "" unless end_obj&.type
151
+
152
+ target_qname = @link_resolver.qualified_name(end_obj.type)
153
+ name = association.name || end_obj.name || ""
154
+ cardinality = format_cardinality(end_obj.cardinality)
155
+ navigable = end_obj.navigable? ? "Yes" : "No"
156
+
157
+ "| #{name} | [#{end_obj.type.name}](#{@link_resolver.class_link(target_qname)}) | " \
158
+ "#{cardinality} | #{navigable} |\n"
159
+ end
160
+
161
+ def build_enum_literals_section(klass)
162
+ unless klass.is_a?(Lutaml::Uml::Enum) && klass.owned_literal&.any?
163
+ return ""
164
+ end
165
+
166
+ content = "## Literals\n\n"
167
+ klass.owned_literal.each do |literal|
168
+ content += "- `#{literal.name}`"
169
+ content += ": #{literal.definition}" if literal.definition
170
+ content += "\n"
171
+ end
172
+
173
+ "#{content}\n"
174
+ end
175
+ end
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../uml/model_helpers"
4
+
5
+ module Lutaml
6
+ module UmlRepository
7
+ module Exporters
8
+ module Markdown
9
+ module Formatting
10
+ include Lutaml::Uml::ModelHelpers
11
+
12
+ def format_cardinality(cardinality)
13
+ return "" unless cardinality
14
+
15
+ min = cardinality.min || "0"
16
+ max = cardinality.max || "*"
17
+ "#{min}..#{max}"
18
+ end
19
+
20
+ def format_stereotypes(stereotype)
21
+ return "" unless stereotype
22
+
23
+ case stereotype
24
+ when Array
25
+ stereotype.join(", ")
26
+ when String
27
+ stereotype
28
+ else
29
+ ""
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module UmlRepository
5
+ module Exporters
6
+ module Markdown
7
+ class IndexPageBuilder
8
+ def initialize(repository, options, link_resolver)
9
+ @repository = repository
10
+ @options = options
11
+ @link_resolver = link_resolver
12
+ end
13
+
14
+ def build
15
+ title = @options.fetch(:title, "UML Model Documentation")
16
+ stats = @repository.statistics
17
+
18
+ <<~MARKDOWN
19
+ # #{title}
20
+
21
+ ## Overview
22
+
23
+ This documentation provides comprehensive information about the UML model.
24
+
25
+ ## Statistics
26
+
27
+ - **Total Packages**: #{stats&.dig(:total_packages) || 0}
28
+ - **Total Classes**: #{stats&.dig(:total_classes) || 0}
29
+ - **Total Associations**: #{stats&.dig(:total_associations) || 0}
30
+ - **Total Diagrams**: #{stats&.dig(:total_diagrams) || 0}
31
+
32
+ ## Package Structure
33
+
34
+ #{build_package_tree_markdown}
35
+
36
+ ## Navigation
37
+
38
+ - [Packages](packages/)
39
+ - [Classes](classes/)
40
+ MARKDOWN
41
+ end
42
+
43
+ private
44
+
45
+ def build_package_tree_markdown
46
+ root_path = @options[:package] || "ModelRoot"
47
+ tree = @repository.package_tree(root_path)
48
+ return "No packages found." unless tree
49
+
50
+ build_tree_node(tree, 0)
51
+ end
52
+
53
+ def build_tree_node(node, depth)
54
+ indent = " " * depth
55
+ path = node[:path]
56
+ link = @link_resolver.package_link(path)
57
+ result = "#{indent}- [#{node[:name]}](#{link})"
58
+ result += " (#{node[:classes_count]} classes)" if node[:classes_count].positive?
59
+ result += "\n"
60
+
61
+ if node[:children]&.any?
62
+ node[:children].each do |child|
63
+ result += build_tree_node(child, depth + 1)
64
+ end
65
+ end
66
+
67
+ result
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module UmlRepository
5
+ module Exporters
6
+ module Markdown
7
+ class LinkResolver
8
+ def initialize(indexes)
9
+ @indexes = indexes
10
+ end
11
+
12
+ def package_link(path)
13
+ "../packages/#{sanitize_filename(path)}.md"
14
+ end
15
+
16
+ def class_link(qname)
17
+ "../classes/#{sanitize_filename(qname)}.md"
18
+ end
19
+
20
+ def package_path(package)
21
+ @indexes&.dig(:package_to_path, package.xmi_id) || package.name
22
+ end
23
+
24
+ def qualified_name(klass)
25
+ @indexes&.dig(:class_to_qname, klass.xmi_id) || klass.name
26
+ end
27
+
28
+ def extract_package_path(qname)
29
+ parts = qname.split("::")
30
+ parts.size > 1 ? parts[0..-2].join("::") : "ModelRoot"
31
+ end
32
+
33
+ def sanitize_filename(name)
34
+ name.gsub("::", "_").gsub(/[^a-zA-Z0-9_\-.]/, "_")
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lutaml
4
+ module UmlRepository
5
+ module Exporters
6
+ module Markdown
7
+ class PackagePageBuilder
8
+ include Formatting
9
+
10
+ def initialize(repository, link_resolver)
11
+ @repository = repository
12
+ @link_resolver = link_resolver
13
+ end
14
+
15
+ def build(package, path)
16
+ classes = @repository.classes_in_package(path, recursive: false)
17
+ sub_packages = package.packages || []
18
+
19
+ <<~MARKDOWN
20
+ # Package: #{package.name}
21
+
22
+ **Qualified Path**: `#{path}`
23
+
24
+ ## Description
25
+
26
+ #{package.definition || 'No description available.'}
27
+
28
+ ## Statistics
29
+
30
+ - **Direct Classes**: #{classes.size}
31
+ - **Sub-packages**: #{sub_packages.size}
32
+
33
+ #{build_sub_packages_section(sub_packages)}
34
+
35
+ #{build_classes_section(classes)}
36
+
37
+ #{build_diagrams_section(path)}
38
+
39
+ ---
40
+
41
+ [Back to Index](../index.md)
42
+ MARKDOWN
43
+ end
44
+
45
+ private
46
+
47
+ def build_sub_packages_section(packages)
48
+ return "" if packages.empty?
49
+
50
+ content = "## Sub-packages\n\n"
51
+ packages.each do |pkg|
52
+ pkg_path = @link_resolver.package_path(pkg)
53
+ link = @link_resolver.package_link(pkg_path)
54
+ content += "- [#{pkg.name}](#{link})\n"
55
+ end
56
+ "#{content}\n"
57
+ end
58
+
59
+ def build_classes_section(classes)
60
+ return "## Classes\n\nNo classes in this package.\n" if classes.empty?
61
+
62
+ content = "## Classes\n\n"
63
+ content += "| Name | Type | Stereotypes | Attributes | Associations |\n"
64
+ content += "|------|------|-------------|------------|--------------|\n"
65
+
66
+ classes.sort_by(&:name).each do |klass|
67
+ content += format_class_table_row(klass)
68
+ end
69
+
70
+ "#{content}\n"
71
+ end
72
+
73
+ def format_class_table_row(klass)
74
+ qname = @link_resolver.qualified_name(klass)
75
+ link = @link_resolver.class_link(qname)
76
+ type = klass.class.name.split("::").last
77
+ stereotypes = format_stereotypes(klass.stereotype)
78
+ attrs_count = klass.attributes&.size || 0
79
+ assocs_count = count_associations(klass)
80
+
81
+ "| [#{klass.name}](#{link}) | #{type} | #{stereotypes} | " \
82
+ "#{attrs_count} | #{assocs_count} |\n"
83
+ end
84
+
85
+ def build_diagrams_section(package_path)
86
+ diagrams = @repository.diagrams_in_package(package_path)
87
+ return "" if diagrams.empty?
88
+
89
+ content = "## Diagrams\n\n"
90
+ diagrams.each do |diagram|
91
+ content += "- **#{diagram.name}** (#{diagram.diagram_type})\n"
92
+ end
93
+ "#{content}\n"
94
+ rescue StandardError
95
+ ""
96
+ end
97
+
98
+ def count_associations(klass)
99
+ @repository.associations_of(klass).size
100
+ rescue StandardError
101
+ 0
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end