ea 0.1.0 → 0.1.4
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/CLAUDE.md +125 -0
- data/Rakefile +12 -4
- data/TODO.next/00-publish-blocking-bugs.md +74 -0
- data/TODO.next/01-standalone-ea-gem-identity.md +76 -0
- data/TODO.next/02-optional-lutaml-uml-dependency.md +47 -0
- data/TODO.next/03-slim-lutaml-uml.md +79 -0
- data/TODO.next/04-loader-registry-for-uml-repository.md +49 -0
- data/TODO.next/05-extract-shared-transformer-methods.md +14 -0
- data/TODO.next/06-deduplicate-stereotype-loading.md +17 -0
- data/TODO.next/07-transformer-registry-in-factory.md +20 -0
- data/TODO.next/08-connector-type-registry.md +27 -0
- data/TODO.next/09-element-renderer-registry.md +29 -0
- data/TODO.next/10-connector-renderer-lsp.md +18 -0
- data/TODO.next/11-consolidate-style-knowledge.md +33 -0
- data/TODO.next/12-data-driven-from-db-row.md +24 -0
- data/TODO.next/13-extract-duplicated-methods.md +17 -0
- data/TODO.next/14-remove-dead-code.md +10 -0
- data/TODO.next/15-narrow-exception-handling.md +39 -0
- data/TODO.next/16-repository-indexes.md +28 -0
- data/TODO.next/17-fix-spec-quality-and-coverage.md +32 -0
- data/TODO.next/18-xmi-tool-specific-parser-architecture.md +172 -0
- data/TODO.next/19-fix-ea-gemspec-dependency-declarations.md +56 -0
- data/TODO.next/20-ci-requires-unreleased-lutaml-uml.md +63 -0
- data/TODO.next/21-qeatoxmi-via-xmi-gem.md +340 -0
- data/TODO.next/22-strip-respond-to-from-qeatoxmi-specs.md +32 -0
- data/TODO.next/23-cleanup-idallocator.md +41 -0
- data/TODO.next/24-tighten-parity-specs.md +42 -0
- data/TODO.next/25-sparx-eaid-format-for-synthesized-ids.md +62 -0
- data/TODO.next/26-fix-uppervalue-lowervalue-count-gap.md +51 -0
- data/TODO.next/27-extract-cardinality-module.md +68 -0
- data/TODO.next/28-extract-xml-sanitizer.md +51 -0
- data/TODO.next/29-ocp-registry-for-classifier-builders.md +58 -0
- data/TODO.next/30-struct-return-for-association-end.md +37 -0
- data/TODO.next/31-idallocator-specs.md +27 -0
- data/TODO.next/32-phase2-gap-sentinel-specs.md +53 -0
- data/TODO.next/33-normalize-lower-cleanup.md +30 -0
- data/TODO.next/34-document-member-end-order-rt-prefix.md +29 -0
- data/TODO.next/35-walk-runstate-for-instance-slots.md +76 -0
- data/TODO.next/36-wire-interface-realization.md +50 -0
- data/TODO.next/37-visibility-returns-real-booleans.md +36 -0
- data/config/diagram_styles.yml +200 -0
- data/config/model_transformations.yml +266 -0
- data/config/qea_schema.yml +1024 -0
- data/docs/ea_to_uml_type_mapping.md +89 -0
- data/docs/xmi_qea_conversion_capabilities.md +99 -0
- data/examples/lur/20251010_current_plateau_v5.1.lur +0 -0
- data/examples/lur/basic.lur +0 -0
- data/examples/lur/test-output.lur +0 -0
- data/examples/lur/test.lur +0 -0
- data/examples/lur_basic_usage.rb +221 -0
- data/examples/lur_cli_workflow.rb +263 -0
- data/examples/lur_statistics.rb +326 -0
- data/examples/qea/20251010_current_plateau_v5.1.qea +0 -0
- data/examples/qea/ArcGISWorkspace_template.qea +0 -0
- data/examples/qea/README_qea_parser.adoc +230 -0
- data/examples/qea/UmlModel_template.qea +0 -0
- data/examples/qea/basic.qea +0 -0
- data/examples/qea/simple.qea +0 -0
- data/examples/qea/simple_example.qea +0 -0
- data/examples/qea/test.qea +0 -0
- data/examples/qea_standalone_query.rb +73 -0
- data/examples/qea_to_repository.rb +51 -0
- data/examples/smoke_test_real_qea.rb +81 -0
- data/exe/ea +7 -0
- data/lib/ea/cli/app.rb +72 -0
- data/lib/ea/cli/command/base.rb +80 -0
- data/lib/ea/cli/command/convert.rb +62 -0
- data/lib/ea/cli/command/diagrams.rb +81 -0
- data/lib/ea/cli/command/list.rb +61 -0
- data/lib/ea/cli/command/parse.rb +29 -0
- data/lib/ea/cli/command/stats.rb +20 -0
- data/lib/ea/cli/command/validate.rb +41 -0
- data/lib/ea/cli/command.rb +15 -0
- data/lib/ea/cli/error.rb +34 -0
- data/lib/ea/cli/output/formatter.rb +34 -0
- data/lib/ea/cli/output/json_formatter.rb +20 -0
- data/lib/ea/cli/output/table_formatter.rb +42 -0
- data/lib/ea/cli/output/yaml_formatter.rb +20 -0
- data/lib/ea/cli/output.rb +56 -0
- data/lib/ea/cli.rb +17 -0
- data/lib/ea/diagram/configuration.rb +379 -0
- data/lib/ea/diagram/element_renderers/base_renderer.rb +77 -0
- data/lib/ea/diagram/element_renderers/class_renderer.rb +323 -0
- data/lib/ea/diagram/element_renderers/connector_renderer.rb +41 -0
- data/lib/ea/diagram/element_renderers/package_renderer.rb +61 -0
- data/lib/ea/diagram/element_renderers.rb +43 -0
- data/lib/ea/diagram/extractor.rb +560 -0
- data/lib/ea/diagram/layout_engine.rb +170 -0
- data/lib/ea/diagram/path_builder.rb +202 -0
- data/lib/ea/diagram/style_parser.rb +42 -0
- data/lib/ea/diagram/style_resolver.rb +276 -0
- data/lib/ea/diagram/svg_renderer.rb +274 -0
- data/lib/ea/diagram/util.rb +73 -0
- data/lib/ea/diagram.rb +47 -0
- data/lib/ea/qea/benchmark.rb +210 -0
- data/lib/ea/qea/database.rb +308 -0
- data/lib/ea/qea/factory/association_builder.rb +203 -0
- data/lib/ea/qea/factory/association_transformer.rb +91 -0
- data/lib/ea/qea/factory/attribute_tag_transformer.rb +57 -0
- data/lib/ea/qea/factory/attribute_transformer.rb +93 -0
- data/lib/ea/qea/factory/base_transformer.rb +177 -0
- data/lib/ea/qea/factory/class_transformer.rb +116 -0
- data/lib/ea/qea/factory/constraint_transformer.rb +75 -0
- data/lib/ea/qea/factory/data_type_transformer.rb +77 -0
- data/lib/ea/qea/factory/diagram_transformer.rb +157 -0
- data/lib/ea/qea/factory/document_builder.rb +283 -0
- data/lib/ea/qea/factory/ea_to_uml_factory.rb +229 -0
- data/lib/ea/qea/factory/enum_transformer.rb +74 -0
- data/lib/ea/qea/factory/generalization_builder.rb +227 -0
- data/lib/ea/qea/factory/generalization_transformer.rb +98 -0
- data/lib/ea/qea/factory/instance_transformer.rb +68 -0
- data/lib/ea/qea/factory/object_property_transformer.rb +58 -0
- data/lib/ea/qea/factory/operation_transformer.rb +66 -0
- data/lib/ea/qea/factory/package_transformer.rb +145 -0
- data/lib/ea/qea/factory/reference_resolver.rb +99 -0
- data/lib/ea/qea/factory/stereotype_loader.rb +39 -0
- data/lib/ea/qea/factory/tagged_value_transformer.rb +38 -0
- data/lib/ea/qea/factory/transformer_registry.rb +80 -0
- data/lib/ea/qea/factory.rb +37 -0
- data/lib/ea/qea/file_detector.rb +178 -0
- data/lib/ea/qea/infrastructure/database_connection.rb +100 -0
- data/lib/ea/qea/infrastructure/schema_reader.rb +136 -0
- data/lib/ea/qea/infrastructure/table_reader.rb +224 -0
- data/lib/ea/qea/infrastructure.rb +12 -0
- data/lib/ea/qea/models/base_model.rb +59 -0
- data/lib/ea/qea/models/ea_attribute.rb +109 -0
- data/lib/ea/qea/models/ea_attribute_tag.rb +100 -0
- data/lib/ea/qea/models/ea_complexity_type.rb +79 -0
- data/lib/ea/qea/models/ea_connector.rb +160 -0
- data/lib/ea/qea/models/ea_connector_type.rb +60 -0
- data/lib/ea/qea/models/ea_constraint_type.rb +63 -0
- data/lib/ea/qea/models/ea_datatype.rb +104 -0
- data/lib/ea/qea/models/ea_diagram.rb +115 -0
- data/lib/ea/qea/models/ea_diagram_link.rb +78 -0
- data/lib/ea/qea/models/ea_diagram_object.rb +73 -0
- data/lib/ea/qea/models/ea_diagram_type.rb +56 -0
- data/lib/ea/qea/models/ea_document.rb +63 -0
- data/lib/ea/qea/models/ea_object.rb +223 -0
- data/lib/ea/qea/models/ea_object_constraint.rb +53 -0
- data/lib/ea/qea/models/ea_object_property.rb +87 -0
- data/lib/ea/qea/models/ea_object_type.rb +73 -0
- data/lib/ea/qea/models/ea_operation.rb +127 -0
- data/lib/ea/qea/models/ea_operation_param.rb +76 -0
- data/lib/ea/qea/models/ea_package.rb +78 -0
- data/lib/ea/qea/models/ea_script.rb +62 -0
- data/lib/ea/qea/models/ea_status_type.rb +66 -0
- data/lib/ea/qea/models/ea_stereotype.rb +57 -0
- data/lib/ea/qea/models/ea_tagged_value.rb +99 -0
- data/lib/ea/qea/models/ea_xref.rb +165 -0
- data/lib/ea/qea/models.rb +35 -0
- data/lib/ea/qea/repositories/base_repository.rb +225 -0
- data/lib/ea/qea/repositories/object_repository.rb +219 -0
- data/lib/ea/qea/repositories.rb +10 -0
- data/lib/ea/qea/services/configuration.rb +211 -0
- data/lib/ea/qea/services/database_loader.rb +191 -0
- data/lib/ea/qea/services.rb +10 -0
- data/lib/ea/qea/validation/association_validator.rb +73 -0
- data/lib/ea/qea/validation/attribute_validator.rb +91 -0
- data/lib/ea/qea/validation/base_validator.rb +331 -0
- data/lib/ea/qea/validation/class_validator.rb +121 -0
- data/lib/ea/qea/validation/database/circular_reference_validator.rb +109 -0
- data/lib/ea/qea/validation/database/orphan_validator.rb +153 -0
- data/lib/ea/qea/validation/database/referential_integrity_validator.rb +128 -0
- data/lib/ea/qea/validation/database.rb +16 -0
- data/lib/ea/qea/validation/diagram_validator.rb +112 -0
- data/lib/ea/qea/validation/formatters/json_formatter.rb +137 -0
- data/lib/ea/qea/validation/formatters/text_formatter.rb +235 -0
- data/lib/ea/qea/validation/formatters.rb +12 -0
- data/lib/ea/qea/validation/operation_validator.rb +71 -0
- data/lib/ea/qea/validation/package_validator.rb +111 -0
- data/lib/ea/qea/validation/validation_engine.rb +387 -0
- data/lib/ea/qea/validation/validation_message.rb +144 -0
- data/lib/ea/qea/validation/validation_result.rb +210 -0
- data/lib/ea/qea/validation/validator_registry.rb +134 -0
- data/lib/ea/qea/validation.rb +28 -0
- data/lib/ea/qea/verification/comparison_result.rb +264 -0
- data/lib/ea/qea/verification/document_normalizer.rb +169 -0
- data/lib/ea/qea/verification/document_verifier.rb +322 -0
- data/lib/ea/qea/verification/element_comparator.rb +277 -0
- data/lib/ea/qea/verification/structure_matcher.rb +287 -0
- data/lib/ea/qea/verification.rb +14 -0
- data/lib/ea/qea.rb +185 -0
- data/lib/ea/transformations/configuration.rb +333 -0
- data/lib/ea/transformations/format_registry.rb +366 -0
- data/lib/ea/transformations/parsers/base_parser.rb +482 -0
- data/lib/ea/transformations/parsers/qea_parser.rb +401 -0
- data/lib/ea/transformations/parsers/xmi_parser.rb +243 -0
- data/lib/ea/transformations/transformation_engine.rb +390 -0
- data/lib/ea/transformations.rb +85 -0
- data/lib/ea/transformers/qea_to_xmi/association_end.rb +19 -0
- data/lib/ea/transformers/qea_to_xmi/cardinality.rb +96 -0
- data/lib/ea/transformers/qea_to_xmi/context.rb +106 -0
- data/lib/ea/transformers/qea_to_xmi/guid_format.rb +56 -0
- data/lib/ea/transformers/qea_to_xmi/id_allocator.rb +92 -0
- data/lib/ea/transformers/qea_to_xmi/run_state.rb +107 -0
- data/lib/ea/transformers/qea_to_xmi/transformer.rb +607 -0
- data/lib/ea/transformers/qea_to_xmi/visibility.rb +73 -0
- data/lib/ea/transformers/qea_to_xmi.rb +29 -0
- data/lib/ea/transformers/uml_to_xmi/id_generator.rb +54 -0
- data/lib/ea/transformers/uml_to_xmi/transformer.rb +152 -0
- data/lib/ea/transformers/uml_to_xmi/writer.rb +96 -0
- data/lib/ea/transformers/uml_to_xmi.rb +16 -0
- data/lib/ea/transformers.rb +34 -0
- data/lib/ea/version.rb +1 -1
- data/lib/ea/xmi/liquid_drops/association_drop.rb +56 -0
- data/lib/ea/xmi/liquid_drops/attribute_drop.rb +72 -0
- data/lib/ea/xmi/liquid_drops/cardinality_drop.rb +35 -0
- data/lib/ea/xmi/liquid_drops/connector_drop.rb +54 -0
- data/lib/ea/xmi/liquid_drops/constraint_drop.rb +29 -0
- data/lib/ea/xmi/liquid_drops/data_type_drop.rb +63 -0
- data/lib/ea/xmi/liquid_drops/dependency_drop.rb +36 -0
- data/lib/ea/xmi/liquid_drops/diagram_drop.rb +34 -0
- data/lib/ea/xmi/liquid_drops/enum_drop.rb +49 -0
- data/lib/ea/xmi/liquid_drops/enum_owned_literal_drop.rb +25 -0
- data/lib/ea/xmi/liquid_drops/generalization_attribute_drop.rb +87 -0
- data/lib/ea/xmi/liquid_drops/generalization_drop.rb +127 -0
- data/lib/ea/xmi/liquid_drops/klass_drop.rb +191 -0
- data/lib/ea/xmi/liquid_drops/operation_drop.rb +29 -0
- data/lib/ea/xmi/liquid_drops/package_drop.rb +108 -0
- data/lib/ea/xmi/liquid_drops/root_drop.rb +34 -0
- data/lib/ea/xmi/liquid_drops/source_target_drop.rb +43 -0
- data/lib/ea/xmi/lookup_service.rb +89 -0
- data/lib/ea/xmi/parser.rb +919 -0
- data/lib/ea/xmi.rb +35 -0
- data/lib/ea.rb +10 -1
- metadata +382 -9
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
class GeneralizationBuilder < BaseTransformer
|
|
7
|
+
def load_generalization(object_id, visited = Set.new, is_leaf = true) # rubocop:disable Style/OptionalBooleanParameter
|
|
8
|
+
return nil if object_id.nil?
|
|
9
|
+
return nil if circular_inheritance?(object_id, visited)
|
|
10
|
+
|
|
11
|
+
visited = visited.dup.add(object_id)
|
|
12
|
+
|
|
13
|
+
current_obj = find_object_by_id(object_id)
|
|
14
|
+
return nil unless current_obj
|
|
15
|
+
|
|
16
|
+
generalization = build_generalization(object_id, current_obj)
|
|
17
|
+
return nil unless generalization
|
|
18
|
+
|
|
19
|
+
populate_generalization_attrs(generalization, object_id)
|
|
20
|
+
populate_parent_generalization(generalization,
|
|
21
|
+
ea_connector_for(object_id), visited)
|
|
22
|
+
|
|
23
|
+
collect_inherited_properties(generalization) if is_leaf && generalization.has_general
|
|
24
|
+
|
|
25
|
+
generalization
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def circular_inheritance?(object_id, visited)
|
|
29
|
+
return false unless visited.include?(object_id)
|
|
30
|
+
|
|
31
|
+
warn "Circular inheritance detected for object_id #{object_id}, " \
|
|
32
|
+
"stopping recursion"
|
|
33
|
+
true
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def load_association_generalizations(object_id)
|
|
37
|
+
return [] if object_id.nil?
|
|
38
|
+
|
|
39
|
+
gen_connectors = database.connectors_for_object(object_id)
|
|
40
|
+
.select { |c| c.generalization? && c.start_object_id == object_id }
|
|
41
|
+
|
|
42
|
+
gen_connectors.filter_map do |ea_connector|
|
|
43
|
+
build_assoc_generalization(ea_connector)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def convert_to_general_attributes(attributes)
|
|
48
|
+
attributes.map { |attr| to_general_attribute(attr) }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def convert_to_top_element_attributes(attributes)
|
|
52
|
+
attributes.map { |attr| to_top_element_attribute(attr) }
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def to_general_attribute(attr)
|
|
56
|
+
base = base_attr_hash(attr)
|
|
57
|
+
Lutaml::Uml::GeneralAttribute.new.tap do |gen_attr|
|
|
58
|
+
base.each { |k, v| gen_attr.public_send(:"#{k}=", v) }
|
|
59
|
+
gen_attr.is_derived = !!attr.is_derived
|
|
60
|
+
gen_attr.has_association = !!attr.association
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def to_top_element_attribute(attr)
|
|
65
|
+
base = base_attr_hash(attr)
|
|
66
|
+
Lutaml::Uml::TopElementAttribute.new.tap do |top_attr|
|
|
67
|
+
base.each { |k, v| top_attr.public_send(:"#{k}=", v) }
|
|
68
|
+
top_attr.is_derived = !!attr.is_derived
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def base_attr_hash(attr)
|
|
73
|
+
{
|
|
74
|
+
id: attr.id,
|
|
75
|
+
name: attr.name,
|
|
76
|
+
type: attr.type,
|
|
77
|
+
xmi_id: attr.xmi_id,
|
|
78
|
+
cardinality: attr.cardinality,
|
|
79
|
+
definition: attr.definition&.strip,
|
|
80
|
+
association: attr.association,
|
|
81
|
+
type_ns: attr.type_ns,
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
private
|
|
86
|
+
|
|
87
|
+
def tag_ancestor_attributes(gen, level)
|
|
88
|
+
[gen.general_attributes, gen.attributes].each do |attr_list|
|
|
89
|
+
attr_list&.each do |attr|
|
|
90
|
+
attr.upper_klass = gen.general_upper_klass
|
|
91
|
+
attr.level = level
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def collect_ancestor_attrs(gen, level, inherited_props,
|
|
97
|
+
inherited_assoc_props)
|
|
98
|
+
gen.attributes.reverse_each do |attr|
|
|
99
|
+
inherited_attr = attr.dup
|
|
100
|
+
inherited_attr.upper_klass = gen.general_upper_klass
|
|
101
|
+
inherited_attr.gen_name = gen.general_name
|
|
102
|
+
inherited_attr.level = level
|
|
103
|
+
|
|
104
|
+
if attr.has_association
|
|
105
|
+
inherited_assoc_props << inherited_attr
|
|
106
|
+
else
|
|
107
|
+
inherited_props << inherited_attr
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def build_assoc_generalization(ea_connector)
|
|
113
|
+
parent_obj = find_object_by_id(ea_connector.end_object_id)
|
|
114
|
+
return nil unless parent_obj
|
|
115
|
+
|
|
116
|
+
Lutaml::Uml::AssociationGeneralization.new.tap do |ag|
|
|
117
|
+
ag.id = normalize_guid_to_xmi_format(ea_connector.ea_guid, "EAID")
|
|
118
|
+
ag.type = "uml:Generalization"
|
|
119
|
+
ag.general = normalize_guid_to_xmi_format(parent_obj.ea_guid,
|
|
120
|
+
"EAID")
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def resolve_name_ns(type_ns, upper_klass)
|
|
125
|
+
ns = case type_ns
|
|
126
|
+
when "core", "gml"
|
|
127
|
+
upper_klass
|
|
128
|
+
else
|
|
129
|
+
type_ns
|
|
130
|
+
end
|
|
131
|
+
ns || upper_klass
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def build_generalization(object_id, current_obj)
|
|
135
|
+
ea_connector = ea_connector_for(object_id)
|
|
136
|
+
gen_transformer = GeneralizationTransformer.new(database)
|
|
137
|
+
if ea_connector.nil?
|
|
138
|
+
gen_transformer.transform(nil, current_obj)
|
|
139
|
+
else
|
|
140
|
+
gen_transformer.transform(ea_connector, current_obj)
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def ea_connector_for(object_id)
|
|
145
|
+
database.connectors_for_object(object_id)
|
|
146
|
+
.find { |c| c.generalization? && c.start_object_id == object_id }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def populate_generalization_attrs(generalization, object_id)
|
|
150
|
+
general_attrs = build_general_attrs(object_id)
|
|
151
|
+
apply_namespace_to_attrs(general_attrs, generalization)
|
|
152
|
+
|
|
153
|
+
generalization.general_attributes = general_attrs
|
|
154
|
+
.sort_by { |a| [a.name.to_s, a.id] }
|
|
155
|
+
|
|
156
|
+
generalization.attributes = transform_general_attributes(
|
|
157
|
+
generalization,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
generalization.owned_props = generalization.attributes
|
|
161
|
+
.reject(&:has_association)
|
|
162
|
+
generalization.assoc_props = generalization.attributes
|
|
163
|
+
.select(&:has_association)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def build_general_attrs(object_id)
|
|
167
|
+
current_attrs = load_attributes(object_id)
|
|
168
|
+
current_assoc_attrs = AssociationBuilder.new(database)
|
|
169
|
+
.load_association_attributes(object_id)
|
|
170
|
+
convert_to_general_attributes(current_attrs + current_assoc_attrs)
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def apply_namespace_to_attrs(general_attrs, generalization)
|
|
174
|
+
upper_klass = generalization.general_upper_klass
|
|
175
|
+
general_attrs.each do |attr|
|
|
176
|
+
attr.gen_name = generalization.general_name
|
|
177
|
+
attr.name_ns = resolve_name_ns(attr.type_ns, upper_klass)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def populate_parent_generalization(generalization, ea_connector,
|
|
182
|
+
visited)
|
|
183
|
+
parent_object_id = ea_connector&.end_object_id
|
|
184
|
+
return unless parent_object_id
|
|
185
|
+
|
|
186
|
+
parent_gen = load_generalization(parent_object_id, visited, false)
|
|
187
|
+
return unless parent_gen
|
|
188
|
+
|
|
189
|
+
generalization.general = parent_gen
|
|
190
|
+
generalization.has_general = true
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def transform_general_attributes(generalization)
|
|
194
|
+
upper_klass = generalization.general_upper_klass
|
|
195
|
+
gen_name = generalization.general_name
|
|
196
|
+
|
|
197
|
+
generalization.general_attributes.map do |attr|
|
|
198
|
+
transformed = attr.dup
|
|
199
|
+
transformed.name_ns = resolve_name_ns(attr.type_ns, upper_klass)
|
|
200
|
+
transformed.gen_name = gen_name
|
|
201
|
+
transformed.name = "" if transformed.name.nil?
|
|
202
|
+
transformed
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def collect_inherited_properties(generalization)
|
|
207
|
+
inherited_props = []
|
|
208
|
+
inherited_assoc_props = []
|
|
209
|
+
level = 0
|
|
210
|
+
|
|
211
|
+
current_gen = generalization.general
|
|
212
|
+
while current_gen
|
|
213
|
+
tag_ancestor_attributes(current_gen, level)
|
|
214
|
+
collect_ancestor_attrs(current_gen, level, inherited_props,
|
|
215
|
+
inherited_assoc_props)
|
|
216
|
+
|
|
217
|
+
level += 1
|
|
218
|
+
current_gen = current_gen.general
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
generalization.inherited_props = inherited_props.reverse
|
|
222
|
+
generalization.inherited_assoc_props = inherited_assoc_props.reverse
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
# Transforms EA connectors (Generalization type) to UML generalizations
|
|
7
|
+
class GeneralizationTransformer < BaseTransformer
|
|
8
|
+
# Transform EA connector to UML generalization
|
|
9
|
+
# @param ea_connector [EaConnector, nil]
|
|
10
|
+
# EA connector model (nil for terminal nodes)
|
|
11
|
+
# @param current_object [EaObject]
|
|
12
|
+
# Current object that owns this generalization
|
|
13
|
+
# @return [Lutaml::Uml::Generalization] UML generalization
|
|
14
|
+
def transform(ea_connector, current_object) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
|
15
|
+
return nil if current_object.nil?
|
|
16
|
+
|
|
17
|
+
# ea_connector can be nil for terminal nodes (classes with no parent)
|
|
18
|
+
if ea_connector && !ea_connector.generalization?
|
|
19
|
+
return nil
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Lutaml::Uml::Generalization.new.tap do |gen| # rubocop:disable Metrics/BlockLength
|
|
23
|
+
# Map properties from CURRENT object (not parent)
|
|
24
|
+
# This matches XMI's self-referential pattern
|
|
25
|
+
gen.general_id = normalize_guid_to_xmi_format(
|
|
26
|
+
current_object.ea_guid, "EAID"
|
|
27
|
+
)
|
|
28
|
+
gen.general_name = current_object.name
|
|
29
|
+
gen.name = current_object.name
|
|
30
|
+
gen.type = "uml:Generalization"
|
|
31
|
+
|
|
32
|
+
# Map definition from ea_connector notes
|
|
33
|
+
if !ea_connector&.notes.nil? && !ea_connector&.notes&.empty?
|
|
34
|
+
gen.definition = normalize_line_endings(ea_connector.notes)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Map stereotype from current object
|
|
38
|
+
gen.stereotype = [current_object.stereotype] unless
|
|
39
|
+
current_object.stereotype.nil? || current_object.stereotype.empty?
|
|
40
|
+
|
|
41
|
+
# Find the package/upper class for the current object
|
|
42
|
+
if current_object.package_id
|
|
43
|
+
current_package = find_package(current_object.package_id)
|
|
44
|
+
if current_package
|
|
45
|
+
gen.general_upper_klass =
|
|
46
|
+
extract_package_prefix(current_package)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Set has_general flag based on whether parent exists
|
|
51
|
+
# Use false (not nil) for terminal nodes to match XMI behavior
|
|
52
|
+
gen.has_general = if ea_connector
|
|
53
|
+
!ea_connector.end_object_id.nil?
|
|
54
|
+
else
|
|
55
|
+
false
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Note: general_attributes, attributes, owned_props, assoc_props,
|
|
59
|
+
# general, inherited_props, inherited_assoc_props
|
|
60
|
+
# will be populated in ClassTransformer.load_generalization
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
# Find object by ID
|
|
67
|
+
# @param object_id [Integer] Object ID
|
|
68
|
+
# @return [EaObject, nil] EA object or nil if not found
|
|
69
|
+
def find_object(object_id)
|
|
70
|
+
return nil if object_id.nil?
|
|
71
|
+
|
|
72
|
+
database.find_object(object_id)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Find package by ID
|
|
76
|
+
# @param package_id [Integer] Package ID
|
|
77
|
+
# @return [EaPackage, nil] EA package or nil if not found
|
|
78
|
+
def find_package(package_id)
|
|
79
|
+
return nil if package_id.nil?
|
|
80
|
+
|
|
81
|
+
database.find_package(package_id)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Extract package prefix from package
|
|
85
|
+
# @param package [EaPackage] EA package
|
|
86
|
+
# @return [String, nil] Package prefix or nil
|
|
87
|
+
def extract_package_prefix(package)
|
|
88
|
+
return nil unless package
|
|
89
|
+
|
|
90
|
+
# Try to extract a meaningful prefix from package name
|
|
91
|
+
# Common patterns: "ModelRoot::i-UR::urf" -> "urf"
|
|
92
|
+
parts = package.name&.split("::")
|
|
93
|
+
parts&.last
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
# Transforms EA objects (Object type) to UML instances
|
|
7
|
+
class InstanceTransformer < BaseTransformer
|
|
8
|
+
# Transform EA object to UML instance
|
|
9
|
+
# @param ea_object [EaObject] EA object model
|
|
10
|
+
# @return [Lutaml::Uml::Instance] UML instance
|
|
11
|
+
def transform(ea_object) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
|
|
12
|
+
return nil if ea_object.nil?
|
|
13
|
+
return nil unless ea_object.instance?
|
|
14
|
+
|
|
15
|
+
Lutaml::Uml::Instance.new.tap do |instance|
|
|
16
|
+
# Map basic properties
|
|
17
|
+
instance.name = ea_object.name
|
|
18
|
+
instance.xmi_id = normalize_guid_to_xmi_format(ea_object.ea_guid,
|
|
19
|
+
"EAID")
|
|
20
|
+
|
|
21
|
+
# Map classifier (the class this is an instance of)
|
|
22
|
+
if ea_object.classifier&.positive?
|
|
23
|
+
classifier_obj = find_classifier(ea_object.classifier)
|
|
24
|
+
if classifier_obj
|
|
25
|
+
instance.classifier = classifier_obj.name
|
|
26
|
+
end
|
|
27
|
+
elsif ea_object.classifier_guid && !ea_object.classifier_guid.empty?
|
|
28
|
+
classifier_obj = find_classifier_by_guid(
|
|
29
|
+
ea_object.classifier_guid,
|
|
30
|
+
)
|
|
31
|
+
if classifier_obj
|
|
32
|
+
instance.classifier = classifier_obj.name
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Map definition/notes
|
|
37
|
+
instance.definition = ea_object.note unless
|
|
38
|
+
ea_object.note.nil? || ea_object.note.empty?
|
|
39
|
+
|
|
40
|
+
# Load and transform tagged values
|
|
41
|
+
instance.tagged_values = load_tagged_values(ea_object.ea_guid)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
# Find classifier object by ID
|
|
48
|
+
# @param classifier_id [Integer] Classifier object ID
|
|
49
|
+
# @return [EaObject, nil] EA object or nil if not found
|
|
50
|
+
def find_classifier(classifier_id)
|
|
51
|
+
return nil if classifier_id.nil? || classifier_id.zero?
|
|
52
|
+
|
|
53
|
+
database.find_object(classifier_id)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Find classifier object by GUID
|
|
57
|
+
# @param classifier_guid [String] Classifier GUID
|
|
58
|
+
# @return [EaObject, nil] EA object or nil if not found
|
|
59
|
+
def find_classifier_by_guid(classifier_guid)
|
|
60
|
+
return nil if classifier_guid.nil? || classifier_guid.empty?
|
|
61
|
+
|
|
62
|
+
database.find_object_by_guid(classifier_guid)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
# Transforms EA ObjectProperty to UML Property/TaggedValue
|
|
7
|
+
#
|
|
8
|
+
# This transformer converts Enterprise Architect object properties
|
|
9
|
+
# (GML/XML Schema encoding metadata) to UML elements. Object properties
|
|
10
|
+
# are treated as specialized tagged values that enhance UML classes
|
|
11
|
+
# with schema-specific metadata.
|
|
12
|
+
#
|
|
13
|
+
# @example Transform an object property
|
|
14
|
+
# ea_prop = Models::EaObjectProperty.new(
|
|
15
|
+
# property_id: 1,
|
|
16
|
+
# object_id: 684,
|
|
17
|
+
# property: "isCollection",
|
|
18
|
+
# value: "false"
|
|
19
|
+
# )
|
|
20
|
+
# transformer = ObjectPropertyTransformer.new
|
|
21
|
+
# uml_tag = transformer.transform(ea_prop)
|
|
22
|
+
class ObjectPropertyTransformer < BaseTransformer
|
|
23
|
+
# Transform EA object property to UML TaggedValue
|
|
24
|
+
#
|
|
25
|
+
# Object properties enhance UML elements with GML/XML encoding
|
|
26
|
+
# metadata. They are transformed into tagged values to preserve
|
|
27
|
+
# this semantic information.
|
|
28
|
+
#
|
|
29
|
+
# @param ea_property [Models::EaObjectProperty] EA object property
|
|
30
|
+
# @return [Lutaml::Uml::TaggedValue, nil] UML tagged value or nil
|
|
31
|
+
def transform(ea_property)
|
|
32
|
+
return nil unless ea_property
|
|
33
|
+
return nil unless ea_property.property
|
|
34
|
+
|
|
35
|
+
Lutaml::Uml::TaggedValue.new.tap do |tag|
|
|
36
|
+
tag.name = ea_property.property
|
|
37
|
+
tag.value = ea_property.value || ""
|
|
38
|
+
tag.notes = format_notes(ea_property)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
# Format notes from EA property
|
|
45
|
+
#
|
|
46
|
+
# @param ea_property [Models::EaObjectProperty] EA property
|
|
47
|
+
# @return [String, nil] Formatted notes
|
|
48
|
+
def format_notes(ea_property)
|
|
49
|
+
return nil unless ea_property.notes
|
|
50
|
+
|
|
51
|
+
# Clean up EA's note format
|
|
52
|
+
notes = ea_property.notes.strip
|
|
53
|
+
notes.empty? ? nil : notes
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
# Transforms EA operations to UML operations
|
|
7
|
+
class OperationTransformer < BaseTransformer
|
|
8
|
+
# Transform EA operation to UML operation
|
|
9
|
+
# @param ea_operation [EaOperation] EA operation model
|
|
10
|
+
# @return [Lutaml::Uml::Operation] UML operation
|
|
11
|
+
def transform(ea_operation) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
12
|
+
return nil if ea_operation.nil?
|
|
13
|
+
|
|
14
|
+
Lutaml::Uml::Operation.new.tap do |op|
|
|
15
|
+
op.name = ea_operation.name
|
|
16
|
+
op.return_type = ea_operation.type
|
|
17
|
+
op.visibility = map_visibility(ea_operation.scope)
|
|
18
|
+
op.xmi_id = ea_operation.ea_guid
|
|
19
|
+
|
|
20
|
+
# Build parameter type string from operation parameters
|
|
21
|
+
op.parameter_type = build_parameter_type(ea_operation)
|
|
22
|
+
|
|
23
|
+
# Map definition/notes
|
|
24
|
+
op.definition = ea_operation.notes unless
|
|
25
|
+
ea_operation.notes.nil? || ea_operation.notes.empty?
|
|
26
|
+
|
|
27
|
+
# Map stereotype if present
|
|
28
|
+
if ea_operation.stereotype && !ea_operation.stereotype.empty?
|
|
29
|
+
op.stereotype = [ea_operation.stereotype]
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
# Build parameter type string from operation parameters
|
|
37
|
+
# @param ea_operation [EaOperation] EA operation
|
|
38
|
+
# @return [String, nil] Parameter type string
|
|
39
|
+
def build_parameter_type(ea_operation)
|
|
40
|
+
# Load parameters for this operation
|
|
41
|
+
params = load_parameters(ea_operation.operationid)
|
|
42
|
+
return nil if params.empty?
|
|
43
|
+
|
|
44
|
+
# Filter out return parameters and build parameter string
|
|
45
|
+
input_params = params.reject(&:return?)
|
|
46
|
+
return nil if input_params.empty?
|
|
47
|
+
|
|
48
|
+
input_params.map do |param|
|
|
49
|
+
type_str = param.type || "void"
|
|
50
|
+
"#{param.name}: #{type_str}"
|
|
51
|
+
end.join(", ")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Load parameters for an operation
|
|
55
|
+
# @param operation_id [Integer] Operation ID
|
|
56
|
+
# @return [Array<EaOperationParam>] Operation parameters
|
|
57
|
+
def load_parameters(operation_id)
|
|
58
|
+
return [] if operation_id.nil?
|
|
59
|
+
|
|
60
|
+
database.operation_params_for(operation_id)
|
|
61
|
+
.sort_by { |p| p.pos || 0 }
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Factory
|
|
6
|
+
# Transforms EA packages to UML packages
|
|
7
|
+
class PackageTransformer < BaseTransformer
|
|
8
|
+
# Transform EA package to UML package
|
|
9
|
+
# @param ea_package [EaPackage] EA package model
|
|
10
|
+
# @return [Lutaml::Uml::Package] UML package
|
|
11
|
+
def transform(ea_package) # rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
|
12
|
+
return nil if ea_package.nil?
|
|
13
|
+
|
|
14
|
+
Lutaml::Uml::Package.new.tap do |pkg|
|
|
15
|
+
# Map basic properties
|
|
16
|
+
pkg.name = ea_package.name
|
|
17
|
+
pkg.xmi_id = normalize_guid_to_xmi_format(ea_package.ea_guid,
|
|
18
|
+
"EAPK")
|
|
19
|
+
|
|
20
|
+
# Map definition/notes
|
|
21
|
+
pkg.definition = ea_package.notes unless
|
|
22
|
+
ea_package.notes.nil? || ea_package.notes.empty?
|
|
23
|
+
|
|
24
|
+
# Load and transform tagged values
|
|
25
|
+
pkg.tagged_values = load_tagged_values(ea_package.ea_guid)
|
|
26
|
+
|
|
27
|
+
# Load stereotype from t_xref
|
|
28
|
+
stereotype = load_stereotype(ea_package.ea_guid)
|
|
29
|
+
pkg.stereotype = [stereotype] if stereotype
|
|
30
|
+
|
|
31
|
+
# Note: Child packages and contents will be loaded separately
|
|
32
|
+
# to avoid circular dependencies and allow lazy loading
|
|
33
|
+
# Don't initialize collections - they have default values
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Transform and build complete package hierarchy
|
|
38
|
+
# @param ea_package [EaPackage] Root EA package
|
|
39
|
+
# @param include_children [Boolean] Whether to recursively load children
|
|
40
|
+
# @return [Lutaml::Uml::Package] Complete UML package with hierarchy
|
|
41
|
+
def transform_with_hierarchy(ea_package, include_children: true)
|
|
42
|
+
pkg = transform(ea_package)
|
|
43
|
+
return pkg unless include_children
|
|
44
|
+
|
|
45
|
+
# Load child packages
|
|
46
|
+
child_packages = load_child_packages(ea_package.package_id)
|
|
47
|
+
pkg.packages = child_packages.map do |child_pkg|
|
|
48
|
+
transform_with_hierarchy(child_pkg, include_children: true)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Load package contents (classes, diagrams, etc.)
|
|
52
|
+
load_package_contents(pkg, ea_package.package_id)
|
|
53
|
+
|
|
54
|
+
pkg
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
# Load child packages
|
|
60
|
+
# @param parent_id [Integer] Parent package ID
|
|
61
|
+
# @return [Array<EaPackage>] Child packages
|
|
62
|
+
def load_child_packages(parent_id)
|
|
63
|
+
return [] if parent_id.nil?
|
|
64
|
+
|
|
65
|
+
database.child_packages_for(parent_id)
|
|
66
|
+
.sort_by { |p| p.tpos || 0 }
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Load package contents (objects and diagrams)
|
|
70
|
+
# @param pkg [Lutaml::Uml::Package] UML package to populate
|
|
71
|
+
# @param package_id [Integer] EA package ID
|
|
72
|
+
def load_package_contents(pkg, package_id)
|
|
73
|
+
return if package_id.nil?
|
|
74
|
+
|
|
75
|
+
# Load objects (classes, etc.) in this package
|
|
76
|
+
load_package_objects(pkg, package_id)
|
|
77
|
+
|
|
78
|
+
# Load diagrams in this package
|
|
79
|
+
load_package_diagrams(pkg, package_id)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
# Maps transformer type keys to UML Package collection methods
|
|
83
|
+
COLLECTION_FOR_TYPE = {
|
|
84
|
+
class: :classes,
|
|
85
|
+
enumeration: :enums,
|
|
86
|
+
data_type: :data_types,
|
|
87
|
+
instance: :instances,
|
|
88
|
+
}.freeze
|
|
89
|
+
|
|
90
|
+
# Load objects for a package
|
|
91
|
+
# @param pkg [Lutaml::Uml::Package] UML package
|
|
92
|
+
# @param package_id [Integer] Package ID
|
|
93
|
+
def load_package_objects(pkg, package_id)
|
|
94
|
+
ea_objects = database.objects_in_package(package_id)
|
|
95
|
+
|
|
96
|
+
ea_objects.each do |ea_obj|
|
|
97
|
+
type_key = ea_obj.transformer_type
|
|
98
|
+
next unless type_key && COLLECTION_FOR_TYPE.key?(type_key)
|
|
99
|
+
|
|
100
|
+
transformer_class = TransformerRegistry.transformer_for(type_key)
|
|
101
|
+
next unless transformer_class
|
|
102
|
+
|
|
103
|
+
uml_element = transformer_class.new(database).transform(ea_obj)
|
|
104
|
+
next unless uml_element
|
|
105
|
+
|
|
106
|
+
collection = COLLECTION_FOR_TYPE[type_key]
|
|
107
|
+
pkg.public_send(collection) << uml_element
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Load diagrams for a package
|
|
112
|
+
# @param pkg [Lutaml::Uml::Package] UML package
|
|
113
|
+
# @param package_id [Integer] Package ID
|
|
114
|
+
def load_package_diagrams(pkg, package_id)
|
|
115
|
+
diagram_transformer = DiagramTransformer.new(database)
|
|
116
|
+
|
|
117
|
+
ea_diagrams = database.diagrams_in_package(package_id)
|
|
118
|
+
pkg.diagrams = diagram_transformer.transform_collection(ea_diagrams)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Load stereotype from t_xref table
|
|
122
|
+
# @param ea_guid [String] Element GUID
|
|
123
|
+
# @return [String, nil] Stereotype value (as string to match XMI format)
|
|
124
|
+
def load_stereotype(ea_guid)
|
|
125
|
+
return nil if ea_guid.nil?
|
|
126
|
+
|
|
127
|
+
StereotypeLoader.new(database).load_from_xref(ea_guid)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Check if an object appears on any diagram
|
|
131
|
+
# @param object_id [Integer] Object ID
|
|
132
|
+
# @return [Boolean] True if object appears on a diagram
|
|
133
|
+
def appears_on_diagram?(object_id)
|
|
134
|
+
return false if object_id.nil?
|
|
135
|
+
return false unless database.diagram_objects
|
|
136
|
+
|
|
137
|
+
# Check if object appears in any diagram's objects
|
|
138
|
+
database.diagram_objects.any? do |dobj|
|
|
139
|
+
dobj.ea_object_id == object_id
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
end
|