Skip to content

Commit 968de38

Browse files
committed
Refactor railroad_diagrams classes to extract complex methods into smaller private methods for improved readability
1 parent 7a2d93c commit 968de38

File tree

20 files changed

+892
-316
lines changed

20 files changed

+892
-316
lines changed

lib/railroad_diagrams/choice.rb

Lines changed: 103 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -80,57 +80,16 @@ def to_s
8080
# @rbs return: Choice
8181
def format(x, y, width)
8282
left_gap, right_gap = determine_gaps(width, @width)
83-
84-
# Hook up the two sides if self is narrower than its stated width.
8583
Path.new(x, y).h(left_gap).add(self)
8684
Path.new(x + left_gap + @width, y + @height).h(right_gap).add(self)
8785
x += left_gap
8886

8987
inner_width = @width - (AR * 4)
9088
default = @items[@default]
9189

92-
# Do the elements that curve above
93-
distance_from_y = 0
94-
(@default - 1).downto(0) do |i|
95-
item = @items[i]
96-
lower_item = @items[i + 1]
97-
distance_from_y += lower_item.up + @separators[i] + item.down + item.height
98-
Path.new(x, y)
99-
.arc('se')
100-
.up(distance_from_y - (AR * 2))
101-
.arc('wn')
102-
.add(self)
103-
item.format(x + (AR * 2), y - distance_from_y, inner_width).add(self)
104-
Path.new(x + (AR * 2) + inner_width, y - distance_from_y + item.height)
105-
.arc('ne')
106-
.down(distance_from_y - item.height + default.height - (AR * 2))
107-
.arc('ws')
108-
.add(self)
109-
end
110-
111-
# Do the straight-line path.
112-
Path.new(x, y).right(AR * 2).add(self)
113-
@items[@default].format(x + (AR * 2), y, inner_width).add(self)
114-
Path.new(x + (AR * 2) + inner_width, y + @height).right(AR * 2).add(self)
115-
116-
# Do the elements that curve below
117-
distance_from_y = 0
118-
(@default + 1...@items.size).each do |i|
119-
item = @items[i]
120-
upper_item = @items[i - 1]
121-
distance_from_y += upper_item.height + upper_item.down + @separators[i - 1] + item.up
122-
Path.new(x, y)
123-
.arc('ne')
124-
.down(distance_from_y - (AR * 2))
125-
.arc('ws')
126-
.add(self)
127-
item.format(x + (AR * 2), y + distance_from_y, inner_width).add(self)
128-
Path.new(x + (AR * 2) + inner_width, y + distance_from_y + item.height)
129-
.arc('se')
130-
.up(distance_from_y - (AR * 2) + item.height - default.height)
131-
.arc('wn')
132-
.add(self)
133-
end
90+
format_items_above_default(x, y, inner_width, default)
91+
format_default_item(x, y, inner_width)
92+
format_items_below_default(x, y, inner_width, default)
13493

13594
self
13695
end
@@ -144,11 +103,9 @@ def text_diagram
144103
]
145104
)
146105

147-
# Format all the child items, so we can know the maximum width.
148106
item_tds = @items.map { |item| item.text_diagram.expand(1, 1, 0, 0) }
149107
max_item_width = item_tds.map(&:width).max
150108
diagram_td = TextDiagram.new(0, 0, [])
151-
# Format the choice collection.
152109
item_tds.each_with_index do |item_td, i|
153110
left_pad, right_pad = TextDiagram.gaps(max_item_width, item_td.width)
154111
item_td = item_td.expand(left_pad, right_pad, 0, 0)
@@ -158,46 +115,37 @@ def text_diagram
158115
move_entry = false
159116
move_exit = false
160117
if i <= @default
161-
# Item below the line: round off the entry/exit lines downwards.
162118
left_lines[item_td.entry] = roundcorner_top_left
163119
right_lines[item_td.exit] = roundcorner_top_right
164120
if i.zero?
165-
# First item and above the line: also remove ascenders above the item's entry and exit, suppress the separator above it.
166121
has_separator = false
167122
(0...item_td.entry).each { |j| left_lines[j] = ' ' }
168123
(0...item_td.exit).each { |j| right_lines[j] = ' ' }
169124
end
170125
end
171126
if i >= @default
172-
# Item below the line: round off the entry/exit lines downwards.
173127
left_lines[item_td.entry] = roundcorner_bot_left
174128
right_lines[item_td.exit] = roundcorner_bot_right
175129
if i.zero?
176-
# First item and below the line: also suppress the separator above it.
177130
has_separator = false
178131
end
179132
if i == @items.size - 1
180-
# Last item and below the line: also remove descenders below the item's entry and exit
181133
(item_td.entry + 1...item_td.height).each { |j| left_lines[j] = ' ' }
182134
(item_td.exit + 1...item_td.height).each { |j| right_lines[j] = ' ' }
183135
end
184136
end
185137
if i == @default
186-
# Item on the line: entry/exit are horizontal, and sets the outer entry/exit.
187138
left_lines[item_td.entry] = cross
188139
right_lines[item_td.exit] = cross
189140
move_entry = true
190141
move_exit = true
191142
if i.zero? && i == @items.size - 1
192-
# Only item and on the line: set entry/exit for straight through.
193143
left_lines[item_td.entry] = line
194144
right_lines[item_td.exit] = line
195145
elsif i.zero?
196-
# First item and on the line: set entry/exit for no ascenders.
197146
left_lines[item_td.entry] = roundcorner_top_right
198147
right_lines[item_td.exit] = roundcorner_top_left
199148
elsif i == @items.size - 1
200-
# Last item and on the line: set entry/exit for no descenders.
201149
left_lines[item_td.entry] = roundcorner_bot_right
202150
right_lines[item_td.exit] = roundcorner_bot_left
203151
end
@@ -218,5 +166,105 @@ def text_diagram
218166
end
219167
diagram_td
220168
end
169+
170+
private
171+
172+
# @rbs x: Numeric
173+
# @rbs y: Numeric
174+
# @rbs inner_width: Numeric
175+
# @rbs default: DiagramItem
176+
# @rbs return: void
177+
def format_items_above_default(x, y, inner_width, default)
178+
distance_from_y = 0
179+
(@default - 1).downto(0) do |i|
180+
item = @items[i]
181+
lower_item = @items[i + 1]
182+
distance_from_y += lower_item.up + @separators[i] + item.down + item.height
183+
184+
add_upward_path(x, y, distance_from_y)
185+
item.format(x + (AR * 2), y - distance_from_y, inner_width).add(self)
186+
add_downward_return_path(x + (AR * 2) + inner_width, y, distance_from_y, item, default)
187+
end
188+
end
189+
190+
# @rbs x: Numeric
191+
# @rbs y: Numeric
192+
# @rbs inner_width: Numeric
193+
# @rbs return: void
194+
def format_default_item(x, y, inner_width)
195+
Path.new(x, y).right(AR * 2).add(self)
196+
@items[@default].format(x + (AR * 2), y, inner_width).add(self)
197+
Path.new(x + (AR * 2) + inner_width, y + @height).right(AR * 2).add(self)
198+
end
199+
200+
# @rbs x: Numeric
201+
# @rbs y: Numeric
202+
# @rbs inner_width: Numeric
203+
# @rbs default: DiagramItem
204+
# @rbs return: void
205+
def format_items_below_default(x, y, inner_width, default)
206+
distance_from_y = 0
207+
(@default + 1...@items.size).each do |i|
208+
item = @items[i]
209+
upper_item = @items[i - 1]
210+
distance_from_y += upper_item.height + upper_item.down + @separators[i - 1] + item.up
211+
212+
add_downward_path(x, y, distance_from_y)
213+
item.format(x + (AR * 2), y + distance_from_y, inner_width).add(self)
214+
add_upward_return_path(x + (AR * 2) + inner_width, y, distance_from_y, item, default)
215+
end
216+
end
217+
218+
# @rbs x: Numeric
219+
# @rbs y: Numeric
220+
# @rbs distance: Numeric
221+
# @rbs return: void
222+
def add_upward_path(x, y, distance)
223+
Path.new(x, y)
224+
.arc('se')
225+
.up(distance - (AR * 2))
226+
.arc('wn')
227+
.add(self)
228+
end
229+
230+
# @rbs x: Numeric
231+
# @rbs y: Numeric
232+
# @rbs distance: Numeric
233+
# @rbs item: DiagramItem
234+
# @rbs default: DiagramItem
235+
# @rbs return: void
236+
def add_downward_return_path(x, y, distance, item, default)
237+
Path.new(x, y - distance + item.height)
238+
.arc('ne')
239+
.down(distance - item.height + default.height - (AR * 2))
240+
.arc('ws')
241+
.add(self)
242+
end
243+
244+
# @rbs x: Numeric
245+
# @rbs y: Numeric
246+
# @rbs distance: Numeric
247+
# @rbs return: void
248+
def add_downward_path(x, y, distance)
249+
Path.new(x, y)
250+
.arc('ne')
251+
.down(distance - (AR * 2))
252+
.arc('ws')
253+
.add(self)
254+
end
255+
256+
# @rbs x: Numeric
257+
# @rbs y: Numeric
258+
# @rbs distance: Numeric
259+
# @rbs item: DiagramItem
260+
# @rbs default: DiagramItem
261+
# @rbs return: void
262+
def add_upward_return_path(x, y, distance, item, default)
263+
Path.new(x, y + distance + item.height)
264+
.arc('se')
265+
.up(distance - (AR * 2) + item.height - default.height)
266+
.arc('wn')
267+
.add(self)
268+
end
221269
end
222270
end

lib/railroad_diagrams/comment.rb

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,30 +31,46 @@ def to_s
3131
# @rbs return: Comment
3232
def format(x, y, _width)
3333
left_gap, right_gap = determine_gaps(width, @width)
34+
add_connecting_paths(x, y, left_gap, right_gap)
35+
add_text_element(x + left_gap, y)
36+
self
37+
end
38+
39+
# @rbs return: TextDiagram
40+
def text_diagram
41+
TextDiagram.new(0, 0, [@text])
42+
end
43+
44+
private
3445

35-
# Hook up the two sides if self is narrower than its stated width.
46+
# @rbs x: Numeric
47+
# @rbs y: Numeric
48+
# @rbs left_gap: Numeric
49+
# @rbs right_gap: Numeric
50+
# @rbs return: void
51+
def add_connecting_paths(x, y, left_gap, right_gap)
3652
Path.new(x, y).h(left_gap).add(self)
3753
Path.new(x + left_gap + @width, y).h(right_gap).add(self)
54+
end
3855

56+
# @rbs x: Numeric
57+
# @rbs y: Numeric
58+
# @rbs return: void
59+
def add_text_element(x, y)
3960
text = DiagramItem.new(
4061
'text',
41-
attrs: { 'x' => x + left_gap + (@width / 2), 'y' => y + 4, 'class' => 'comment' },
62+
attrs: { 'x' => x + (@width / 2), 'y' => y + 4, 'class' => 'comment' },
4263
text: @text
4364
)
65+
4466
if @href
4567
a = DiagramItem.new('a', attrs: { 'xlink:href' => @href }, text: text).add(self)
4668
text.add(a)
4769
else
4870
text.add(self)
4971
end
50-
DiagramItem.new('title', attrs: {}, text: @title).add(self) if @title
51-
self
52-
end
5372

54-
# @rbs return: TextDiagram
55-
def text_diagram
56-
# NOTE: href, title, and cls are ignored for text diagrams.
57-
TextDiagram.new(0, 0, [@text])
73+
DiagramItem.new('title', attrs: {}, text: @title).add(self) if @title
5874
end
5975
end
6076
end

0 commit comments

Comments
 (0)