ea 0.6.19 → 0.6.21

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: 93444f7054362eb7eacaee52caf7a5be9896fde1f3c2a9ef19e2850abb990a9d
4
- data.tar.gz: 9c224144cc0899efc1f8bb9c41f53d1fdf19104083f658915314cf609cf7d062
3
+ metadata.gz: 548d074902dd1fa399222eecf7bce3890790951fdd62f8d1d5e4c054e602e680
4
+ data.tar.gz: 95bc0204957914b6451a505b29adb96d8ad4906229b488406d3cb1b2efcc6f53
5
5
  SHA512:
6
- metadata.gz: 39ffbc27aab19937893283c206ea1409b639357f0a27138b70b9f6c9d1ad8ac149cb5fc911f5ac39afb03b0f1a0d8ee1cb345d38bf02469f22c0460d1975e547
7
- data.tar.gz: 358e559f41b84f168c08008e598b858248a4d0b627c38b2f1771dde340790b565c54efe2874492830dac6f8395cd315cb745ae0081822977ba9f4b28481c302c
6
+ metadata.gz: 71b2b781fbfdc1839b5211aa3d193be4b7daa035fbfa6b1947d8339d71acb8075a80aede566df22cd0709029904be2508203bd726811a27dd9d9be74fd5c2a99
7
+ data.tar.gz: 4844d29466fe899fcb10900455dcfcc5f2aecf6f7d77ab25243a78f7ef61f9d85e64db4a1d0432aa13f39d473c38f7452b3738aeb95917dacadc994b747222c4
@@ -4,9 +4,12 @@ module Ea
4
4
  module Svg
5
5
  module EaEmitter
6
6
  module Compartment
7
- # Constraints compartment. Skipped when the classifier has no
8
- # constraints. Renders an italic "constraints" header and one
9
- # "{name}" line per constraint.
7
+ # Real (OCL) constraints compartment. Skipped when the
8
+ # classifier has no constraints — the {root}/{leaf} marker
9
+ # renders in its own Marker compartment between the divider
10
+ # and the attributes. EA seats OCL constraint lines after the
11
+ # content and suppresses them when they would overflow the
12
+ # stored box height (never truncates rows).
10
13
  module Constraints
11
14
  DEFAULT_TEXT_COLOR = "#000000"
12
15
 
@@ -16,10 +19,15 @@ module Ea
16
19
  return nil unless context.constraints&.any?
17
20
  return nil unless context.geometry.tagged_value_first_y
18
21
 
22
+ first_y = context.geometry.tagged_value_first_y
23
+ line_h = context.size + 6
24
+ last_y = first_y + (context.constraints.size - 1) * line_h
25
+ return nil if last_y + 4 > context.bounds.y + context.bounds.height
26
+
19
27
  Element::ConstraintRenderer.render(
20
28
  context.constraints,
21
29
  bounds: context.bounds,
22
- first_y: context.geometry.tagged_value_first_y,
30
+ first_y: first_y,
23
31
  family: context.family, size: context.size,
24
32
  fill: DEFAULT_TEXT_COLOR
25
33
  )
@@ -25,14 +25,48 @@ module Ea
25
25
  def render_literals_block(context)
26
26
  line_h = context.size + LITERAL_LINE_OFFSET
27
27
  text_blocks = []
28
+ row_y = context.geometry.enum_literal_first_y
29
+ # EA renders a centered italic "literals" caption above
30
+ # the rows when the literals carry stored code values
31
+ # (t_attribute.Default); bare literal lists render the
32
+ # rows directly. Corpus-verified (PT_TypeOfSA:
33
+ # "literals" caption + "ServingParcel = SP" rows;
34
+ # CV_SequenceType: bare rows, no caption).
35
+ if caption?(context)
36
+ text_blocks << caption_text(context, row_y)
37
+ row_y += line_h
38
+ end
28
39
  context.enum_literals.each_with_index do |literal, idx|
29
- y = context.geometry.enum_literal_first_y + (idx * line_h)
40
+ y = row_y + (idx * line_h)
30
41
  text_blocks << visibility_placeholder(context, y)
31
42
  text_blocks << literal_name_text(context, literal, y)
32
43
  end
33
44
  wrap_group(text_blocks, context.theme.text_color)
34
45
  end
35
46
 
47
+ def caption?(context)
48
+ context.enum_literals.any? do |l|
49
+ value = l.value.to_s
50
+ !value.empty? && value != l.name.to_s
51
+ end
52
+ end
53
+
54
+ def caption_text(context, y)
55
+ content = "literals"
56
+ len = TextRenderer.estimate_width(content, context.size, nil,
57
+ family: context.family).round
58
+ x = (context.bounds.x + (context.bounds.width - len) / 2.0).floor
59
+ TextRenderer.new(
60
+ content: content,
61
+ x: x, y: y,
62
+ family: context.family, size: context.size, size_unit: context.size_unit,
63
+ fill: context.theme.text_color,
64
+ stroke_in_text: context.theme.stroke_in_text_color,
65
+ width_factor: context.theme.text_width_factor,
66
+ style: "italic"
67
+ ).to_svg
68
+ end
69
+
36
70
  def visibility_placeholder(context, y)
37
71
  TextRenderer.new(
38
72
  content: " ",
@@ -46,8 +80,9 @@ module Ea
46
80
  end
47
81
 
48
82
  def literal_name_text(context, literal, y)
83
+ content = literal_display(literal)
49
84
  TextRenderer.new(
50
- content: literal.name.to_s,
85
+ content: content,
51
86
  x: context.bounds.x + (context.theme.attribute_spec.content_x_offset || 26),
52
87
  y: y,
53
88
  family: context.family, size: context.size, size_unit: context.size_unit,
@@ -57,6 +92,15 @@ module Ea
57
92
  ).to_svg
58
93
  end
59
94
 
95
+ # EA shows "Name = Code" for literals with a stored
96
+ # default value; bare names otherwise.
97
+ def literal_display(literal)
98
+ value = literal.value.to_s
99
+ return literal.name.to_s if value.empty? || value == literal.name.to_s
100
+
101
+ "#{literal.name} = #{value}"
102
+ end
103
+
60
104
  def wrap_group(text_blocks, text_color)
61
105
  style = "stroke-width:1;stroke-linecap:round;stroke-linejoin:bevel; " \
62
106
  "fill:#{text_color};fill-opacity:1.00; " \
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ea
4
+ module Svg
5
+ module EaEmitter
6
+ module Compartment
7
+ # {root}/{leaf} marker compartment. EA seats the marker line
8
+ # DIRECTLY BELOW the header divider, BEFORE the attribute
9
+ # rows (each marker row shifts the attributes down one row).
10
+ # Real OCL constraints render trailing, after the content —
11
+ # the two are distinct compartments.
12
+ module Marker
13
+ module_function
14
+
15
+ def render(context)
16
+ return nil unless context.marker_lines&.any?
17
+ return nil unless context.geometry.marker_first_y
18
+
19
+ Element::ConstraintRenderer.render(
20
+ context.marker_lines,
21
+ bounds: context.bounds,
22
+ first_y: context.geometry.marker_first_y,
23
+ family: context.family, size: context.size
24
+ )
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -13,8 +13,6 @@ module Ea
13
13
  # (379 diagrams, 378 exact): classifiers never render the
14
14
  # subtitle, and ShowForeign=0 diagrams render none.
15
15
  module PackageFromParent
16
- Y_OFFSET_FROM_BOTTOM = 5
17
-
18
16
  module_function
19
17
 
20
18
  def render(context)
@@ -39,10 +37,14 @@ module Ea
39
37
 
40
38
  module_function :render
41
39
 
40
+ # EA draws the subtitle 15px BELOW the body bottom (outside
41
+ # the box) — verified against EA-published package SVGs.
42
+ Y_OFFSET_FROM_BOTTOM = 15
43
+
42
44
  def subtitle(text, context)
43
45
  bounds = context.bounds
44
46
  fill = context.theme.attribute_text_color
45
- y = bounds.y + bounds.height - Y_OFFSET_FROM_BOTTOM
47
+ y = bounds.y + bounds.height + Y_OFFSET_FROM_BOTTOM
46
48
  # EA centers the subtitle by its integer textLength inside
47
49
  # the package BODY and floors x.
48
50
  body_width = Element::PackageShapeRenderer.body_width_for(
@@ -20,6 +20,7 @@ module Ea
20
20
  autoload :EnumLiterals, "ea/svg/ea_emitter/compartment/enum_literals"
21
21
  autoload :TaggedValues, "ea/svg/ea_emitter/compartment/tagged_values"
22
22
  autoload :Constraints, "ea/svg/ea_emitter/compartment/constraints"
23
+ autoload :Marker, "ea/svg/ea_emitter/compartment/marker"
23
24
  autoload :PackageContents, "ea/svg/ea_emitter/compartment/package_contents"
24
25
  autoload :InstanceUnderline, "ea/svg/ea_emitter/compartment/instance_underline"
25
26
  autoload :InstanceSlots, "ea/svg/ea_emitter/compartment/instance_slots"
@@ -34,6 +35,7 @@ module Ea
34
35
  Header,
35
36
  HeaderDivider,
36
37
  StereotypeIcon,
38
+ Marker,
37
39
  Attributes,
38
40
  Operations,
39
41
  EnumLiterals,
@@ -21,6 +21,7 @@ module Ea
21
21
  :attr_lines_count, :op_lines_count,
22
22
  :tagged_values_count,
23
23
  :constraints_count,
24
+ :marker_count,
24
25
  :enum_literals_count,
25
26
  :header_top_padding, :header_line_offset,
26
27
  :divider_offset, :attr_line_offset,
@@ -30,6 +31,7 @@ module Ea
30
31
  attr_lines_count:, op_lines_count:,
31
32
  tagged_values_count:,
32
33
  constraints_count: 0,
34
+ marker_count: 0,
33
35
  enum_literals_count: 0,
34
36
  header_top_padding: 12,
35
37
  header_line_offset: 6,
@@ -43,6 +45,7 @@ module Ea
43
45
  @op_lines_count = op_lines_count
44
46
  @tagged_values_count = tagged_values_count
45
47
  @constraints_count = constraints_count
48
+ @marker_count = marker_count
46
49
  @enum_literals_count = enum_literals_count
47
50
  @header_top_padding = header_top_padding
48
51
  @header_line_offset = header_line_offset
@@ -67,6 +70,29 @@ module Ea
67
70
  end
68
71
 
69
72
  def attr_first_y
73
+ base = raw_attr_first_y
74
+ return base unless marker_count.to_i.positive?
75
+
76
+ # EA renders the {root}/{leaf} marker compartment BETWEEN
77
+ # the header divider and the attributes: its rows occupy
78
+ # (attr_base - 9) onward at the 13px pitch, and attributes
79
+ # shift down one row per marker line. Real OCL constraints
80
+ # do NOT shift attributes — they render trailing.
81
+ # Corpus-verified (TK_PositionType: name +13 {root} +22
82
+ # first-attr; MD_Identification keeps attrs at +22 despite
83
+ # carrying OCL constraints).
84
+ base + (size + 6) * marker_count
85
+ end
86
+
87
+ # First marker-line baseline: one row slot above where
88
+ # attributes would start without markers.
89
+ def marker_first_y
90
+ return nil unless marker_count.to_i.positive?
91
+
92
+ raw_attr_first_y - 9
93
+ end
94
+
95
+ def raw_attr_first_y
70
96
  return bounds.y + size + (header_top_padding || 12) + 12 unless divider_y
71
97
 
72
98
  divider_y + size + (attr_first_offset || 7)
@@ -106,15 +132,19 @@ module Ea
106
132
 
107
133
  # Tagged values appear after attributes (or after ops if
108
134
  # present). EA does not emit a separate divider — the
109
- # italic "tags" header marks the compartment.
135
+ # italic "tags" header marks the compartment. Constraints
136
+ # render ABOVE the attributes (constraints_first_y), not
137
+ # here.
110
138
  def tagged_value_first_y
111
- return nil unless tagged_values_count.to_i.positive? || constraints_count.to_i.positive?
139
+ return nil unless tagged_values_count.to_i.positive? ||
140
+ constraints_count.to_i.positive?
112
141
 
113
142
  content_bottom_y + size + 5
114
143
  end
115
144
 
116
145
  # The lowest content edge among attributes, enum literals,
117
- # and operations — the anchor for trailing compartments.
146
+ # operations, and constraints — the anchor for trailing
147
+ # compartments and the autosize height.
118
148
  def content_bottom_y
119
149
  bottoms = [attr_bottom_y]
120
150
  bottoms << enum_literals_bottom_y if enum_literals_count.to_i.positive?
@@ -5,47 +5,31 @@ module Ea
5
5
  module EaEmitter
6
6
  module Element
7
7
  # Emits the constraints compartment text `<g>`. EA renders
8
- # constraints as a sub-compartment with an italic "constraints"
9
- # header followed by `{name}` lines:
10
- #
11
- # <text style="...font-style:italic;...">constraints</text>
12
- # <text style="...font-style:normal;...">{pattern}</text>
8
+ # each constraint as a bare "{name}" line — no caption —
9
+ # RIGHT-ALIGNED to the element box's right edge at the 13px
10
+ # compartment pitch, seated between the header divider and
11
+ # the attribute rows. Corpus-verified (TK_PositionType /
12
+ # TK_Position: "{root}" x + textLength lands exactly on the
13
+ # box right edge).
13
14
  class ConstraintRenderer
14
- HEADER_TEXT = "constraints"
15
- HEADER_X_OFFSET = 5
16
- LINE_X_OFFSET = 5
17
-
18
15
  def self.render(constraints, bounds:, first_y:, family:, size:,
19
16
  fill: "#000000")
20
- line_h = size + 4
21
- text_blocks = []
22
- text_blocks << build_text(
23
- bounds.x + centered_x_offset(bounds, size), first_y,
24
- HEADER_TEXT, family, size, fill, style: "italic"
25
- )
26
- constraints.each_with_index do |constraint, idx|
27
- y = first_y + ((idx + 1) * line_h)
28
- text_blocks << build_text(
29
- bounds.x + LINE_X_OFFSET, y,
30
- "{#{constraint.name}}", family, size, fill
31
- )
17
+ line_h = size + 6
18
+ text_blocks = constraints.each_with_index.map do |constraint, idx|
19
+ content = "{#{constraint.name}}"
20
+ x = bounds.x + bounds.width -
21
+ TextRenderer.estimate_width(content, size, nil,
22
+ family: family).round
23
+ build_text(x, first_y + idx * line_h, content, family, size, fill)
32
24
  end
33
25
  %(<g style="#{Style::TEXT_GROUP}">\n#{text_blocks.join("\n")}\n</g>)
34
26
  end
35
27
 
36
- def self.build_text(x, y, content, family, size, fill, style: "normal")
28
+ def self.build_text(x, y, content, family, size, fill)
37
29
  TextRenderer.new(content: content, x: x, y: y,
38
- family: family, size: size, fill: fill,
39
- style: style).to_svg
30
+ family: family, size: size, fill: fill).to_svg
40
31
  end
41
32
  private_class_method :build_text
42
-
43
- def self.centered_x_offset(bounds, size)
44
- text_width = HEADER_TEXT.length * (size / 2)
45
- centered = (bounds.width / 2 - text_width / 2).floor
46
- [HEADER_X_OFFSET, centered].max
47
- end
48
- private_class_method :centered_x_offset
49
33
  end
50
34
  end
51
35
  end
@@ -9,15 +9,18 @@ module Ea
9
9
  # Package as this folder-like silhouette regardless of diagram
10
10
  # type.
11
11
  #
12
- # Layout (element bounds cover tab + body together):
12
+ # Layout (element bounds cover tab + body together; the tab
13
+ # occupies the TOP of the stored rect — corpus-verified
14
+ # against EA-published package polygons, single tab 20px and
15
+ # stereotype tab 36px, both inside):
13
16
  #
14
17
  # ┌───┐
15
- # │tab│ ← top TAB_HEIGHT_SINGLE rows ABOVE element bounds;
16
- # │ │ when a stereotype is present, the tab grows to
17
- # └───┴──────────┐ TAB_HEIGHT_DOUBLE rows and extends INTO
18
- # │ │ the bounds; the name renders bold,
19
- # │ body │ left-aligned. The body always starts
20
- # │ │ where the tab ends.
18
+ # │tab│ ← top TAB_HEIGHT rows of the bounds;
19
+ # │ │ 36px when a stereotype is present
20
+ # ├───┴──────────┐
21
+ # │ │ the name renders bold, left-aligned;
22
+ # │ body │ the body always starts where the
23
+ # │ │ tab ends
21
24
  # └───────────────┘
22
25
  #
23
26
  class PackageShapeRenderer
@@ -128,11 +131,9 @@ module Ea
128
131
  tab_top_y + TAB_LABEL_Y_OFFSET
129
132
  end
130
133
 
131
- # Tab anchored 20px above the bounds top — matches EA's
132
- # folder silhouette regardless of whether the tab holds one
133
- # line or two.
134
+ # Tab occupies the top of the stored rect.
134
135
  def tab_top_y
135
- bounds.y - TAB_HEIGHT_SINGLE
136
+ bounds.y
136
137
  end
137
138
 
138
139
  def tab_height
@@ -153,12 +154,9 @@ module Ea
153
154
  ]
154
155
  end
155
156
 
156
- # Body extends from tab.bottom to (bounds.bottom - 20px
157
- # bottom margin). Total body height = bounds.height -
158
- # tab_height (because tab takes (tab_height - 20) from the
159
- # top of the bounds plus 20 above the bounds).
157
+ # Body extends from the tab bottom to the bounds bottom.
160
158
  def body_height(body_top)
161
- bounds.y + bounds.height - TAB_HEIGHT_SINGLE - body_top
159
+ bounds.y + bounds.height - body_top
162
160
  end
163
161
 
164
162
  def tab_points
@@ -86,30 +86,36 @@ module Ea
86
86
  tagged_values_for(classifier).size,
87
87
  header_lines,
88
88
  constraints_count: constraints_for(classifier).size,
89
- enum_literals_count: enum_literals_for(classifier).size)
90
- # EA suppresses the whole attribute compartment when it does
91
- # not fit the stored box height (never truncates rows) - the
92
- # AOS box on CityFurniture hides its association property
93
- # this way. Verified against EA-published reference SVGs.
89
+ marker_count: marker_lines_for(classifier).size,
90
+ enum_literals_count: enum_row_count_for(classifier))
91
+ # EA suppresses the whole attribute compartment when its
92
+ # rows do not fit the stored box height (never truncates
93
+ # rows) - the AOS box on CityFurniture hides its
94
+ # association property this way. The gate compares the last
95
+ # baseline + text descent (~4px) against the box bottom:
96
+ # TK_PositionType keeps 7 rows ending 6px above the bottom,
97
+ # while a 13px-tighter box loses them all.
94
98
  if attr_lines.any? &&
95
- geometry.attr_bottom_y.to_i + size > bounds.y + bounds.height
99
+ geometry.attr_bottom_y.to_i + 4 > bounds.y + bounds.height
96
100
  attr_lines = []
97
101
  geometry = compartment_geometry(bounds, size, attr_lines, op_lines,
98
102
  tagged_values_for(classifier).size,
99
103
  header_lines,
100
104
  constraints_count: constraints_for(classifier).size,
101
- enum_literals_count: enum_literals_for(classifier).size)
105
+ marker_count: marker_lines_for(classifier).size,
106
+ enum_literals_count: enum_row_count_for(classifier))
102
107
  end
103
108
  # EA suppresses the operations compartment when its rows
104
109
  # overflow the stored box height (same rule as attributes).
105
110
  if op_lines.any? && geometry.op_first_y &&
106
- geometry.op_bottom_y.to_i + size > bounds.y + bounds.height
111
+ geometry.op_bottom_y.to_i + 4 > bounds.y + bounds.height
107
112
  op_lines = []
108
113
  geometry = compartment_geometry(bounds, size, attr_lines, op_lines,
109
114
  tagged_values_for(classifier).size,
110
115
  header_lines,
111
116
  constraints_count: constraints_for(classifier).size,
112
- enum_literals_count: enum_literals_for(classifier).size)
117
+ marker_count: marker_lines_for(classifier).size,
118
+ enum_literals_count: enum_row_count_for(classifier))
113
119
  end
114
120
  RenderContext.new(
115
121
  element: element,
@@ -127,6 +133,7 @@ module Ea
127
133
  enum_literals: enum_literals_for(classifier),
128
134
  tagged_values: element.show_tagged_values ? tagged_values_for(classifier) : [],
129
135
  constraints: constraints_for(classifier),
136
+ marker_lines: marker_lines_for(classifier),
130
137
  package_content_lines: package_content_lines_for(model_element),
131
138
  geometry: geometry,
132
139
  theme: theme,
@@ -139,13 +146,15 @@ module Ea
139
146
 
140
147
  def compartment_geometry(bounds, size, attr_lines, op_lines,
141
148
  tagged_count, header_lines,
142
- constraints_count: 0, enum_literals_count: 0)
149
+ constraints_count: 0, marker_count: 0,
150
+ enum_literals_count: 0)
143
151
  CompartmentGeometry.new(bounds: bounds, size: size,
144
152
  header_lines_count: header_lines.size,
145
153
  attr_lines_count: attr_lines.size,
146
154
  op_lines_count: op_lines.size,
147
155
  tagged_values_count: tagged_count,
148
156
  constraints_count: constraints_count,
157
+ marker_count: marker_count,
149
158
  enum_literals_count: enum_literals_count,
150
159
  header_top_padding: header_padding_for(header_lines),
151
160
  header_line_offset: theme.compartments.header_line_offset,
@@ -187,18 +196,34 @@ module Ea
187
196
  classifier.literals || []
188
197
  end
189
198
 
199
+ # The "literals" caption occupies a row slot when any
200
+ # literal carries a stored code value.
201
+ def enum_row_count_for(classifier)
202
+ literals = enum_literals_for(classifier)
203
+ caption = literals.any? { |l| !l.value.to_s.empty? && l.value.to_s != l.name.to_s }
204
+ literals.size + (caption ? 1 : 0)
205
+ end
206
+
190
207
  def tagged_values_for(classifier)
191
208
  return [] unless classifier.is_a?(Ea::Model::Classifier)
192
209
 
193
210
  classifier.tagged_values || []
194
211
  end
195
212
 
213
+ # Real OCL constraints render trailing, after the content
214
+ # compartment; the {root}/{leaf} marker renders its own
215
+ # compartment between the divider and the attributes.
196
216
  def constraints_for(classifier)
197
217
  return [] unless classifier.is_a?(Ea::Model::Classifier)
198
218
 
219
+ classifier.constraints || []
220
+ end
221
+
222
+ def marker_lines_for(classifier)
223
+ return [] unless classifier.is_a?(Ea::Model::Classifier)
224
+
199
225
  marker_line = root_leaf_marker_for(classifier)
200
- marker = marker_line ? [marker_constraint(marker_line)] : []
201
- marker + (classifier.constraints || [])
226
+ marker_line ? [marker_constraint(marker_line)] : []
202
227
  end
203
228
 
204
229
  # EA renders the element's Root/Leaf checkboxes as {root},
@@ -16,7 +16,7 @@ module Ea
16
16
  :fill, :stroke, :stroke_width, :text_fill,
17
17
  :family, :size, :size_unit,
18
18
  :header_lines, :attr_lines, :op_lines,
19
- :enum_literals, :tagged_values, :constraints,
19
+ :enum_literals, :tagged_values, :constraints, :marker_lines,
20
20
  :package_content_lines,
21
21
  :geometry, :theme, :canvas, :diagram, :model_index,
22
22
  :off_canvas_parent_name,
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.6.19"
7
+ VERSION = "0.6.21"
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.6.19
4
+ version: 0.6.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -884,6 +884,7 @@ files:
884
884
  - lib/ea/svg/ea_emitter/compartment/header_divider.rb
885
885
  - lib/ea/svg/ea_emitter/compartment/instance_slots.rb
886
886
  - lib/ea/svg/ea_emitter/compartment/instance_underline.rb
887
+ - lib/ea/svg/ea_emitter/compartment/marker.rb
887
888
  - lib/ea/svg/ea_emitter/compartment/note_body.rb
888
889
  - lib/ea/svg/ea_emitter/compartment/note_text.rb
889
890
  - lib/ea/svg/ea_emitter/compartment/operations.rb