ea 0.5.1 → 0.5.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8649c4d58ca59e1a753bf7b4c1400e14ac7026e1142e914a4025dfd09a2e5bb1
4
- data.tar.gz: 170d39d2601ea16f0dd171c7ab51906b4bbe0baf5c973eaffdfc02df2e27ab59
3
+ metadata.gz: feec20be82e181c35e21063e8faaefc697c466aeb96ea462a1e1911e20656863
4
+ data.tar.gz: a15bbc9f5d6f078d712f436584175ad4901bad1b2918c9d6f163de1be64b0c21
5
5
  SHA512:
6
- metadata.gz: f7bd4ceb020497b93a2c9c9e0c60d3aa57a0cbb664803f4609a7ec82b2129649496bca45000b2ec91ba1c07a9254b1382bce67411f9f35b5d41dcaebe22590ff
7
- data.tar.gz: ed3b011237a1a76a85ac1af8315afcfd9250b97396fbbcefe15f0491adbe1a51a1944abd7ba9ec513b0011c2461c4ff3c7bb5be20dfa58156cc93e3698c39d44
6
+ metadata.gz: 9c0ea25f28a1e8dfe0b7d923deb5340f3da3d3aefd8f95b284e80b3de6126756dba1dc96563113b3c64a918c7962fd351361a84f3afc066f304479847625ac7e
7
+ data.tar.gz: 0d68e3d7eea42bcc0d8008c84d5a69d58f94702981659174aa18f6ad7f67bcb07554e054e795aa7fde3716d63597ec71ee1e6148f187935d5c141c9cb2e94835
@@ -0,0 +1,30 @@
1
+ # TODO.complete/64: QeaToXmi emits connector elements
2
+
3
+ ## Status: open
4
+
5
+ `Ea::Transformers::QeaToXmi` emits associations as `<memberEnd>` +
6
+ `<ownedEnd>` on the owning class, but does NOT emit EA's
7
+ `<connector>` elements. Per the parity regression spec, that's the
8
+ #1 missing category (73/73 in basic.qea, 73/80 in plateau).
9
+
10
+ ## Plan
11
+
12
+ 1. After serializing the model root + classes, walk `t_connector`
13
+ for associations/aggregations/compositions.
14
+ 2. For each connector, locate the corresponding `t_diagramlinks` row
15
+ to retrieve geometry (SX/SY/EX/EY/EDGE) and visual style
16
+ (lineStyle/lineColor).
17
+ 3. Emit `<connector>` element with geometry in `<style>` sub-element.
18
+
19
+ ## Acceptance
20
+
21
+ - `ea export xmi` output for basic.qea now contains
22
+ `<connector>` elements (was 0/73).
23
+ - `spec/ea/validation/xmi_parity_spec.rb` packagedElement threshold
24
+ raised from 5% to 25% (connectors represent ~25% of EA's output).
25
+
26
+ ## OCP
27
+
28
+ Each connector type (Association/Aggregation/Composition) gets a
29
+ private serializer method dispatched by `connector_type`. New
30
+ connector types = new case branch; no other code changes.
@@ -0,0 +1,29 @@
1
+ # TODO.complete/65: QeaToXmi emits diagram elements
2
+
3
+ ## Status: open
4
+
5
+ `Ea::Transformers::QeaToXmi` does not emit EA's `<diagram>` elements
6
+ at all. The parity spec confirms 0/23 in basic.qea, 0/2 in test.qea.
7
+
8
+ ## Plan
9
+
10
+ 1. Walk `t_diagram` for every diagram.
11
+ 2. For each diagram, walk `t_diagramlinks` to find placed
12
+ elements + connectors; emit them as `<element>` children of
13
+ `<diagram>`.
14
+ 3. Each element child references its `xmi:idref` to the model
15
+ class.
16
+ 4. Connector children emit as `<connector>` with geometry (see
17
+ TODO 64).
18
+
19
+ ## Acceptance
20
+
21
+ - `ea export xmi` output for basic.qea now contains
22
+ `<diagram>` elements (was 0/23).
23
+ - Parity threshold raised from 25% to 50%.
24
+
25
+ ## OCP
26
+
27
+ Diagrams emit via a new private method `emit_diagrams(model)`
28
+ called after the model class tree. Adding new diagram metadata
29
+ (swimlane info, etc.) = new private method, no other changes.
@@ -0,0 +1,28 @@
1
+ # TODO.complete/66: QeaToXmi emits style / tags / documentation
2
+
3
+ ## Status: open
4
+
5
+ EA's reference XMI contains hundreds of `<style>`, `<tags>`, and
6
+ `<documentation>` elements per diagram. Ours emits zero. Per the
7
+ parity spec: 0/663 styles, 0/478 tags, 0/357 documentation entries.
8
+
9
+ ## Plan
10
+
11
+ 1. Walk `t_diagramlinks` to find connector+element style strings.
12
+ 2. Emit `<style>` children of `<connector>` / `<element>` with the
13
+ stored style XML verbatim.
14
+ 3. Walk `t_taggedvalue` for tagged values; emit as `<tags>` children
15
+ with `<tag>` items.
16
+ 4. Walk `t_objectnotes` for documentation; emit as `<documentation>`
17
+ children of the owning element.
18
+
19
+ ## Acceptance
20
+
21
+ - Output contains `<style>`, `<tags>`, `<documentation>` elements.
22
+ - Parity threshold raised from 50% to 75%.
23
+
24
+ ## OCP
25
+
26
+ Each sub-element type (style/tags/documentation) is a private
27
+ emitter method dispatched by collection. New element types = new
28
+ case branch.
@@ -0,0 +1,20 @@
1
+ # TODO.complete/67: OCL collection operations
2
+
3
+ ## Status: open
4
+
5
+ `Ea::Ocl` evaluates a subset of OCL: `exists`, `forAll`, `matches`,
6
+ `and`/`or`/`not`, attribute access. Real EA constraints use
7
+ `size()` and `isEmpty()` (parity: 0/0 because the OCL evaluator
8
+ wasn't even invoked before this session).
9
+
10
+ ## Plan
11
+
12
+ 1. Add `CollectionSize` AST node: `<collection>->size()`.
13
+ 2. Add `CollectionIsEmpty` AST node: `<collection>->isEmpty()`.
14
+ 3. Parser recognizes `->size` and `->isEmpty` patterns.
15
+ 4. Evaluator returns integer / boolean.
16
+
17
+ ## Acceptance
18
+
19
+ - Spec: `inv: self.items->size() > 0` parses + evaluates.
20
+ - Spec: `inv: self.items->isEmpty() or self.required` parses + evaluates.
@@ -0,0 +1,19 @@
1
+ # TODO.complete/68: OCL comparison operators
2
+
3
+ ## Status: open
4
+
5
+ `Ea::Ocl` supports `=`/`==` via equality, but not ordering: `>`,
6
+ `<`, `>=`, `<=`. These appear in real OCL invariants.
7
+
8
+ ## Plan
9
+
10
+ 1. Add `Comparison` AST node: `left op right` where op is one of
11
+ `>`, `<`, `>=`, `<=`.
12
+ 2. Parser recognizes the operators.
13
+ 3. Evaluator compares numeric operands; raises `UnsupportedError` on
14
+ non-numeric.
15
+
16
+ ## Acceptance
17
+
18
+ - Spec: `inv: self.age >= 18` parses + evaluates (true / false).
19
+ - Spec: `inv: self.count < self.max` parses + evaluates.
@@ -0,0 +1,25 @@
1
+ # TODO.complete/69: Specs for newly-added QEA models
2
+
3
+ ## Status: open
4
+
5
+ The following models were added in TODO 44 / TODO 7 sessions but
6
+ have no spec coverage: `EaSecrypt`, `EaPalette`, `EaPaletteItem`,
7
+ `EaImplement`, `EaRoleConstraint`, `EaObjectProblem`, `EaObjectRisk`,
8
+ `EaObjectTest`, `EaObjectEffort`, `EaObjectResource`,
9
+ `EaObjectScenario`, `EaObjectRequire`, `EaObjectTrx`.
10
+
11
+ Without specs, regressions in column mapping or primary key logic
12
+ go undetected.
13
+
14
+ ## Plan
15
+
16
+ 1. Single consolidated spec file: `spec/ea/qea/models/
17
+ auxiliary_models_spec.rb`.
18
+ 2. Per-model `it "loads primary key and columns"` block.
19
+ 3. Verifies `primary_key_column` is correct.
20
+ 4. Verifies `column_map` translates known column names to symbols.
21
+
22
+ ## Acceptance
23
+
24
+ - File exists, all 13 models have at least 1 example.
25
+ - `bundle exec rspec` passes with 0 failures.
@@ -48,7 +48,7 @@ module Ea
48
48
 
49
49
  def qea_to_xmi_xml
50
50
  database = load_database(file_path)
51
- Ea::Transformers.qea_to_xmi(database)
51
+ Ea::Transformers.qea_to_xmi(database, with_extensions: false)
52
52
  ensure
53
53
  database&.close_connection
54
54
  end
@@ -17,6 +17,9 @@ module Ea
17
17
  when Nodes::StringMatches then eval_string_matches(ast, context)
18
18
  when Nodes::CollectionExists then eval_exists(ast, context)
19
19
  when Nodes::CollectionForAll then eval_for_all(ast, context)
20
+ when Nodes::CollectionSize then eval_size(ast, context)
21
+ when Nodes::CollectionIsEmpty then eval_is_empty(ast, context)
22
+ when Nodes::Comparison then eval_comparison(ast, context)
20
23
  when Nodes::BinaryOp then eval_binary(ast, context)
21
24
  when Nodes::UnaryOp then eval_unary(ast, context)
22
25
  else
@@ -58,6 +61,40 @@ module Ea
58
61
  end
59
62
  end
60
63
 
64
+ def eval_size(ast, context)
65
+ collection = evaluate(ast.collection, context)
66
+ return 0 unless collection.respond_to?(:size)
67
+
68
+ collection.size
69
+ end
70
+
71
+ def eval_is_empty(ast, context)
72
+ collection = evaluate(ast.collection, context)
73
+ return true unless collection.respond_to?(:empty?)
74
+
75
+ collection.empty?
76
+ end
77
+
78
+ def eval_comparison(ast, context)
79
+ left = evaluate(ast.left, context)
80
+ right = evaluate(ast.right, context)
81
+ unless left.is_a?(Numeric) && right.is_a?(Numeric)
82
+ raise UnsupportedError,
83
+ "Comparison requires numeric operands: #{ast.op} on #{left.inspect}, #{right.inspect}"
84
+ end
85
+
86
+ case ast.op
87
+ when ">" then left > right
88
+ when "<" then left < right
89
+ when ">=" then left >= right
90
+ when "<=" then left <= right
91
+ when "=" then left == right
92
+ when "==" then left == right
93
+ when "!=" then left != right
94
+ else raise UnsupportedError, "Unknown comparison op: #{ast.op}"
95
+ end
96
+ end
97
+
61
98
  def eval_binary(ast, context)
62
99
  left = evaluate(ast.left, context)
63
100
  right = evaluate(ast.right, context)
data/lib/ea/ocl/nodes.rb CHANGED
@@ -25,6 +25,15 @@ module Ea
25
25
  # `<a> and <b>`, `<a> or <b>`, `not <a>`
26
26
  BinaryOp = Struct.new(:op, :left, :right, keyword_init: true)
27
27
  UnaryOp = Struct.new(:op, :operand, keyword_init: true)
28
+
29
+ # `<collection>->size()` — returns integer cardinality.
30
+ CollectionSize = Struct.new(:collection, keyword_init: true)
31
+
32
+ # `<collection>->isEmpty()` — returns boolean.
33
+ CollectionIsEmpty = Struct.new(:collection, keyword_init: true)
34
+
35
+ # `<a> op <b>` where op ∈ {>, <, >=, <=, =, ==, !=}.
36
+ Comparison = Struct.new(:op, :left, :right, keyword_init: true)
28
37
  end
29
38
  end
30
39
  end
data/lib/ea/ocl/parser.rb CHANGED
@@ -33,7 +33,7 @@ module Ea
33
33
  end
34
34
 
35
35
  # Parse one expression. Returns a single AST node.
36
- def parse_expression(source)
36
+ def parse_expression(source) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
37
37
  s = source.strip
38
38
 
39
39
  # Strip outer parens
@@ -45,7 +45,14 @@ module Ea
45
45
  operand: parse_expression(s[4..]))
46
46
  end
47
47
 
48
- # 'and' / 'or' at top level (find the operator not inside parens)
48
+ # 'and' / 'or' / comparison ops comparison has higher
49
+ # precedence than logical, so check it first.
50
+ if (split = split_on_comparison_op(s))
51
+ op, left, right = split
52
+ return Nodes::Comparison.new(op: op,
53
+ left: parse_expression(left),
54
+ right: parse_expression(right))
55
+ end
49
56
  if (split = split_on_logical_op(s))
50
57
  op, left, right = split
51
58
  return Nodes::BinaryOp.new(op: op,
@@ -58,6 +65,16 @@ module Ea
58
65
  return collection_node(m[2].to_sym, m[1], m[3], m[4])
59
66
  end
60
67
 
68
+ # Collection ->size() — integer cardinality
69
+ if (m = s.match(/^(.+?)->size\(\)\z/))
70
+ return Nodes::CollectionSize.new(collection: parse_expression(m[1]))
71
+ end
72
+
73
+ # Collection ->isEmpty() — boolean
74
+ if (m = s.match(/^(.+?)->isEmpty\(\)\z/))
75
+ return Nodes::CollectionIsEmpty.new(collection: parse_expression(m[1]))
76
+ end
77
+
61
78
  # String.matches('regex')
62
79
  if (m = s.match(/^(.+?)\.matches\(\s*['"](.+?)['"]\s*\)\z/))
63
80
  return Nodes::StringMatches.new(string: parse_expression(m[1]),
@@ -99,7 +116,6 @@ module Ea
99
116
  # Find the topmost ` and ` or ` or ` outside of parens.
100
117
  # Returns [op, left_str, right_str] or nil.
101
118
  def split_on_logical_op(source)
102
- depth = 0
103
119
  # Look for ' or ' first (lower precedence than 'and' in OCL?)
104
120
  # Actually OCL: 'or' < 'xor' < 'and' < 'implies'. We pick the
105
121
  # rightmost top-level operator (left-associative).
@@ -113,6 +129,45 @@ module Ea
113
129
  nil
114
130
  end
115
131
 
132
+ # Split on top-level comparison operator (>, <, >=, <=, =, ==, !=).
133
+ # Comparison has higher precedence than and/or, so we split here
134
+ # BEFORE calling split_on_logical_op.
135
+ def split_on_comparison_op(source)
136
+ %w[>= <= == != = > <].each do |op|
137
+ # Need to be careful with `>=` vs `>`: scan in order so
138
+ # multi-char operators are detected first.
139
+ idx = find_top_level_op(source, op)
140
+ next unless idx
141
+
142
+ return [op, source[0...idx], source[(idx + op.length)..]]
143
+ end
144
+ nil
145
+ end
146
+
147
+ def find_top_level_op(source, op) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
148
+ depth = 0
149
+ i = 0
150
+ while i < source.length
151
+ c = source[i]
152
+ depth += 1 if c == "("
153
+ depth -= 1 if c == ")"
154
+ if depth.zero? && source[i, op.length] == op
155
+ # Each `next` clause below MUST fall through to `i += 1`
156
+ # at the loop's tail — using `next` here would skip the
157
+ # increment and infinite-loop on the same matching char.
158
+ should_skip =
159
+ (op == ">" && source[i + 1, 1] == "=") || # >= matches as >
160
+ (op == "<" && source[i + 1, 1] == "=") || # <= matches as <
161
+ (op == "=" && source[i + 1, 1] == "=") || # == matches as =
162
+ (op == ">" && source[i - 1, 1] == "-") || # -> arrow
163
+ (op == "<" && source[i - 1, 1] == "-") # <- arrow
164
+ return i unless should_skip
165
+ end
166
+ i += 1
167
+ end
168
+ nil
169
+ end
170
+
116
171
  # Find substring at depth 0 (not inside parens).
117
172
  def find_top_level(source, substring)
118
173
  depth = 0
@@ -121,9 +176,8 @@ module Ea
121
176
  c = source[i]
122
177
  depth += 1 if c == "("
123
178
  depth -= 1 if c == ")"
124
- if depth.zero? && source[i, substring.length] == substring
125
- return i
126
- end
179
+ return i if depth.zero? && source[i, substring.length] == substring
180
+
127
181
  i += 1
128
182
  end
129
183
  nil
@@ -70,8 +70,144 @@ module Ea
70
70
  # nil-valued attributes are skipped at the source. No
71
71
  # post-processing pass is needed — the prior XmlSanitizer
72
72
  # workaround (TODO 21 §1) has been removed.
73
- def serialize
74
- build_root.to_xml(use_prefix: true)
73
+ # Serialize to XMI XML.
74
+ #
75
+ # Default produces model tree only (parseable by the xmi gem's
76
+ # Sparx parser for round-trip). Pass `with_extensions: true` to
77
+ # also emit EA-specific `<connectors>` and `<diagrams>` sections
78
+ # inside `<xmi:Extension>`. Those use post-processing string
79
+ # injection that the xmi gem's parser doesn't model, so the
80
+ # output is NOT round-trippable when extensions are included.
81
+ #
82
+ # @param with_extensions [Boolean]
83
+ # @return [String] XMI XML
84
+ def serialize(with_extensions: true)
85
+ xml = build_root.to_xml(use_prefix: true)
86
+ with_extensions ? inject_extension_content(xml) : xml
87
+ end
88
+
89
+ # Injects EA-specific extension content (connectors, diagrams)
90
+ # into the serialized XMI. The xmi gem's Extension type is
91
+ # modeled but doesn't declare `connectors` / `diagrams`
92
+ # children. We post-process the serialized XML to insert
93
+ # them inside the existing `<xmi:Extension>` element.
94
+ def inject_extension_content(xml)
95
+ content = extension_inner_xml
96
+ return xml if content.empty?
97
+
98
+ # Replace the empty `<xmi:Extension .../>` or the
99
+ # closing `</xmi:Extension>` with the populated version.
100
+ if xml.include?("<xmi:Extension")
101
+ xml.sub(%r{<xmi:Extension ([^>]+)>\s*</xmi:Extension>},
102
+ "<xmi:Extension \\1>\n#{content}\n\t</xmi:Extension>")
103
+ .sub(/<xmi:Extension ([^>]+)\/>/,
104
+ "<xmi:Extension \\1>\n#{content}\n\t</xmi:Extension>")
105
+ else
106
+ xml
107
+ end
108
+ end
109
+
110
+ # @return [String] XML for the inner content of <xmi:Extension>:
111
+ # <elements>...</elements>, <connectors>...</connectors>,
112
+ # <diagrams>...</diagrams>. Empty when none apply.
113
+ def extension_inner_xml
114
+ parts = []
115
+ connectors_xml = build_connectors_extension
116
+ parts << connectors_xml unless connectors_xml.empty?
117
+ diagrams_xml = build_diagrams_extension
118
+ parts << diagrams_xml unless diagrams_xml.empty?
119
+ parts.join("\n")
120
+ end
121
+
122
+ def build_connectors_extension
123
+ connectors = @database.collections[:connectors] || []
124
+ return "" if connectors.empty?
125
+
126
+ inner = connectors.map { |conn| connector_xml(conn) }.compact.join("\n")
127
+ return "" if inner.empty?
128
+
129
+ "\t\t<connectors>\n#{inner}\n\t\t</connectors>"
130
+ end
131
+
132
+ def build_diagrams_extension
133
+ diagrams = @database.collections[:diagrams] || []
134
+ return "" if diagrams.empty?
135
+
136
+ inner = diagrams.map { |dgm| diagram_xml(dgm) }.compact.join("\n")
137
+ return "" if inner.empty?
138
+
139
+ "\t\t<diagrams>\n#{inner}\n\t\t</diagrams>"
140
+ end
141
+
142
+ # Per-connector XML with xmi:idref to the model-level
143
+ # association (when present) plus source/target references.
144
+ def connector_xml(conn)
145
+ return nil unless conn.ea_guid
146
+
147
+ connector_id = "EAID_#{guid_to_xmi_id(conn.ea_guid)}"
148
+ source_obj = @database.collections[:objects]&.find { |o| o.ea_object_id == conn.start_object_id }
149
+ target_obj = @database.collections[:objects]&.find { |o| o.ea_object_id == conn.end_object_id }
150
+ return nil unless source_obj && target_obj
151
+
152
+ name_attr = conn.name ? %( name="#{escape(conn.name)}") : ""
153
+ inner = source_end_xml(conn, source_obj) + target_end_xml(conn, target_obj)
154
+ %(<connector xmi:idref="#{connector_id}"#{name_attr}>\n#{inner}\t\t</connector>)
155
+ end
156
+
157
+ def source_end_xml(conn, source_obj)
158
+ end_xml(source_obj, "source")
159
+ end
160
+
161
+ def target_end_xml(conn, target_obj)
162
+ end_xml(target_obj, "target")
163
+ end
164
+
165
+ def end_xml(obj, kind)
166
+ xmi_id = "EAID_#{guid_to_xmi_id(obj.ea_guid)}"
167
+ lines = [
168
+ "\t\t\t<#{kind} xmi:idref=\"#{xmi_id}\">",
169
+ "\t\t\t\t<model ea_localid=\"#{obj.ea_object_id}\" " \
170
+ "type=\"#{obj.object_type}\" name=\"#{escape(obj.name.to_s)}\"/>",
171
+ "\t\t\t\t<role visibility=\"Public\" targetScope=\"instance\"/>",
172
+ "\t\t\t</#{kind}>"
173
+ ]
174
+ lines.join("\n") + "\n"
175
+ end
176
+
177
+ def diagram_xml(dgm)
178
+ return nil unless dgm.ea_guid
179
+
180
+ diagram_id = "EAID_#{guid_to_xmi_id(dgm.ea_guid)}"
181
+ pkg_guid = package_guid_for(dgm)
182
+ pkg_ref = pkg_guid ? "EAPK_#{guid_to_xmi_id(pkg_guid)}" : ""
183
+ lines = [
184
+ "<diagram xmi:id=\"#{diagram_id}\">",
185
+ "\t\t\t<model package=\"#{pkg_ref}\" localID=\"#{dgm.diagram_id}\" owner=\"#{pkg_ref}\"/>",
186
+ "\t\t\t<properties name=\"#{escape(dgm.name.to_s)}\" type=\"#{escape(dgm.diagram_type.to_s)}\"/>",
187
+ "\t\t</diagram>"
188
+ ]
189
+ lines.join("\n")
190
+ end
191
+
192
+ def package_guid_for(dgm)
193
+ pkg = (@database.collections[:packages] || []).find { |p| p.package_id == dgm.package_id }
194
+ pkg&.ea_guid || dgm.ea_guid
195
+ end
196
+
197
+ def guid_to_xmi_id(guid)
198
+ return "" unless guid
199
+
200
+ guid.to_s.gsub(/[{}]/, "")
201
+ .tr("-", "_")
202
+ .prepend("EA") # truncated below
203
+ .sub(/\AEA/, "")
204
+ end
205
+
206
+ def escape(text)
207
+ text.to_s.gsub("&", "&amp;")
208
+ .gsub("<", "&lt;")
209
+ .gsub(">", "&gt;")
210
+ .gsub('"', "&quot;")
75
211
  end
76
212
 
77
213
  private
@@ -25,9 +25,10 @@ module Ea
25
25
  # Sparx-specific concepts (stereotypes, tagged values, multiplicities,
26
26
  # diagrams, xrefs).
27
27
  # @param database [Ea::Qea::Database]
28
+ # @param with_extensions [Boolean] emit EA-specific connectors+diagrams
28
29
  # @return [String] XMI XML
29
- def qea_to_xmi(database)
30
- QeaToXmi::Transformer.new(database).serialize
30
+ def qea_to_xmi(database, with_extensions: true)
31
+ QeaToXmi::Transformer.new(database).serialize(with_extensions: with_extensions)
31
32
  end
32
33
  end
33
34
  end
data/lib/ea/version.rb CHANGED
@@ -4,5 +4,5 @@ module Ea
4
4
  # Gem release version. Extracted to its own file so the
5
5
  # `gem-release` tool's `gem bump` can find and update it via the
6
6
  # standard `lib/<gem>/version.rb` convention.
7
- VERSION = "0.5.1"
7
+ VERSION = "0.5.2"
8
8
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -236,6 +236,12 @@ files:
236
236
  - TODO.complete/61-plantuml-relationships.md
237
237
  - TODO.complete/62-changelog.md
238
238
  - TODO.complete/63-dependabot-fix.md
239
+ - TODO.complete/64-qeatoxmi-connectors.md
240
+ - TODO.complete/65-qeatoxmi-diagrams.md
241
+ - TODO.complete/66-qeatoxmi-style-tags-docs.md
242
+ - TODO.complete/67-ocl-collection-ops.md
243
+ - TODO.complete/68-ocl-comparison-ops.md
244
+ - TODO.complete/69-spec-new-models.md
239
245
  - TODO.complete/STATUS.md
240
246
  - TODO.diagrams/01-svg-measurement-harness.md
241
247
  - TODO.diagrams/01-xmi-extension-elements-parsing.md