metadata_presenter 2.10.0 → 2.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e03698bc80c7779212a57aaa9bbca97b5567025b950a6a6b7170fb635745e3e0
4
- data.tar.gz: 7c3eca3a9da18aa6001791d2c5def0abacbf95b8b9baeb2be8920df804734bdd
3
+ metadata.gz: 6cca8a3428e516ba176e5a898a1d1a76cd57fa836041f0c3fc492a8cd394e88a
4
+ data.tar.gz: 9940b709ccce5e211444fe6b7cf84dfeed78f1c13591c9291b797a3eca4ac609
5
5
  SHA512:
6
- metadata.gz: a6dedb4d4413eab6222933b8096bf45c6fef7db7d51853e1a46ecaf51f4b718362bbe00776f5adfc3b3687dcf10fb6660b289d9dc930768dadfa5dc1bfbda1b9
7
- data.tar.gz: c822f36b904e46fd6075979dd3acca19ed1e91ddcf73a5adf93ca4ad261e2da5e5507866fe890641c116ecb4695e25b16281fd5aa54304b7328b50b5a4d55b34
6
+ metadata.gz: 1b9c3ae006ca76d0386db74a2fb39d106884dc0cd285457c05be6f3d3f75e2a30cc79511112d3881c532ba7e6e3c087e5e83e4116a708cf3cd81b4ea345de813
7
+ data.tar.gz: 659da027fb5c27df2c007dfd961bfce0148879aec3833f72c53f4d195080bde041b29c53260c397430e5425383a2c7a364e1ed8fd4d22bbabdb33417ecb896ed
@@ -0,0 +1,18 @@
1
+ module MetadataPresenter
2
+ module BranchDestinations
3
+ # The frontend requires that expressions of type 'or' get there own line and
4
+ # arrow. 'and' expression types continue to be grouped together.
5
+ # Return the UUIDs of the destinations exiting a branch and allow duplicates
6
+ # if the expression type is an 'or'.
7
+ def exiting_destinations_from_branch(branch)
8
+ destination_uuids = branch.conditionals.map do |conditional|
9
+ if conditional.type == 'or'
10
+ conditional.expressions.map { |_| conditional.next }
11
+ else
12
+ conditional.next
13
+ end
14
+ end
15
+ destination_uuids.flatten.push(branch.default_next)
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,25 @@
1
+ module MetadataPresenter
2
+ class ColumnNumber
3
+ def initialize(uuid:, coordinates:, new_column:)
4
+ @uuid = uuid
5
+ @coordinates = coordinates
6
+ @new_column = new_column
7
+ end
8
+
9
+ def number
10
+ use_new_column? ? new_column : existing_column
11
+ end
12
+
13
+ private
14
+
15
+ attr_reader :uuid, :coordinates, :new_column
16
+
17
+ def use_new_column?
18
+ existing_column.nil? || new_column > existing_column
19
+ end
20
+
21
+ def existing_column
22
+ @existing_column ||= @coordinates.uuid_column(uuid)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,59 @@
1
+ module MetadataPresenter
2
+ class Coordinates
3
+ def initialize(flow)
4
+ @flow = flow
5
+ @positions = setup_positions
6
+ end
7
+
8
+ attr_reader :positions
9
+
10
+ def set_column(uuid, number)
11
+ positions[uuid][:column] = number
12
+ end
13
+
14
+ def set_row(uuid, number)
15
+ positions[uuid][:row] = number
16
+ end
17
+
18
+ def uuid_column(uuid)
19
+ positions[uuid][:column]
20
+ end
21
+
22
+ def uuid_row(uuid)
23
+ positions[uuid][:row]
24
+ end
25
+
26
+ def uuid_at_position(column, row)
27
+ positions.find do |uuid, position|
28
+ if position[:column] == column && position[:row] == row
29
+ return uuid
30
+ end
31
+ end
32
+ end
33
+
34
+ def position(uuid)
35
+ positions[uuid]
36
+ end
37
+
38
+ def occupied?(column, row, new_object_uuid)
39
+ positions.any? do |uuid, position|
40
+ position[:column] == column &&
41
+ position[:row] == row &&
42
+ new_object_uuid != uuid
43
+ end
44
+ end
45
+
46
+ def positions_in_column(column_number)
47
+ positions.select { |_, position| position[:column] == column_number }
48
+ end
49
+
50
+ private
51
+
52
+ attr_reader :flow
53
+ attr_writer :positions
54
+
55
+ def setup_positions
56
+ flow.keys.index_with { |_uuid| { row: nil, column: nil } }
57
+ end
58
+ end
59
+ end
@@ -12,6 +12,7 @@ module MetadataPresenter
12
12
  end
13
13
 
14
14
  class Grid
15
+ include BranchDestinations
15
16
  attr_reader :start_from
16
17
 
17
18
  def initialize(service, start_from: nil, main_flow: [])
@@ -21,7 +22,7 @@ module MetadataPresenter
21
22
  @ordered = []
22
23
  @routes = []
23
24
  @traversed = []
24
- @coordinates = setup_coordinates
25
+ @coordinates = MetadataPresenter::Coordinates.new(service.flow)
25
26
  end
26
27
 
27
28
  ROW_ZERO = 0
@@ -30,8 +31,8 @@ module MetadataPresenter
30
31
  return @ordered unless @ordered.empty?
31
32
 
32
33
  @ordered = make_grid
33
- add_columns
34
- add_rows
34
+ set_column_numbers
35
+ set_row_numbers
35
36
  add_by_coordinates
36
37
  insert_expression_spacers
37
38
  trim_pointers unless main_flow.empty?
@@ -62,10 +63,6 @@ module MetadataPresenter
62
63
  attr_reader :service, :main_flow
63
64
  attr_accessor :ordered, :traversed, :routes, :coordinates
64
65
 
65
- def setup_coordinates
66
- service.flow.keys.index_with { |_uuid| { row: nil, column: nil } }
67
- end
68
-
69
66
  def route_from_start
70
67
  @route_from_start ||=
71
68
  MetadataPresenter::Route.new(
@@ -83,7 +80,12 @@ module MetadataPresenter
83
80
  end
84
81
 
85
82
  def max_potential_rows
86
- @max_potential_rows ||= @routes.map(&:row).max + 1
83
+ @max_potential_rows ||= begin
84
+ destinations_count = service.branches.map do |branch|
85
+ exiting_destinations_from_branch(branch).count
86
+ end
87
+ destinations_count.sum
88
+ end
87
89
  end
88
90
 
89
91
  def max_potential_columns
@@ -121,29 +123,47 @@ module MetadataPresenter
121
123
  end
122
124
  end
123
125
 
124
- def add_columns
126
+ def set_column_numbers
125
127
  @routes.each do |route|
126
- route.flow_uuids.each.with_index(route.column) do |uuid, column|
127
- column_number = @coordinates[uuid][:column]
128
- if column_number.nil? || column > column_number
129
- @coordinates[uuid][:column] = column
130
- end
128
+ route.flow_uuids.each.with_index(route.column) do |uuid, new_column|
129
+ column_number = MetadataPresenter::ColumnNumber.new(
130
+ uuid: uuid,
131
+ new_column: new_column,
132
+ coordinates: @coordinates
133
+ ).number
134
+ @coordinates.set_column(uuid, column_number)
131
135
  end
132
136
  end
133
137
  end
134
138
 
135
- def add_rows
139
+ def set_row_numbers
136
140
  @routes.each do |route|
137
- next if @traversed.include?(route.traverse_from)
141
+ next if @traversed.include?(route.traverse_from) && appears_later_in_flow?(route)
138
142
 
143
+ current_row = route.row
139
144
  route.flow_uuids.each do |uuid|
140
- @coordinates[uuid][:row] = route.row if @coordinates[uuid][:row].nil?
145
+ row_number = MetadataPresenter::RowNumber.new(
146
+ uuid: uuid,
147
+ route: route,
148
+ current_row: current_row,
149
+ coordinates: @coordinates,
150
+ service: service
151
+ ).number
152
+ @coordinates.set_row(uuid, row_number)
153
+
141
154
  update_route_rows(route, uuid)
142
155
  @traversed.push(uuid) unless @traversed.include?(uuid)
156
+ current_row = row_number
143
157
  end
144
158
  end
145
159
  end
146
160
 
161
+ # New routes can be linked to later. We need to also traverse these to see
162
+ # if anything should be moved to a different row.
163
+ def appears_later_in_flow?(route)
164
+ @coordinates.uuid_column(route.traverse_from) > route.column
165
+ end
166
+
147
167
  # Each Route object has a starting row. Each Route object has no knowledge
148
168
  # of other potential routes and pages/branches that may or may not exist in
149
169
  # them. The starting row may need to change dependent upon what has been
@@ -161,7 +181,8 @@ module MetadataPresenter
161
181
  end
162
182
 
163
183
  def add_by_coordinates
164
- @coordinates.each do |uuid, position|
184
+ service.flow.each_key do |uuid|
185
+ position = coordinates.position(uuid)
165
186
  next if detached?(position)
166
187
 
167
188
  @ordered[position[:column]][position[:row]] = get_flow_object(uuid)
@@ -219,37 +240,23 @@ module MetadataPresenter
219
240
  # the one the branch is located in.
220
241
  def insert_expression_spacers
221
242
  service.branches.each do |branch|
222
- position = @coordinates[branch.uuid]
223
- next if position[:row].nil? || position[:column].nil? # detached branch
243
+ next if coordinates.uuid_column(branch.uuid).nil?
224
244
 
225
- next_column = position[:column] + 1
226
- uuids = []
227
- exiting_destinations_from_branch(branch).each.with_index(position[:row]) do |uuid, row|
228
- if uuids.include?(uuid)
245
+ previous_uuid = ''
246
+ next_column = coordinates.uuid_column(branch.uuid) + 1
247
+ exiting_destinations_from_branch(branch).each_with_index do |uuid, row|
248
+ if uuid == previous_uuid
229
249
  @ordered[next_column].insert(row, MetadataPresenter::Spacer.new)
230
250
  end
231
-
232
- uuids.push(uuid) unless uuids.include?(uuid)
233
- end
234
- end
235
- end
236
-
237
- # The frontend requires that expressions of type 'or' get there own line and
238
- # arrow. 'and' expression types continue to be grouped together.
239
- # Return the UUIDs of the destinations exiting a branch and allow duplicates
240
- # if the expression type is an 'or'.
241
- def exiting_destinations_from_branch(branch)
242
- destination_uuids = branch.conditionals.map do |conditional|
243
- if conditional.type == 'or'
244
- conditional.expressions.map(&:next)
245
- else
246
- conditional.next
251
+ previous_uuid = uuid
247
252
  end
248
253
  end
249
- destination_uuids.flatten
250
254
  end
251
255
 
252
256
  # Any destinations exiting the branch that have not already been traversed.
257
+ # This removes any branch destinations that already exist on other rows. If
258
+ # that is the case then the arrow will flow towards whatever row that object
259
+ # is located.
253
260
  def routes_exiting_branch(branch)
254
261
  branch.all_destination_uuids.reject { |uuid| @traversed.include?(uuid) }
255
262
  end
@@ -0,0 +1,71 @@
1
+ module MetadataPresenter
2
+ class RowNumber
3
+ include BranchDestinations
4
+
5
+ def initialize(uuid:, route:, current_row:, coordinates:, service:)
6
+ @uuid = uuid
7
+ @route = route
8
+ @current_row = current_row
9
+ @coordinates = coordinates
10
+ @service = service
11
+ end
12
+
13
+ ROW_ZERO = 0
14
+
15
+ def number
16
+ return route.row if first_row? && existing_row.nil?
17
+
18
+ return ROW_ZERO if place_on_row_zero?
19
+
20
+ if object_above.branch? && uuid != object_above.uuid
21
+ coordinates.uuid_row(object_above.uuid) + number_of_destinations
22
+ else
23
+ existing_row.nil? ? current_row : [current_row, existing_row].max
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :uuid, :route, :current_row, :coordinates, :service
30
+
31
+ def existing_row
32
+ @existing_row ||= coordinates.uuid_row(uuid)
33
+ end
34
+
35
+ def first_row?
36
+ @first_row ||= route.row.zero?
37
+ end
38
+
39
+ def object_above
40
+ @object_above ||=
41
+ service.flow_object(coordinates.uuid_at_position(uuid_column, row_above))
42
+ end
43
+
44
+ # Takes into account the 'or' type of conditionals which requires an
45
+ # additional spacer
46
+ def number_of_destinations
47
+ exiting_destinations_from_branch(object_above).count
48
+ end
49
+
50
+ def uuid_column
51
+ @uuid_column ||= coordinates.uuid_column(uuid)
52
+ end
53
+
54
+ def row_above
55
+ @row_above ||= route.row - 1
56
+ end
57
+
58
+ # If an object has already been positioned on row 0 then leave it there.
59
+ # If the object is a checkanswers or confirmation type then always place it
60
+ # on row 0.
61
+ def place_on_row_zero?
62
+ cya_or_confirmation_page? || coordinates.uuid_row(uuid) == ROW_ZERO
63
+ end
64
+
65
+ def cya_or_confirmation_page?
66
+ %w[page.checkanswers page.confirmation].include?(
67
+ service.find_page_by_uuid(uuid)&.type
68
+ )
69
+ end
70
+ end
71
+ end