ea 0.5.2 → 0.6.0
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/TODO.complete/01-t-xref-parsing.md +1 -1
- data/TODO.complete/02-per-label-geometry.md +1 -1
- data/TODO.complete/03-object-properties-constraints.md +1 -1
- data/TODO.complete/04-operation-params.md +1 -1
- data/TODO.complete/05-pdata-flag-matrix.md +1 -1
- data/TODO.complete/06-emf-image-rendering.md +1 -1
- data/TODO.complete/07-auxiliary-tables.md +1 -1
- data/TODO.complete/10-mdg-stereotype-registry.md +1 -1
- data/TODO.complete/11-gml-xsd-generation.md +1 -1
- data/TODO.complete/13-shapescript-interpreter.md +12 -23
- data/TODO.complete/20-cli-diff.md +1 -1
- data/TODO.complete/21-cli-render.md +1 -1
- data/TODO.complete/22-cli-export.md +1 -1
- data/TODO.complete/23-cli-mdg.md +1 -1
- data/TODO.complete/30-headerlines-ocp-refactor.md +1 -1
- data/TODO.complete/32-spec-coverage.md +1 -1
- data/TODO.complete/33-blocked-parity-gaps.md +1 -1
- data/TODO.complete/36-stereotype-icon-wiring.md +1 -1
- data/TODO.complete/37-cli-lint.md +1 -1
- data/TODO.complete/38-cli-query.md +1 -1
- data/TODO.complete/39-cli-info.md +1 -1
- data/TODO.complete/40-ocl-evaluator.md +1 -1
- data/TODO.complete/41-round-trip-spec.md +1 -1
- data/TODO.complete/42-html-diff-report.md +1 -1
- data/TODO.complete/43-json-schema-export.md +1 -1
- data/TODO.complete/44-remaining-qea-tables.md +1 -1
- data/TODO.complete/45-shapescript-extensions.md +1 -1
- data/TODO.complete/46-xsd-consolidation.md +1 -1
- data/TODO.complete/47-headerlines-legacy-removal.md +1 -1
- data/TODO.complete/51-remove-respond-to.md +42 -15
- data/TODO.complete/52-xsd-decouple-fixtures.md +1 -1
- data/TODO.complete/54-wire-stereotype-icon-renderer.md +1 -1
- data/TODO.complete/55-wire-shapescript.md +1 -1
- data/TODO.complete/56-wire-emf-renderer.md +1 -1
- data/TODO.complete/57-wire-ocl-evaluator.md +1 -1
- data/TODO.complete/58-diff-modifications.md +1 -1
- data/TODO.complete/59-delete-toy-xmi-export.md +1 -1
- data/TODO.complete/60-curate-json-export.md +1 -1
- data/TODO.complete/61-plantuml-relationships.md +1 -1
- data/TODO.complete/62-changelog.md +1 -1
- data/TODO.complete/63-dependabot-fix.md +1 -1
- data/TODO.complete/64-qeatoxmi-connectors.md +9 -24
- data/TODO.complete/65-qeatoxmi-diagrams.md +9 -23
- data/TODO.complete/66-qeatoxmi-style-tags-docs.md +25 -18
- data/TODO.complete/67-ocl-collection-ops.md +12 -12
- data/TODO.complete/68-ocl-comparison-ops.md +16 -11
- data/TODO.complete/69-spec-new-models.md +13 -18
- data/TODO.complete/70-specs-for-all-models.md +21 -0
- data/TODO.complete/71-autoload-audit.md +26 -0
- data/TODO.complete/72-extension-serializer-ocp-naming.md +26 -0
- data/TODO.complete/73-ocl-validator-latent-bugs.md +50 -0
- data/TODO.complete/74-visibility-symbol-dry.md +39 -0
- data/TODO.complete/75-database-table-collection-registry.md +32 -0
- data/TODO.complete/76-stale-todo-cleanup.md +52 -0
- data/TODO.complete/77-eliminate-banned-patterns-from-specs.md +55 -0
- data/TODO.complete/78-mdg-stereotype-emission.md +66 -0
- data/TODO.complete/79-equivalence-fixes.md +57 -0
- data/TODO.complete/80-performance-extension-serializer-indexes.md +43 -0
- data/TODO.complete/81-dry-scope-guid-extraction.md +33 -0
- data/TODO.complete/82-public-send-audit-conclusion.md +25 -0
- data/TODO.complete/83-dry-shared-xml-escape-guid-format.md +52 -0
- data/TODO.complete/84-ocp-markers-shape-registry.md +54 -0
- data/TODO.complete/85-frozen-literal-rubocop-normalize-type-spec.md +38 -0
- data/TODO.complete/86-frozen-sweep-lint-query-specs.md +55 -0
- data/TODO.complete/STATUS.md +26 -5
- data/lib/ea/cli/app.rb +1 -0
- data/lib/ea/cli/command/export.rb +10 -1
- data/lib/ea/cli/command/mdg.rb +1 -10
- data/lib/ea/cli/command/render.rb +2 -1
- data/lib/ea/diff/html_reporter.rb +1 -5
- data/lib/ea/export/json/generator.rb +5 -6
- data/lib/ea/export/plantuml/generator.rb +5 -3
- data/lib/ea/guid_format.rb +91 -0
- data/lib/ea/mdg/document.rb +2 -1
- data/lib/ea/mdg/loader.rb +2 -1
- data/lib/ea/mdg/registry.rb +57 -2
- data/lib/ea/mdg/xml/applies_to.rb +1 -1
- data/lib/ea/mdg/xml/apply.rb +1 -1
- data/lib/ea/mdg/xml/content.rb +1 -1
- data/lib/ea/mdg/xml/documentation.rb +1 -1
- data/lib/ea/mdg/xml/stereotype.rb +1 -1
- data/lib/ea/mdg/xml/stereotypes.rb +1 -1
- data/lib/ea/mdg/xml/tag.rb +1 -1
- data/lib/ea/mdg/xml/tagged_values.rb +1 -1
- data/lib/ea/mdg/xml/technology.rb +1 -1
- data/lib/ea/mdg/xml/uml_profile.rb +1 -1
- data/lib/ea/mdg/xml/uml_profiles.rb +1 -1
- data/lib/ea/mdg/xml.rb +2 -1
- data/lib/ea/mdg.rb +2 -1
- data/lib/ea/model/ghost_label.rb +2 -1
- data/lib/ea/ocl/evaluator.rb +4 -2
- data/lib/ea/qea/database.rb +57 -2
- data/lib/ea/qea/factory/reference_resolver.rb +1 -1
- data/lib/ea/qea/models/ea_attribute.rb +1 -17
- data/lib/ea/qea/models/ea_connector.rb +3 -2
- data/lib/ea/qea/models/ea_object.rb +14 -9
- data/lib/ea/qea/models/ea_operation.rb +1 -17
- data/lib/ea/qea/models/ea_xref.rb +3 -0
- data/lib/ea/qea/models/scope_predicate.rb +29 -0
- data/lib/ea/qea/models.rb +1 -0
- data/lib/ea/qea/repositories/base_repository.rb +4 -1
- data/lib/ea/qea/validation/base_validator.rb +3 -48
- data/lib/ea/qea/validation/database/ocl_constraint_validator.rb +23 -13
- data/lib/ea/shapescript/renderer.rb +1 -3
- data/lib/ea/sources/qea/diagram_builder.rb +1 -0
- data/lib/ea/sources/qea/id_normalizer.rb +2 -2
- data/lib/ea/svg/ea_emitter/background.rb +2 -1
- data/lib/ea/svg/ea_emitter/element/attribute_line_builder.rb +1 -6
- data/lib/ea/svg/ea_emitter/element/operation_renderer.rb +2 -7
- data/lib/ea/svg/ea_emitter/elements.rb +1 -3
- data/lib/ea/svg/ea_emitter/ghost_labels.rb +2 -1
- data/lib/ea/svg/ea_emitter/label/end_label.rb +1 -6
- data/lib/ea/svg/ea_emitter/marker/package_import.rb +1 -1
- data/lib/ea/svg/ea_emitter/markers.rb +52 -23
- data/lib/ea/svg/ea_emitter/text_renderer.rb +1 -4
- data/lib/ea/svg/ea_emitter/visibility_symbol.rb +37 -0
- data/lib/ea/svg/ea_emitter.rb +1 -0
- data/lib/ea/svg/parity/source.rb +0 -2
- data/lib/ea/svg/parity/suite.rb +0 -1
- data/lib/ea/transformers/qea_to_xmi/cardinality.rb +40 -28
- data/lib/ea/transformers/qea_to_xmi/context.rb +35 -1
- data/lib/ea/transformers/qea_to_xmi/extension_serializer.rb +686 -0
- data/lib/ea/transformers/qea_to_xmi/guid_format.rb +5 -48
- data/lib/ea/transformers/qea_to_xmi/id_allocator.rb +55 -54
- data/lib/ea/transformers/qea_to_xmi/primitive_types.rb +105 -0
- data/lib/ea/transformers/qea_to_xmi/profile_serializer.rb +163 -0
- data/lib/ea/transformers/qea_to_xmi/run_state.rb +7 -6
- data/lib/ea/transformers/qea_to_xmi/transformer.rb +396 -185
- data/lib/ea/transformers/qea_to_xmi/visibility.rb +30 -19
- data/lib/ea/transformers/qea_to_xmi.rb +5 -2
- data/lib/ea/transformers.rb +7 -2
- data/lib/ea/validation.rb +1 -1
- data/lib/ea/version.rb +1 -1
- data/lib/ea/xmi/liquid_drops/attribute_drop.rb +12 -4
- data/lib/ea/xmi/liquid_drops/klass_drop.rb +1 -2
- data/lib/ea/xmi/lookup_service.rb +4 -0
- data/lib/ea/xmi/parser.rb +30 -1
- data/lib/ea/xml_escape.rb +21 -0
- data/lib/ea.rb +2 -0
- metadata +28 -11
- data/lutaml-uml-0.5.1.gem +0 -0
data/lib/ea/model/ghost_label.rb
CHANGED
data/lib/ea/ocl/evaluator.rb
CHANGED
|
@@ -32,6 +32,8 @@ module Ea
|
|
|
32
32
|
return nil unless context
|
|
33
33
|
|
|
34
34
|
context.public_send(name)
|
|
35
|
+
rescue NoMethodError
|
|
36
|
+
nil
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
def eval_string_matches(ast, context)
|
|
@@ -63,14 +65,14 @@ module Ea
|
|
|
63
65
|
|
|
64
66
|
def eval_size(ast, context)
|
|
65
67
|
collection = evaluate(ast.collection, context)
|
|
66
|
-
return 0 unless collection.
|
|
68
|
+
return 0 unless collection.is_a?(Array)
|
|
67
69
|
|
|
68
70
|
collection.size
|
|
69
71
|
end
|
|
70
72
|
|
|
71
73
|
def eval_is_empty(ast, context)
|
|
72
74
|
collection = evaluate(ast.collection, context)
|
|
73
|
-
return true unless collection.
|
|
75
|
+
return true unless collection.is_a?(Array)
|
|
74
76
|
|
|
75
77
|
collection.empty?
|
|
76
78
|
end
|
data/lib/ea/qea/database.rb
CHANGED
|
@@ -65,6 +65,51 @@ module Ea
|
|
|
65
65
|
documents scripts
|
|
66
66
|
].freeze
|
|
67
67
|
|
|
68
|
+
# Maps EA SQL table names to collection accessor symbols.
|
|
69
|
+
# Centralised here (MECE) so validators and services don't
|
|
70
|
+
# each maintain their own case/when dispatch. Adding a new
|
|
71
|
+
# table = adding one hash entry.
|
|
72
|
+
TABLE_TO_COLLECTION = {
|
|
73
|
+
"t_package" => :packages,
|
|
74
|
+
"t_object" => :objects,
|
|
75
|
+
"t_attribute" => :attributes,
|
|
76
|
+
"t_operation" => :operations,
|
|
77
|
+
"t_operationparams" => :operation_params,
|
|
78
|
+
"t_connector" => :connectors,
|
|
79
|
+
"t_diagram" => :diagrams,
|
|
80
|
+
"t_diagramobjects" => :diagram_objects,
|
|
81
|
+
"t_diagramlinks" => :diagram_links,
|
|
82
|
+
"t_objectconstraint" => :object_constraints,
|
|
83
|
+
"t_objectproperties" => :object_properties,
|
|
84
|
+
"t_taggedvalue" => :tagged_values,
|
|
85
|
+
"t_attributetag" => :attribute_tags,
|
|
86
|
+
"t_xref" => :xrefs,
|
|
87
|
+
"t_stereotypes" => :stereotypes,
|
|
88
|
+
"t_datatypes" => :datatypes,
|
|
89
|
+
"t_constrainttypes" => :constraint_types,
|
|
90
|
+
"t_connectortypes" => :connector_types,
|
|
91
|
+
"t_diagramtypes" => :diagram_types,
|
|
92
|
+
"t_objecttypes" => :object_types,
|
|
93
|
+
"t_statustypes" => :status_types,
|
|
94
|
+
"t_complexitytypes" => :complexity_types,
|
|
95
|
+
"t_documents" => :documents,
|
|
96
|
+
"t_scripts" => :scripts,
|
|
97
|
+
}.freeze
|
|
98
|
+
|
|
99
|
+
# @param table_name [String] EA SQL table name (e.g., "t_object")
|
|
100
|
+
# @return [Array] the collection for that table, or [] if unknown
|
|
101
|
+
def collection_for_table(table_name)
|
|
102
|
+
name = TABLE_TO_COLLECTION[table_name]
|
|
103
|
+
return [] unless name
|
|
104
|
+
|
|
105
|
+
records = @collections[name]
|
|
106
|
+
return [] unless records
|
|
107
|
+
|
|
108
|
+
# t_object is wrapped in ObjectRepository — call .all to
|
|
109
|
+
# get the plain Array that validators expect.
|
|
110
|
+
records.is_a?(Repositories::ObjectRepository) ? records.all : records
|
|
111
|
+
end
|
|
112
|
+
|
|
68
113
|
COLLECTION_ACCESSORS.each do |name|
|
|
69
114
|
define_method(name) do
|
|
70
115
|
@collections[name] || []
|
|
@@ -167,9 +212,19 @@ module Ea
|
|
|
167
212
|
@diagram_links_by_id[id] || []
|
|
168
213
|
end
|
|
169
214
|
|
|
170
|
-
# Find an object by ID
|
|
215
|
+
# Find an object by ID. Uses the repository's primary-key index
|
|
216
|
+
# rather than a scan: the parentid walk in QeaToXmi's
|
|
217
|
+
# `cyclic_ancestry?` calls this once per ancestor hop per object.
|
|
218
|
+
#
|
|
219
|
+
# Hash lookup matches on eql?, so it would miss a Float id that a
|
|
220
|
+
# scan's == would have caught. No caller here can do that:
|
|
221
|
+
# t_object.Object_ID is declared Type::Integer and the model
|
|
222
|
+
# coerces on construction, and every caller passes either such an
|
|
223
|
+
# attribute or an explicit to_i. Deliberately left unguarded — a
|
|
224
|
+
# scan fallback on miss would put every absent-parent lookup in
|
|
225
|
+
# the ancestry walk back on a linear scan.
|
|
171
226
|
def find_object(id)
|
|
172
|
-
objects.
|
|
227
|
+
objects.find(id)
|
|
173
228
|
end
|
|
174
229
|
|
|
175
230
|
# Find object by ea_guid
|
|
@@ -81,23 +81,7 @@ module Ea
|
|
|
81
81
|
const == 1
|
|
82
82
|
end
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
# @return [Boolean]
|
|
86
|
-
def public?
|
|
87
|
-
scope&.downcase == "public"
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
# Check if attribute is private
|
|
91
|
-
# @return [Boolean]
|
|
92
|
-
def private?
|
|
93
|
-
scope&.downcase == "private"
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
# Check if attribute is protected
|
|
97
|
-
# @return [Boolean]
|
|
98
|
-
def protected?
|
|
99
|
-
scope&.downcase == "protected"
|
|
100
|
-
end
|
|
84
|
+
include ScopePredicate
|
|
101
85
|
|
|
102
86
|
# @return [Integer] pos for attribute ordering within parent
|
|
103
87
|
def sort_position
|
|
@@ -119,10 +119,11 @@ module Ea
|
|
|
119
119
|
connector_type == "Aggregation"
|
|
120
120
|
end
|
|
121
121
|
|
|
122
|
-
# Check if connector is a realization
|
|
122
|
+
# Check if connector is a realization. EA writes both the US
|
|
123
|
+
# and UK spellings depending on version/edition.
|
|
123
124
|
# @return [Boolean]
|
|
124
125
|
def realization?
|
|
125
|
-
connector_type
|
|
126
|
+
%w[Realization Realisation].include?(connector_type)
|
|
126
127
|
end
|
|
127
128
|
|
|
128
129
|
# Check if source is aggregate
|
|
@@ -194,17 +194,22 @@ module Ea
|
|
|
194
194
|
# Note — diagram note. Same situation as Text: rendering
|
|
195
195
|
# hint, not a model element. Dropped.
|
|
196
196
|
#
|
|
197
|
+
TRANSFORMER_TYPES = {
|
|
198
|
+
"Enumeration" => :enumeration,
|
|
199
|
+
"DataType" => :data_type,
|
|
200
|
+
"PrimitiveType" => :data_type,
|
|
201
|
+
"Class" => :class,
|
|
202
|
+
"Interface" => :class,
|
|
203
|
+
"Signal" => :signal,
|
|
204
|
+
"Object" => :instance,
|
|
205
|
+
"Association" => :association_element,
|
|
206
|
+
}.freeze
|
|
207
|
+
|
|
197
208
|
# @return [Symbol, nil] Registry key or nil if not a UML model element
|
|
198
209
|
def transformer_type
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
:data_type
|
|
203
|
-
elsif uml_class? || interface?
|
|
204
|
-
:class
|
|
205
|
-
elsif instance?
|
|
206
|
-
:instance
|
|
207
|
-
end
|
|
210
|
+
return :enumeration if stereotype_is?("enumeration")
|
|
211
|
+
|
|
212
|
+
TRANSFORMER_TYPES[object_type]
|
|
208
213
|
end
|
|
209
214
|
|
|
210
215
|
def stereotype_is?(expected)
|
|
@@ -106,23 +106,7 @@ module Ea
|
|
|
106
106
|
styleex&.include?("Reception=1")
|
|
107
107
|
end
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
# @return [Boolean]
|
|
111
|
-
def public?
|
|
112
|
-
scope&.downcase == "public"
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
# Check if operation is private
|
|
116
|
-
# @return [Boolean]
|
|
117
|
-
def private?
|
|
118
|
-
scope&.downcase == "private"
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
# Check if operation is protected
|
|
122
|
-
# @return [Boolean]
|
|
123
|
-
def protected?
|
|
124
|
-
scope&.downcase == "protected"
|
|
125
|
-
end
|
|
109
|
+
include ScopePredicate
|
|
126
110
|
|
|
127
111
|
# @return [Integer] pos for operation ordering within parent
|
|
128
112
|
def sort_position
|
|
@@ -10,6 +10,9 @@ module Ea
|
|
|
10
10
|
attribute :xref_id, Lutaml::Model::Type::String
|
|
11
11
|
attribute :name, Lutaml::Model::Type::String
|
|
12
12
|
attribute :xref_type, Lutaml::Model::Type::String
|
|
13
|
+
attribute :visibility, Lutaml::Model::Type::String
|
|
14
|
+
attribute :behavior, Lutaml::Model::Type::String
|
|
15
|
+
attribute :partition, Lutaml::Model::Type::String
|
|
13
16
|
attribute :client, Lutaml::Model::Type::String
|
|
14
17
|
attribute :supplier, Lutaml::Model::Type::String
|
|
15
18
|
attribute :description, Lutaml::Model::Type::String
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ea
|
|
4
|
+
module Qea
|
|
5
|
+
module Models
|
|
6
|
+
# Mixin providing `public?`, `private?`, `protected?` scope
|
|
7
|
+
# predicates for any model that has a `scope` attribute
|
|
8
|
+
# (t_attribute.scope, t_operation.scope, t_object.scope).
|
|
9
|
+
#
|
|
10
|
+
# EA stores scope as a case-insensitive string ("Public",
|
|
11
|
+
# "Private", "Protected"). This module centralises the
|
|
12
|
+
# comparison so both EaAttribute and EaOperation share one
|
|
13
|
+
# implementation.
|
|
14
|
+
module ScopePredicate
|
|
15
|
+
def public?
|
|
16
|
+
scope&.downcase == "public"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def private?
|
|
20
|
+
scope&.downcase == "private"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def protected?
|
|
24
|
+
scope&.downcase == "protected"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
data/lib/ea/qea/models.rb
CHANGED
|
@@ -6,6 +6,7 @@ module Ea
|
|
|
6
6
|
module Qea
|
|
7
7
|
module Models
|
|
8
8
|
autoload :BaseModel, "ea/qea/models/base_model"
|
|
9
|
+
autoload :ScopePredicate, "ea/qea/models/scope_predicate"
|
|
9
10
|
autoload :EaAttribute, "ea/qea/models/ea_attribute"
|
|
10
11
|
autoload :EaAttributeTag, "ea/qea/models/ea_attribute_tag"
|
|
11
12
|
autoload :EaComplexityType, "ea/qea/models/ea_complexity_type"
|
|
@@ -215,9 +215,12 @@ module Ea
|
|
|
215
215
|
|
|
216
216
|
private
|
|
217
217
|
|
|
218
|
+
# First occurrence wins, matching what a scan would return —
|
|
219
|
+
# `find` and `find_by_key` must not disagree about which record
|
|
220
|
+
# answers for a duplicated key.
|
|
218
221
|
def build_pk_index
|
|
219
222
|
@pk_index = {}
|
|
220
|
-
@records.each { |r| @pk_index[r.primary_key]
|
|
223
|
+
@records.each { |r| @pk_index[r.primary_key] ||= r }
|
|
221
224
|
end
|
|
222
225
|
end
|
|
223
226
|
end
|
|
@@ -128,54 +128,9 @@ module Ea
|
|
|
128
128
|
# Maps table names to their corresponding collections in Database
|
|
129
129
|
#
|
|
130
130
|
# @param table [String] Table name (e.g., "t_package", "t_object")
|
|
131
|
-
# @return [Array
|
|
132
|
-
def get_collection_for_table(table)
|
|
133
|
-
|
|
134
|
-
when "t_package"
|
|
135
|
-
database.packages
|
|
136
|
-
when "t_object"
|
|
137
|
-
database.objects.all
|
|
138
|
-
when "t_attribute"
|
|
139
|
-
database.attributes
|
|
140
|
-
when "t_operation"
|
|
141
|
-
database.operations
|
|
142
|
-
when "t_operationparams"
|
|
143
|
-
database.operation_params
|
|
144
|
-
when "t_connector"
|
|
145
|
-
database.connectors
|
|
146
|
-
when "t_diagram"
|
|
147
|
-
database.diagrams
|
|
148
|
-
when "t_diagramobjects"
|
|
149
|
-
database.diagram_objects
|
|
150
|
-
when "t_diagramlinks"
|
|
151
|
-
database.diagram_links
|
|
152
|
-
when "t_objectconstraint"
|
|
153
|
-
database.object_constraints
|
|
154
|
-
when "t_objectproperties"
|
|
155
|
-
database.object_properties
|
|
156
|
-
when "t_taggedvalue"
|
|
157
|
-
database.tagged_values
|
|
158
|
-
when "t_attributetag"
|
|
159
|
-
database.attribute_tags
|
|
160
|
-
when "t_xref"
|
|
161
|
-
database.xrefs
|
|
162
|
-
when "t_stereotypes"
|
|
163
|
-
database.stereotypes
|
|
164
|
-
when "t_datatypes"
|
|
165
|
-
database.datatypes
|
|
166
|
-
when "t_constrainttypes"
|
|
167
|
-
database.constraint_types
|
|
168
|
-
when "t_connectortypes"
|
|
169
|
-
database.connector_types
|
|
170
|
-
when "t_diagramtypes"
|
|
171
|
-
database.diagram_types
|
|
172
|
-
when "t_objecttypes"
|
|
173
|
-
database.object_types
|
|
174
|
-
when "t_statustypes"
|
|
175
|
-
database.status_types
|
|
176
|
-
when "t_complexitytypes"
|
|
177
|
-
database.complexity_types
|
|
178
|
-
end
|
|
131
|
+
# @return [Array] Collection array or [] if table not mapped
|
|
132
|
+
def get_collection_for_table(table)
|
|
133
|
+
database.collection_for_table(table)
|
|
179
134
|
end
|
|
180
135
|
|
|
181
136
|
# Adds an error to the validation result
|
|
@@ -24,18 +24,30 @@ module Ea
|
|
|
24
24
|
return unless ast
|
|
25
25
|
|
|
26
26
|
if evaluate(ast, owner)
|
|
27
|
-
result.
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
result.add_info(
|
|
28
|
+
category: :ocl_constraint,
|
|
29
|
+
entity_type: :class,
|
|
30
|
+
entity_id: owner.ea_object_id.to_s,
|
|
31
|
+
entity_name: owner.name,
|
|
32
|
+
message: "OCL constraint '#{constraint.constraint_type}' passed",
|
|
33
|
+
)
|
|
30
34
|
else
|
|
31
|
-
result.
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
result.add_warning(
|
|
36
|
+
category: :ocl_constraint,
|
|
37
|
+
entity_type: :class,
|
|
38
|
+
entity_id: owner.ea_object_id.to_s,
|
|
39
|
+
entity_name: owner.name,
|
|
40
|
+
message: "OCL constraint '#{constraint.constraint_type}' failed: #{constraint.constraint}",
|
|
41
|
+
)
|
|
34
42
|
end
|
|
35
43
|
rescue Ea::Ocl::UnsupportedError => e
|
|
36
|
-
result.
|
|
37
|
-
|
|
38
|
-
|
|
44
|
+
result.add_info(
|
|
45
|
+
category: :ocl_constraint,
|
|
46
|
+
entity_type: :class,
|
|
47
|
+
entity_id: owner&.ea_object_id.to_s,
|
|
48
|
+
entity_name: owner&.name,
|
|
49
|
+
message: "Skipping OCL constraint (unsupported syntax): #{e.message}",
|
|
50
|
+
)
|
|
39
51
|
end
|
|
40
52
|
|
|
41
53
|
# Parse the OCL body. Returns nil for empty / non-invariant
|
|
@@ -51,13 +63,11 @@ module Ea
|
|
|
51
63
|
end
|
|
52
64
|
|
|
53
65
|
def owner_for(constraint)
|
|
54
|
-
object_id = constraint.
|
|
55
|
-
constraint.ea_object_id :
|
|
56
|
-
constraint.object_id
|
|
66
|
+
object_id = constraint.ea_object_id
|
|
57
67
|
return nil unless object_id
|
|
58
68
|
|
|
59
69
|
(database.collections[:objects] || [])
|
|
60
|
-
.find { |o| o.
|
|
70
|
+
.find { |o| o.ea_object_id == object_id }
|
|
61
71
|
end
|
|
62
72
|
end
|
|
63
73
|
end
|
|
@@ -17,7 +17,7 @@ module Ea
|
|
|
17
17
|
def from_guid(ea_guid)
|
|
18
18
|
return nil if ea_guid.nil? || ea_guid.empty?
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
Ea::GuidFormat.strip_braces(ea_guid)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
# Convert a GUID to the EAID_ filename format used by EA's
|
|
@@ -26,7 +26,7 @@ module Ea
|
|
|
26
26
|
def to_eaid(ea_guid)
|
|
27
27
|
return nil if ea_guid.nil? || ea_guid.empty?
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
Ea::GuidFormat.ea_guid_to_xmi_id(ea_guid, prefix: "EAID")
|
|
30
30
|
end
|
|
31
31
|
|
|
32
32
|
def synthetic(prefix, *parts)
|
|
@@ -55,12 +55,7 @@ module Ea
|
|
|
55
55
|
private
|
|
56
56
|
|
|
57
57
|
def visibility_marker
|
|
58
|
-
|
|
59
|
-
when "private" then "-"
|
|
60
|
-
when "protected" then "#"
|
|
61
|
-
when "package" then "~"
|
|
62
|
-
else "+"
|
|
63
|
-
end
|
|
58
|
+
VisibilitySymbol.for(property.visibility)
|
|
64
59
|
end
|
|
65
60
|
|
|
66
61
|
# Property name, prefixed with the declaring classifier's
|
|
@@ -55,12 +55,7 @@ module Ea
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def self.visibility_prefix(operation)
|
|
58
|
-
|
|
59
|
-
when "private" then "- "
|
|
60
|
-
when "protected" then "# "
|
|
61
|
-
when "package" then "~ "
|
|
62
|
-
else "+ "
|
|
63
|
-
end
|
|
58
|
+
VisibilitySymbol.for(operation.visibility, with_space: true)
|
|
64
59
|
end
|
|
65
60
|
private_class_method :visibility_prefix
|
|
66
61
|
|
|
@@ -71,7 +66,7 @@ module Ea
|
|
|
71
66
|
|
|
72
67
|
"#{text}: #{operation.return_type_name}"
|
|
73
68
|
end
|
|
74
|
-
|
|
69
|
+
public_class_method :operation_text
|
|
75
70
|
|
|
76
71
|
def self.namespace_double_colon(type_name)
|
|
77
72
|
return "" if type_name.nil? || type_name.empty?
|
|
@@ -185,9 +185,6 @@ module Ea
|
|
|
185
185
|
# alphabetical "+ Name" rows in the body compartment, but
|
|
186
186
|
# only when the diagram's t_diagram.ShowPackageContents flag
|
|
187
187
|
# is non-zero. Returns [] when the diagram suppresses
|
|
188
|
-
# package contents or the model element isn't a Package.
|
|
189
|
-
# Each entry is a Struct(name:, kind:) so the renderer can
|
|
190
|
-
# pick the correct per-type icon (Enumeration vs default).
|
|
191
188
|
def package_content_lines_for(model_element)
|
|
192
189
|
return [] unless model_element.is_a?(Ea::Model::Package)
|
|
193
190
|
return [] unless diagram.show_package_contents
|
|
@@ -199,6 +196,7 @@ module Ea
|
|
|
199
196
|
PackageContentRow.new(name: c.name.to_s, kind: row_icon_kind(c))
|
|
200
197
|
end
|
|
201
198
|
end
|
|
199
|
+
public :package_content_lines_for
|
|
202
200
|
|
|
203
201
|
def package_children(package)
|
|
204
202
|
return [] unless model_index
|
|
@@ -236,12 +236,7 @@ module Ea
|
|
|
236
236
|
end
|
|
237
237
|
|
|
238
238
|
def visibility_prefix(property)
|
|
239
|
-
|
|
240
|
-
when "private" then "-"
|
|
241
|
-
when "protected" then "#"
|
|
242
|
-
when "package" then "~"
|
|
243
|
-
else "+"
|
|
244
|
-
end
|
|
239
|
+
VisibilitySymbol.for(property.visibility)
|
|
245
240
|
end
|
|
246
241
|
|
|
247
242
|
def text_at(x, y, content)
|
|
@@ -62,7 +62,7 @@ module Ea
|
|
|
62
62
|
# Backwards-compatible API: count of marker bodies emitted.
|
|
63
63
|
def count_for(connector)
|
|
64
64
|
return 0 if connector.hidden
|
|
65
|
-
return 0 unless connector.waypoints&.any?
|
|
65
|
+
return 0 unless connector.waypoints&.any?(&:position)
|
|
66
66
|
|
|
67
67
|
entries_for(connector).size
|
|
68
68
|
end
|
|
@@ -85,15 +85,51 @@ module Ea
|
|
|
85
85
|
end
|
|
86
86
|
end
|
|
87
87
|
|
|
88
|
+
# OCP registries for marker shapes. Adding a new marker shape
|
|
89
|
+
# = adding one entry to SHAPE_REGISTRY, not editing 3 case/when
|
|
90
|
+
# branches. Each entry carries the style_key and a render
|
|
91
|
+
# lambda that knows how to draw the shape.
|
|
92
|
+
#
|
|
93
|
+
# Style keys (:diamond_filled, :triangle_open, :connector_line)
|
|
94
|
+
# map to CSS strings via STYLE_MAP below.
|
|
95
|
+
SHAPE_REGISTRY = {
|
|
96
|
+
diamond: {
|
|
97
|
+
style_key: :diamond_filled,
|
|
98
|
+
render: ->(m, anchor, base) { m.diamond_polygon(anchor, base) }
|
|
99
|
+
},
|
|
100
|
+
triangle: {
|
|
101
|
+
style_key: :triangle_open,
|
|
102
|
+
render: ->(m, anchor, base) { m.triangle_polygon(anchor, base) }
|
|
103
|
+
},
|
|
104
|
+
plus: {
|
|
105
|
+
style_key: :connector_line,
|
|
106
|
+
render: ->(m, anchor, _base) { m.plus_path(anchor) }
|
|
107
|
+
},
|
|
108
|
+
arrow: {
|
|
109
|
+
style_key: :connector_line,
|
|
110
|
+
render: ->(m, anchor, base) { m.arrow_path(anchor, base) }
|
|
111
|
+
},
|
|
112
|
+
package_anchor: {
|
|
113
|
+
style_key: :connector_line,
|
|
114
|
+
render: ->(m, anchor, base) { m.package_anchor_path(anchor, base) }
|
|
115
|
+
}
|
|
116
|
+
}.freeze
|
|
117
|
+
|
|
118
|
+
# Style key → (fill, opacity) pair. The common stroke prefix
|
|
119
|
+
# is shared, so only the fill and opacity vary.
|
|
120
|
+
STYLE_MAP = {
|
|
121
|
+
diamond_filled: { fill: "#000000", opacity: "1.00" },
|
|
122
|
+
triangle_open: { fill: "#FFFFFF", opacity: "1.00" },
|
|
123
|
+
connector_line: { fill: "#000000", opacity: "0.00" }
|
|
124
|
+
}.freeze
|
|
125
|
+
|
|
88
126
|
def style_for(key)
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
"
|
|
94
|
-
|
|
95
|
-
"stroke-width:#{stroke_width};stroke-linecap:round;stroke-linejoin:bevel; fill:#000000;fill-opacity:0.00; stroke:#000000; stroke-opacity:1.00"
|
|
96
|
-
end
|
|
127
|
+
spec = STYLE_MAP[key]
|
|
128
|
+
return nil unless spec
|
|
129
|
+
|
|
130
|
+
"stroke-width:#{stroke_width};stroke-linecap:round;stroke-linejoin:bevel; " \
|
|
131
|
+
"fill:#{spec[:fill]};fill-opacity:#{spec[:opacity]}; " \
|
|
132
|
+
"stroke:#000000; stroke-opacity:1.00"
|
|
97
133
|
end
|
|
98
134
|
|
|
99
135
|
def visible_connectors
|
|
@@ -210,13 +246,7 @@ module Ea
|
|
|
210
246
|
end
|
|
211
247
|
|
|
212
248
|
def style_key_for(spec)
|
|
213
|
-
|
|
214
|
-
when :diamond then :diamond_filled
|
|
215
|
-
when :triangle then :triangle_open
|
|
216
|
-
when :plus then :connector_line # shares style with line <g>
|
|
217
|
-
when :arrow then :connector_line # share with line <g>
|
|
218
|
-
when :package_anchor then :connector_line
|
|
219
|
-
end
|
|
249
|
+
SHAPE_REGISTRY.dig(spec.shape, :style_key)
|
|
220
250
|
end
|
|
221
251
|
|
|
222
252
|
# Rounded [x, y] of the marker's tip (anchor) in canvas
|
|
@@ -227,13 +257,10 @@ module Ea
|
|
|
227
257
|
end
|
|
228
258
|
|
|
229
259
|
def render_shape(spec)
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
when :arrow then arrow_path(spec.anchor, spec.base)
|
|
235
|
-
when :package_anchor then package_anchor_path(spec.anchor, spec.base)
|
|
236
|
-
end
|
|
260
|
+
entry = SHAPE_REGISTRY[spec.shape]
|
|
261
|
+
return nil unless entry
|
|
262
|
+
|
|
263
|
+
entry[:render].call(self, spec.anchor, spec.base)
|
|
237
264
|
end
|
|
238
265
|
|
|
239
266
|
# Plus marker: two crossed line segments at the anchor.
|
|
@@ -384,6 +411,8 @@ module Ea
|
|
|
384
411
|
|
|
385
412
|
[dx / len, dy / len]
|
|
386
413
|
end
|
|
414
|
+
public :diamond_polygon, :triangle_polygon, :plus_path,
|
|
415
|
+
:arrow_path, :package_anchor_path
|
|
387
416
|
|
|
388
417
|
def translate_point(p)
|
|
389
418
|
return p unless @canvas
|