super_diff 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -1
  3. data/lib/super_diff.rb +27 -6
  4. data/lib/super_diff/active_record.rb +7 -7
  5. data/lib/super_diff/active_record/differs/active_record_relation.rb +3 -13
  6. data/lib/super_diff/active_record/object_inspection.rb +2 -6
  7. data/lib/super_diff/active_record/object_inspection/inspection_tree_builders.rb +16 -0
  8. data/lib/super_diff/active_record/object_inspection/{inspectors → inspection_tree_builders}/active_record_model.rb +19 -20
  9. data/lib/super_diff/active_record/object_inspection/{inspectors → inspection_tree_builders}/active_record_relation.rb +9 -8
  10. data/lib/super_diff/active_record/operation_tree_flatteners.rb +10 -0
  11. data/lib/super_diff/active_record/operation_tree_flatteners/active_record_relation.rb +17 -0
  12. data/lib/super_diff/active_record/operation_trees/active_record_relation.rb +8 -7
  13. data/lib/super_diff/active_support.rb +8 -8
  14. data/lib/super_diff/active_support/differs/hash_with_indifferent_access.rb +3 -13
  15. data/lib/super_diff/active_support/object_inspection.rb +2 -6
  16. data/lib/super_diff/active_support/object_inspection/{inspectors.rb → inspection_tree_builders.rb} +2 -2
  17. data/lib/super_diff/active_support/object_inspection/inspection_tree_builders/hash_with_indifferent_access.rb +37 -0
  18. data/lib/super_diff/active_support/operation_tree_builders/hash_with_indifferent_access.rb +17 -0
  19. data/lib/super_diff/active_support/operation_tree_flatteners.rb +10 -0
  20. data/lib/super_diff/active_support/operation_tree_flatteners/hash_with_indifferent_access.rb +17 -0
  21. data/lib/super_diff/active_support/operation_trees/hash_with_indifferent_access.rb +4 -7
  22. data/lib/super_diff/colorized_document_extensions.rb +9 -6
  23. data/lib/super_diff/configuration.rb +81 -8
  24. data/lib/super_diff/csi.rb +1 -2
  25. data/lib/super_diff/csi/four_bit_color.rb +0 -2
  26. data/lib/super_diff/differs/array.rb +1 -1
  27. data/lib/super_diff/differs/base.rb +3 -21
  28. data/lib/super_diff/differs/custom_object.rb +1 -1
  29. data/lib/super_diff/differs/default_object.rb +1 -1
  30. data/lib/super_diff/differs/hash.rb +1 -1
  31. data/lib/super_diff/differs/main.rb +1 -7
  32. data/lib/super_diff/differs/multiline_string.rb +1 -1
  33. data/lib/super_diff/differs/time_like.rb +1 -1
  34. data/lib/super_diff/equality_matchers/array.rb +2 -2
  35. data/lib/super_diff/equality_matchers/default.rb +2 -2
  36. data/lib/super_diff/equality_matchers/hash.rb +2 -2
  37. data/lib/super_diff/equality_matchers/multiline_string.rb +2 -2
  38. data/lib/super_diff/equality_matchers/primitive.rb +4 -7
  39. data/lib/super_diff/equality_matchers/singleline_string.rb +2 -2
  40. data/lib/super_diff/helpers.rb +52 -2
  41. data/lib/super_diff/line.rb +83 -0
  42. data/lib/super_diff/object_inspection.rb +12 -1
  43. data/lib/super_diff/object_inspection/inspection_tree.rb +183 -81
  44. data/lib/super_diff/object_inspection/inspection_tree_builders.rb +44 -0
  45. data/lib/super_diff/object_inspection/inspection_tree_builders/array.rb +38 -0
  46. data/lib/super_diff/object_inspection/inspection_tree_builders/base.rb +27 -0
  47. data/lib/super_diff/object_inspection/inspection_tree_builders/custom_object.rb +37 -0
  48. data/lib/super_diff/object_inspection/inspection_tree_builders/default_object.rb +63 -0
  49. data/lib/super_diff/object_inspection/{inspectors → inspection_tree_builders}/defaults.rb +1 -2
  50. data/lib/super_diff/object_inspection/inspection_tree_builders/hash.rb +46 -0
  51. data/lib/super_diff/object_inspection/{inspectors → inspection_tree_builders}/main.rb +5 -10
  52. data/lib/super_diff/object_inspection/inspection_tree_builders/primitive.rb +21 -0
  53. data/lib/super_diff/object_inspection/{inspectors → inspection_tree_builders}/time_like.rb +19 -18
  54. data/lib/super_diff/object_inspection/nodes.rb +33 -32
  55. data/lib/super_diff/object_inspection/nodes/as_lines_when_rendering_to_lines.rb +97 -0
  56. data/lib/super_diff/object_inspection/nodes/as_prefix_when_rendering_to_lines.rb +27 -0
  57. data/lib/super_diff/object_inspection/nodes/as_prelude_when_rendering_to_lines.rb +27 -0
  58. data/lib/super_diff/object_inspection/nodes/as_single_line.rb +33 -0
  59. data/lib/super_diff/object_inspection/nodes/base.rb +55 -20
  60. data/lib/super_diff/object_inspection/nodes/inspection.rb +47 -7
  61. data/lib/super_diff/object_inspection/nodes/nesting.rb +16 -5
  62. data/lib/super_diff/object_inspection/nodes/only_when.rb +54 -0
  63. data/lib/super_diff/object_inspection/nodes/text.rb +16 -2
  64. data/lib/super_diff/object_inspection/nodes/when_empty.rb +21 -6
  65. data/lib/super_diff/object_inspection/nodes/when_non_empty.rb +20 -5
  66. data/lib/super_diff/object_inspection/nodes/when_rendering_to_lines.rb +27 -0
  67. data/lib/super_diff/object_inspection/nodes/when_rendering_to_string.rb +27 -0
  68. data/lib/super_diff/object_inspection/prefix_for_next_node.rb +6 -0
  69. data/lib/super_diff/object_inspection/prelude_for_next_node.rb +6 -0
  70. data/lib/super_diff/operation_tree_builders/array.rb +7 -10
  71. data/lib/super_diff/operation_tree_builders/base.rb +6 -6
  72. data/lib/super_diff/operation_tree_builders/custom_object.rb +5 -2
  73. data/lib/super_diff/operation_tree_builders/default_object.rb +1 -1
  74. data/lib/super_diff/operation_tree_builders/hash.rb +0 -7
  75. data/lib/super_diff/operation_tree_builders/multiline_string.rb +2 -6
  76. data/lib/super_diff/operation_tree_flatteners.rb +20 -0
  77. data/lib/super_diff/operation_tree_flatteners/array.rb +15 -0
  78. data/lib/super_diff/operation_tree_flatteners/base.rb +54 -0
  79. data/lib/super_diff/operation_tree_flatteners/collection.rb +139 -0
  80. data/lib/super_diff/operation_tree_flatteners/custom_object.rb +28 -0
  81. data/lib/super_diff/operation_tree_flatteners/default_object.rb +32 -0
  82. data/lib/super_diff/operation_tree_flatteners/hash.rb +41 -0
  83. data/lib/super_diff/operation_tree_flatteners/multiline_string.rb +17 -0
  84. data/lib/super_diff/operation_trees/array.rb +4 -7
  85. data/lib/super_diff/operation_trees/base.rb +39 -16
  86. data/lib/super_diff/operation_trees/custom_object.rb +4 -8
  87. data/lib/super_diff/operation_trees/default_object.rb +28 -13
  88. data/lib/super_diff/operation_trees/hash.rb +4 -7
  89. data/lib/super_diff/operation_trees/main.rb +1 -1
  90. data/lib/super_diff/operation_trees/multiline_string.rb +4 -7
  91. data/lib/super_diff/operations/binary_operation.rb +1 -6
  92. data/lib/super_diff/operations/unary_operation.rb +2 -30
  93. data/lib/super_diff/recursion_guard.rb +3 -3
  94. data/lib/super_diff/rspec.rb +12 -13
  95. data/lib/super_diff/rspec/monkey_patches.rb +2 -2
  96. data/lib/super_diff/rspec/object_inspection.rb +4 -1
  97. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders.rb +44 -0
  98. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/collection_containing_exactly.rb +9 -8
  99. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/collection_including.rb +9 -8
  100. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/double.rb +103 -0
  101. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/hash_including.rb +36 -0
  102. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/instance_of.rb +3 -5
  103. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/kind_of.rb +3 -5
  104. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/object_having_attributes.rb +10 -12
  105. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/primitive.rb +10 -0
  106. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/value_within.rb +33 -0
  107. data/lib/super_diff/rspec/operation_tree_builders/collection_containing_exactly.rb +0 -3
  108. data/lib/super_diff/tiered_lines.rb +4 -0
  109. data/lib/super_diff/tiered_lines_elider.rb +490 -0
  110. data/lib/super_diff/tiered_lines_formatter.rb +79 -0
  111. data/lib/super_diff/version.rb +1 -1
  112. data/spec/examples.txt +407 -410
  113. data/spec/integration/rails/active_support_spec.rb +19 -0
  114. data/spec/integration/rspec/contain_exactly_matcher_spec.rb +12 -6
  115. data/spec/integration/rspec/eq_matcher_spec.rb +22 -88
  116. data/spec/integration/rspec/have_attributes_matcher_spec.rb +6 -7
  117. data/spec/integration/rspec/match_array_matcher_spec.rb +14 -7
  118. data/spec/integration/rspec/match_matcher_spec.rb +10 -5
  119. data/spec/spec_helper.rb +1 -0
  120. data/spec/support/command_runner.rb +15 -25
  121. data/spec/support/helpers.rb +21 -0
  122. data/spec/support/integration/helpers.rb +2 -0
  123. data/spec/support/integration/matchers/produce_output_when_run_matcher.rb +3 -3
  124. data/spec/support/integration/test_programs/base.rb +36 -10
  125. data/spec/support/shared_examples/active_record.rb +3 -2
  126. data/spec/support/shared_examples/active_support.rb +65 -0
  127. data/spec/support/shared_examples/elided_diffs.rb +914 -0
  128. data/spec/support/shared_examples/hash_with_indifferent_access.rb +16 -16
  129. data/spec/support/unit/helpers.rb +15 -0
  130. data/spec/support/unit/matchers/match_output.rb +41 -0
  131. data/spec/unit/active_record/object_inspection_spec.rb +273 -0
  132. data/spec/unit/equality_matchers/main_spec.rb +51 -71
  133. data/spec/unit/helpers_spec.rb +61 -0
  134. data/spec/unit/operation_tree_flatteners/array_spec.rb +604 -0
  135. data/spec/unit/operation_tree_flatteners/custom_object_spec.rb +667 -0
  136. data/spec/unit/operation_tree_flatteners/default_object_spec.rb +687 -0
  137. data/spec/unit/operation_tree_flatteners/hash_spec.rb +632 -0
  138. data/spec/unit/operation_tree_flatteners/multiline_string_spec.rb +121 -0
  139. data/spec/unit/rspec/object_inspection_spec.rb +446 -0
  140. data/spec/unit/super_diff_spec.rb +1488 -846
  141. data/spec/unit/tiered_lines_elider_spec.rb +6356 -0
  142. data/spec/unit/tiered_lines_formatter_spec.rb +193 -0
  143. metadata +88 -50
  144. data/lib/super_diff/active_record/diff_formatters.rb +0 -10
  145. data/lib/super_diff/active_record/diff_formatters/active_record_relation.rb +0 -23
  146. data/lib/super_diff/active_record/object_inspection/inspectors.rb +0 -16
  147. data/lib/super_diff/active_support/diff_formatters.rb +0 -10
  148. data/lib/super_diff/active_support/diff_formatters/hash_with_indifferent_access.rb +0 -36
  149. data/lib/super_diff/active_support/object_inspection/inspectors/hash_with_indifferent_access.rb +0 -28
  150. data/lib/super_diff/diff_formatters.rb +0 -14
  151. data/lib/super_diff/diff_formatters/array.rb +0 -21
  152. data/lib/super_diff/diff_formatters/base.rb +0 -33
  153. data/lib/super_diff/diff_formatters/custom_object.rb +0 -30
  154. data/lib/super_diff/diff_formatters/default_object.rb +0 -46
  155. data/lib/super_diff/diff_formatters/defaults.rb +0 -10
  156. data/lib/super_diff/diff_formatters/hash.rb +0 -34
  157. data/lib/super_diff/diff_formatters/main.rb +0 -41
  158. data/lib/super_diff/object_inspection/inspectors.rb +0 -23
  159. data/lib/super_diff/object_inspection/inspectors/array.rb +0 -32
  160. data/lib/super_diff/object_inspection/inspectors/base.rb +0 -36
  161. data/lib/super_diff/object_inspection/inspectors/custom_object.rb +0 -37
  162. data/lib/super_diff/object_inspection/inspectors/default_object.rb +0 -61
  163. data/lib/super_diff/object_inspection/inspectors/hash.rb +0 -32
  164. data/lib/super_diff/object_inspection/inspectors/primitive.rb +0 -28
  165. data/lib/super_diff/object_inspection/inspectors/string.rb +0 -23
  166. data/lib/super_diff/object_inspection/nodes/break.rb +0 -15
  167. data/lib/super_diff/object_inspection/nodes/when_multiline.rb +0 -22
  168. data/lib/super_diff/object_inspection/nodes/when_singleline.rb +0 -24
  169. data/lib/super_diff/rspec/object_inspection/inspectors.rb +0 -40
  170. data/lib/super_diff/rspec/object_inspection/inspectors/hash_including.rb +0 -36
  171. data/lib/super_diff/rspec/object_inspection/inspectors/primitive.rb +0 -13
  172. data/lib/super_diff/rspec/object_inspection/inspectors/value_within.rb +0 -29
  173. data/spec/support/object_id.rb +0 -27
  174. data/spec/support/ruby_versions.rb +0 -11
@@ -0,0 +1,667 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe SuperDiff::OperationTreeFlatteners::CustomObject do
4
+ context "given an empty tree" do
5
+ it "returns a set of lines which are simply the open token and close token" do
6
+ operation_tree = SuperDiff::OperationTrees::CustomObject.new(
7
+ [],
8
+ underlying_object: underlying_object,
9
+ )
10
+
11
+ flattened_operation_tree = described_class.call(operation_tree)
12
+
13
+ expect(flattened_operation_tree).to match([
14
+ an_object_having_attributes(
15
+ type: :noop,
16
+ indentation_level: 0,
17
+ prefix: "",
18
+ value: %(#<SuperDiff::Test::Person {),
19
+ collection_bookend: :open,
20
+ complete_bookend: :open,
21
+ ),
22
+ an_object_having_attributes(
23
+ type: :noop,
24
+ indentation_level: 0,
25
+ prefix: "",
26
+ value: %(}>),
27
+ collection_bookend: :close,
28
+ complete_bookend: :close,
29
+ ),
30
+ ])
31
+ end
32
+ end
33
+
34
+ context "given a tree of only noops" do
35
+ it "returns a series of lines from inspecting each value, creating multiple lines upon encountering inner data structures" do
36
+ collection = Array.new(3) { :some_value }
37
+ operation_tree = SuperDiff::OperationTrees::CustomObject.new(
38
+ [
39
+ double(
40
+ :operation,
41
+ name: :noop,
42
+ collection: collection,
43
+ key: :foo,
44
+ value: "bar",
45
+ index: 0,
46
+ ),
47
+ double(
48
+ :operation,
49
+ name: :noop,
50
+ collection: collection,
51
+ key: :baz,
52
+ value: SuperDiff::Test::Person.new(name: 'Emily', age: 15),
53
+ index: 1,
54
+ ),
55
+ double(
56
+ :operation,
57
+ name: :noop,
58
+ collection: collection,
59
+ key: :qux,
60
+ value: "blargh",
61
+ index: 2,
62
+ ),
63
+ ],
64
+ underlying_object: underlying_object
65
+ )
66
+
67
+ flattened_operation_tree = described_class.call(operation_tree)
68
+
69
+ expect(flattened_operation_tree).to match([
70
+ an_object_having_attributes(
71
+ type: :noop,
72
+ indentation_level: 0,
73
+ prefix: "",
74
+ value: %(#<SuperDiff::Test::Person {),
75
+ collection_bookend: :open,
76
+ complete_bookend: :open,
77
+ add_comma: false,
78
+ ),
79
+ an_object_having_attributes(
80
+ type: :noop,
81
+ indentation_level: 1,
82
+ prefix: %(foo: ),
83
+ value: %("bar"),
84
+ add_comma: true,
85
+ ),
86
+ an_object_having_attributes(
87
+ type: :noop,
88
+ indentation_level: 1,
89
+ prefix: %(baz: ),
90
+ value: %(#<SuperDiff::Test::Person {),
91
+ collection_bookend: :open,
92
+ complete_bookend: nil,
93
+ add_comma: false,
94
+ ),
95
+ an_object_having_attributes(
96
+ type: :noop,
97
+ indentation_level: 2,
98
+ prefix: %(name: ),
99
+ value: %("Emily"),
100
+ add_comma: true,
101
+ ),
102
+ an_object_having_attributes(
103
+ type: :noop,
104
+ indentation_level: 2,
105
+ prefix: %(age: ),
106
+ value: %(15),
107
+ add_comma: false,
108
+ ),
109
+ an_object_having_attributes(
110
+ type: :noop,
111
+ indentation_level: 1,
112
+ prefix: "",
113
+ value: %(}>),
114
+ collection_bookend: :close,
115
+ complete_bookend: nil,
116
+ add_comma: true,
117
+ ),
118
+ an_object_having_attributes(
119
+ type: :noop,
120
+ indentation_level: 1,
121
+ prefix: %(qux: ),
122
+ value: %("blargh"),
123
+ add_comma: false,
124
+ ),
125
+ an_object_having_attributes(
126
+ type: :noop,
127
+ indentation_level: 0,
128
+ prefix: "",
129
+ value: %(}>),
130
+ collection_bookend: :close,
131
+ complete_bookend: :close,
132
+ add_comma: false,
133
+ ),
134
+ ])
135
+ end
136
+ end
137
+
138
+ context "given a one-dimensional tree of noops, inserts, and deletes" do
139
+ it "returns a series of lines from inspecting each value, creating multiple lines upon encountering inner data structures" do
140
+ expected = Array.new(3) { :some_value }
141
+ actual = Array.new(4) { :some_value }
142
+ operation_tree = SuperDiff::OperationTrees::CustomObject.new(
143
+ [
144
+ double(
145
+ :operation,
146
+ name: :delete,
147
+ collection: expected,
148
+ key: :foo,
149
+ value: "bar",
150
+ index: 0,
151
+ ),
152
+ double(
153
+ :operation,
154
+ name: :insert,
155
+ collection: actual,
156
+ key: :foo,
157
+ value: "czar",
158
+ index: 0,
159
+ ),
160
+ double(
161
+ :operation,
162
+ name: :noop,
163
+ collection: actual,
164
+ key: :baz,
165
+ value: SuperDiff::Test::Person.new(name: 'Emily', age: 15),
166
+ index: 1,
167
+ ),
168
+ double(
169
+ :operation,
170
+ name: :noop,
171
+ collection: actual,
172
+ key: :qux,
173
+ value: "blargh",
174
+ index: 2,
175
+ ),
176
+ double(
177
+ :operation,
178
+ name: :insert,
179
+ collection: actual,
180
+ key: :sing,
181
+ value: "song",
182
+ index: 3,
183
+ ),
184
+ ],
185
+ underlying_object: underlying_object
186
+ )
187
+
188
+ flattened_operation_tree = described_class.call(operation_tree)
189
+
190
+ expect(flattened_operation_tree).to match([
191
+ an_object_having_attributes(
192
+ type: :noop,
193
+ indentation_level: 0,
194
+ prefix: "",
195
+ value: %(#<SuperDiff::Test::Person {),
196
+ collection_bookend: :open,
197
+ complete_bookend: :open,
198
+ add_comma: false,
199
+ ),
200
+ an_object_having_attributes(
201
+ type: :delete,
202
+ indentation_level: 1,
203
+ prefix: %(foo: ),
204
+ value: %("bar"),
205
+ add_comma: true,
206
+ ),
207
+ an_object_having_attributes(
208
+ type: :insert,
209
+ indentation_level: 1,
210
+ prefix: %(foo: ),
211
+ value: %("czar"),
212
+ add_comma: true,
213
+ ),
214
+ an_object_having_attributes(
215
+ type: :noop,
216
+ indentation_level: 1,
217
+ prefix: %(baz: ),
218
+ value: %(#<SuperDiff::Test::Person {),
219
+ collection_bookend: :open,
220
+ complete_bookend: nil,
221
+ add_comma: false,
222
+ ),
223
+ an_object_having_attributes(
224
+ type: :noop,
225
+ indentation_level: 2,
226
+ prefix: %(name: ),
227
+ value: %("Emily"),
228
+ add_comma: true,
229
+ ),
230
+ an_object_having_attributes(
231
+ type: :noop,
232
+ indentation_level: 2,
233
+ prefix: %(age: ),
234
+ value: %(15),
235
+ add_comma: false,
236
+ ),
237
+ an_object_having_attributes(
238
+ type: :noop,
239
+ indentation_level: 1,
240
+ prefix: "",
241
+ value: %(}>),
242
+ collection_bookend: :close,
243
+ complete_bookend: nil,
244
+ add_comma: true,
245
+ ),
246
+ an_object_having_attributes(
247
+ type: :noop,
248
+ indentation_level: 1,
249
+ prefix: %(qux: ),
250
+ value: %("blargh"),
251
+ add_comma: true,
252
+ ),
253
+ an_object_having_attributes(
254
+ type: :insert,
255
+ indentation_level: 1,
256
+ prefix: %(sing: ),
257
+ value: %("song"),
258
+ add_comma: false,
259
+ ),
260
+ an_object_having_attributes(
261
+ type: :noop,
262
+ indentation_level: 0,
263
+ prefix: "",
264
+ value: %(}>),
265
+ collection_bookend: :close,
266
+ complete_bookend: :close,
267
+ add_comma: false,
268
+ ),
269
+ ])
270
+ end
271
+ end
272
+
273
+ context "given a multi-dimensional tree of operations" do
274
+ it "splits change operations into multiple lines" do
275
+ collection = Array.new(3) { :some_value }
276
+ subcollection = Array.new(2) { :some_value }
277
+ operation_tree = SuperDiff::OperationTrees::CustomObject.new(
278
+ [
279
+ double(
280
+ :operation,
281
+ name: :noop,
282
+ collection: collection,
283
+ key: :foo,
284
+ value: "bar",
285
+ index: 0,
286
+ ),
287
+ double(
288
+ :operation,
289
+ name: :change,
290
+ left_collection: collection,
291
+ left_key: :baz,
292
+ left_index: 1,
293
+ right_collection: collection,
294
+ right_key: :baz,
295
+ right_index: 1,
296
+ children: SuperDiff::OperationTrees::CustomObject.new(
297
+ [
298
+ double(
299
+ :operation,
300
+ name: :noop,
301
+ collection: subcollection,
302
+ key: :one,
303
+ value: "fish",
304
+ index: 0,
305
+ ),
306
+ double(
307
+ :operation,
308
+ name: :delete,
309
+ collection: subcollection,
310
+ key: :two,
311
+ value: "fish",
312
+ index: 1,
313
+ ),
314
+ double(
315
+ :operation,
316
+ name: :insert,
317
+ collection: subcollection,
318
+ key: :blue,
319
+ value: "fish",
320
+ index: 1,
321
+ ),
322
+ ],
323
+ underlying_object: underlying_object,
324
+ ),
325
+ ),
326
+ double(
327
+ :operation,
328
+ name: :noop,
329
+ collection: collection,
330
+ key: :qux,
331
+ value: "blargh",
332
+ index: 2,
333
+ ),
334
+ ],
335
+ underlying_object: underlying_object
336
+ )
337
+
338
+ flattened_operation_tree = described_class.call(operation_tree)
339
+
340
+ expect(flattened_operation_tree).to match([
341
+ an_object_having_attributes(
342
+ type: :noop,
343
+ indentation_level: 0,
344
+ prefix: "",
345
+ value: %(#<SuperDiff::Test::Person {),
346
+ collection_bookend: :open,
347
+ complete_bookend: :open,
348
+ add_comma: false,
349
+ ),
350
+ an_object_having_attributes(
351
+ type: :noop,
352
+ indentation_level: 1,
353
+ prefix: %(foo: ),
354
+ value: %("bar"),
355
+ add_comma: true,
356
+ ),
357
+ an_object_having_attributes(
358
+ type: :noop,
359
+ indentation_level: 1,
360
+ prefix: %(baz: ),
361
+ value: %(#<SuperDiff::Test::Person {),
362
+ collection_bookend: :open,
363
+ complete_bookend: nil,
364
+ add_comma: false,
365
+ ),
366
+ an_object_having_attributes(
367
+ type: :noop,
368
+ indentation_level: 2,
369
+ prefix: %(one: ),
370
+ value: %("fish"),
371
+ add_comma: true,
372
+ ),
373
+ an_object_having_attributes(
374
+ type: :delete,
375
+ indentation_level: 2,
376
+ prefix: %(two: ),
377
+ value: %("fish"),
378
+ add_comma: false,
379
+ ),
380
+ an_object_having_attributes(
381
+ type: :insert,
382
+ indentation_level: 2,
383
+ prefix: %(blue: ),
384
+ value: %("fish"),
385
+ add_comma: false,
386
+ ),
387
+ an_object_having_attributes(
388
+ type: :noop,
389
+ indentation_level: 1,
390
+ prefix: "",
391
+ value: %(}>),
392
+ collection_bookend: :close,
393
+ complete_bookend: nil,
394
+ add_comma: true,
395
+ ),
396
+ an_object_having_attributes(
397
+ type: :noop,
398
+ indentation_level: 1,
399
+ prefix: %(qux: ),
400
+ value: %("blargh"),
401
+ add_comma: false,
402
+ ),
403
+ an_object_having_attributes(
404
+ type: :noop,
405
+ indentation_level: 0,
406
+ prefix: "",
407
+ value: %(}>),
408
+ collection_bookend: :close,
409
+ complete_bookend: :close,
410
+ add_comma: false,
411
+ ),
412
+ ])
413
+ end
414
+ end
415
+
416
+ context "given a single-dimensional tree that contains a reference to itself" do
417
+ it "replaces the reference with a static placeholder" do
418
+ left_collection = Array.new(3) { :some_value }
419
+ right_collection = Array.new(2) { :some_value }.tap do |collection|
420
+ collection << right_collection
421
+ end
422
+
423
+ operation_tree = SuperDiff::OperationTrees::CustomObject.new(
424
+ [
425
+ double(
426
+ :operation,
427
+ name: :noop,
428
+ collection: right_collection,
429
+ key: :foo,
430
+ value: "bar",
431
+ index: 0,
432
+ ),
433
+ double(
434
+ :operation,
435
+ name: :noop,
436
+ collection: right_collection,
437
+ key: :baz,
438
+ value: "qux",
439
+ index: 1,
440
+ ),
441
+ double(
442
+ :operation,
443
+ name: :delete,
444
+ collection: left_collection,
445
+ key: :blargh,
446
+ value: "zig",
447
+ index: 2,
448
+ ),
449
+ double(
450
+ :operation,
451
+ name: :insert,
452
+ collection: right_collection,
453
+ key: :zing,
454
+ value: right_collection,
455
+ index: 2,
456
+ ),
457
+ ],
458
+ underlying_object: underlying_object,
459
+ )
460
+
461
+ flattened_operation_tree = described_class.call(operation_tree)
462
+
463
+ expect(flattened_operation_tree).to match([
464
+ an_object_having_attributes(
465
+ type: :noop,
466
+ indentation_level: 0,
467
+ prefix: "",
468
+ value: %(#<SuperDiff::Test::Person {),
469
+ collection_bookend: :open,
470
+ complete_bookend: :open,
471
+ add_comma: false,
472
+ ),
473
+ an_object_having_attributes(
474
+ type: :noop,
475
+ indentation_level: 1,
476
+ prefix: %(foo: ),
477
+ value: %("bar"),
478
+ add_comma: true,
479
+ ),
480
+ an_object_having_attributes(
481
+ type: :noop,
482
+ indentation_level: 1,
483
+ prefix: %(baz: ),
484
+ value: %("qux"),
485
+ add_comma: true,
486
+ ),
487
+ an_object_having_attributes(
488
+ type: :delete,
489
+ indentation_level: 1,
490
+ prefix: %(blargh: ),
491
+ value: %("zig"),
492
+ add_comma: false,
493
+ ),
494
+ an_object_having_attributes(
495
+ type: :insert,
496
+ indentation_level: 1,
497
+ prefix: %(zing: ),
498
+ value: %(∙∙∙),
499
+ add_comma: false,
500
+ ),
501
+ an_object_having_attributes(
502
+ type: :noop,
503
+ indentation_level: 0,
504
+ prefix: "",
505
+ value: %(}>),
506
+ collection_bookend: :close,
507
+ complete_bookend: :close,
508
+ add_comma: false,
509
+ ),
510
+ ])
511
+ end
512
+ end
513
+
514
+ context "given a multi-dimensional tree that contains a reference to itself in an inner level" do
515
+ it "replaces the reference with a static placeholder" do
516
+ collection = Array.new(3) { :some_value }
517
+ left_subcollection = Array.new(2) { :some_value }
518
+ right_subcollection = Array.new(1) { :some_value }.tap do |coll|
519
+ coll << right_subcollection
520
+ end
521
+
522
+ operation_tree = SuperDiff::OperationTrees::CustomObject.new(
523
+ [
524
+ double(
525
+ :operation,
526
+ name: :noop,
527
+ collection: collection,
528
+ key: :foo,
529
+ value: "bar",
530
+ index: 0,
531
+ ),
532
+ double(
533
+ :operation,
534
+ name: :change,
535
+ left_collection: collection,
536
+ left_key: :baz,
537
+ left_index: 1,
538
+ right_collection: collection,
539
+ right_key: :baz,
540
+ right_index: 1,
541
+ children: SuperDiff::OperationTrees::CustomObject.new(
542
+ [
543
+ double(
544
+ :operation,
545
+ name: :noop,
546
+ collection: right_subcollection,
547
+ key: :one,
548
+ value: "fish",
549
+ index: 0,
550
+ ),
551
+ double(
552
+ :operation,
553
+ name: :delete,
554
+ collection: left_subcollection,
555
+ key: :two,
556
+ value: "fish",
557
+ index: 1,
558
+ ),
559
+ double(
560
+ :operation,
561
+ name: :insert,
562
+ collection: right_subcollection,
563
+ key: :two,
564
+ value: right_subcollection,
565
+ index: 1,
566
+ ),
567
+ ],
568
+ underlying_object: underlying_object,
569
+ ),
570
+ ),
571
+ double(
572
+ :operation,
573
+ name: :noop,
574
+ collection: collection,
575
+ key: :qux,
576
+ value: "blargh",
577
+ index: 2,
578
+ ),
579
+ ],
580
+ underlying_object: underlying_object,
581
+ )
582
+
583
+ flattened_operation_tree = described_class.call(operation_tree)
584
+
585
+ expect(flattened_operation_tree).to match([
586
+ an_object_having_attributes(
587
+ type: :noop,
588
+ indentation_level: 0,
589
+ prefix: "",
590
+ value: %(#<SuperDiff::Test::Person {),
591
+ collection_bookend: :open,
592
+ complete_bookend: :open,
593
+ add_comma: false,
594
+ ),
595
+ an_object_having_attributes(
596
+ type: :noop,
597
+ indentation_level: 1,
598
+ prefix: %(foo: ),
599
+ value: %("bar"),
600
+ add_comma: true,
601
+ ),
602
+ an_object_having_attributes(
603
+ type: :noop,
604
+ indentation_level: 1,
605
+ prefix: %(baz: ),
606
+ value: %(#<SuperDiff::Test::Person {),
607
+ collection_bookend: :open,
608
+ complete_bookend: nil,
609
+ add_comma: false,
610
+ ),
611
+ an_object_having_attributes(
612
+ type: :noop,
613
+ indentation_level: 2,
614
+ prefix: %(one: ),
615
+ value: %("fish"),
616
+ add_comma: true,
617
+ ),
618
+ an_object_having_attributes(
619
+ type: :delete,
620
+ indentation_level: 2,
621
+ prefix: %(two: ),
622
+ value: %("fish"),
623
+ add_comma: false,
624
+ ),
625
+ an_object_having_attributes(
626
+ type: :insert,
627
+ indentation_level: 2,
628
+ prefix: %(two: ),
629
+ value: %(∙∙∙),
630
+ add_comma: false,
631
+ ),
632
+ an_object_having_attributes(
633
+ type: :noop,
634
+ indentation_level: 1,
635
+ prefix: "",
636
+ value: %(}>),
637
+ collection_bookend: :close,
638
+ complete_bookend: nil,
639
+ add_comma: true,
640
+ ),
641
+ an_object_having_attributes(
642
+ type: :noop,
643
+ indentation_level: 1,
644
+ prefix: %(qux: ),
645
+ value: %("blargh"),
646
+ add_comma: false,
647
+ ),
648
+ an_object_having_attributes(
649
+ type: :noop,
650
+ indentation_level: 0,
651
+ prefix: "",
652
+ value: %(}>),
653
+ collection_bookend: :close,
654
+ complete_bookend: :close,
655
+ add_comma: false,
656
+ ),
657
+ ])
658
+ end
659
+ end
660
+
661
+ def underlying_object
662
+ @_underlying_object ||= SuperDiff::Test::Person.new(
663
+ name: 'whatever',
664
+ age: 30,
665
+ )
666
+ end
667
+ end