super_diff 0.1.0 → 0.2.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.
Files changed (206) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +117 -89
  3. data/lib/super_diff.rb +33 -47
  4. data/lib/super_diff/active_record.rb +41 -0
  5. data/lib/super_diff/active_record/diff_formatters.rb +10 -0
  6. data/lib/super_diff/active_record/diff_formatters/active_record_relation.rb +23 -0
  7. data/lib/super_diff/active_record/differs.rb +10 -0
  8. data/lib/super_diff/active_record/differs/active_record_relation.rb +30 -0
  9. data/lib/super_diff/active_record/object_inspection.rb +14 -0
  10. data/lib/super_diff/active_record/object_inspection/inspectors.rb +16 -0
  11. data/lib/super_diff/active_record/object_inspection/inspectors/active_record_model.rb +38 -0
  12. data/lib/super_diff/active_record/object_inspection/inspectors/active_record_relation.rb +18 -0
  13. data/lib/super_diff/active_record/object_inspection/map_extension.rb +18 -0
  14. data/lib/super_diff/active_record/operation_sequences.rb +10 -0
  15. data/lib/super_diff/active_record/operation_sequences/active_record_relation.rb +16 -0
  16. data/lib/super_diff/active_record/operational_sequencers.rb +14 -0
  17. data/lib/super_diff/active_record/operational_sequencers/active_record_model.rb +19 -0
  18. data/lib/super_diff/active_record/operational_sequencers/active_record_relation.rb +24 -0
  19. data/lib/super_diff/active_support.rb +33 -0
  20. data/lib/super_diff/active_support/diff_formatters.rb +10 -0
  21. data/lib/super_diff/active_support/diff_formatters/hash_with_indifferent_access.rb +36 -0
  22. data/lib/super_diff/active_support/differs.rb +10 -0
  23. data/lib/super_diff/active_support/differs/hash_with_indifferent_access.rb +36 -0
  24. data/lib/super_diff/active_support/object_inspection.rb +14 -0
  25. data/lib/super_diff/active_support/object_inspection/inspectors.rb +12 -0
  26. data/lib/super_diff/active_support/object_inspection/inspectors/hash_with_indifferent_access.rb +18 -0
  27. data/lib/super_diff/active_support/object_inspection/map_extension.rb +15 -0
  28. data/lib/super_diff/active_support/operation_sequences.rb +10 -0
  29. data/lib/super_diff/active_support/operation_sequences/hash_with_indifferent_access.rb +16 -0
  30. data/lib/super_diff/active_support/operational_sequencers.rb +10 -0
  31. data/lib/super_diff/active_support/operational_sequencers/hash_with_indifferent_access.rb +21 -0
  32. data/lib/super_diff/colorized_document_extensions.rb +17 -0
  33. data/lib/super_diff/csi.rb +45 -15
  34. data/lib/super_diff/csi/bold_sequence.rb +9 -0
  35. data/lib/super_diff/csi/color.rb +62 -0
  36. data/lib/super_diff/csi/color_sequence_block.rb +28 -0
  37. data/lib/super_diff/csi/colorized_document.rb +72 -0
  38. data/lib/super_diff/csi/document.rb +183 -0
  39. data/lib/super_diff/csi/eight_bit_color.rb +72 -26
  40. data/lib/super_diff/csi/four_bit_color.rb +63 -29
  41. data/lib/super_diff/csi/twenty_four_bit_color.rb +79 -18
  42. data/lib/super_diff/csi/uncolorized_document.rb +29 -0
  43. data/lib/super_diff/diff_formatter.rb +10 -15
  44. data/lib/super_diff/diff_formatters.rb +10 -1
  45. data/lib/super_diff/diff_formatters/base.rb +12 -17
  46. data/lib/super_diff/diff_formatters/collection.rb +81 -50
  47. data/lib/super_diff/diff_formatters/{object.rb → custom_object.rb} +12 -9
  48. data/lib/super_diff/diff_formatters/default_object.rb +48 -0
  49. data/lib/super_diff/diff_formatters/multiline_string.rb +31 -0
  50. data/lib/super_diff/differ.rb +35 -32
  51. data/lib/super_diff/differs.rb +16 -1
  52. data/lib/super_diff/differs/array.rb +2 -2
  53. data/lib/super_diff/differs/base.rb +11 -21
  54. data/lib/super_diff/differs/custom_object.rb +26 -0
  55. data/lib/super_diff/differs/default_object.rb +25 -0
  56. data/lib/super_diff/differs/empty.rb +1 -1
  57. data/lib/super_diff/differs/hash.rb +2 -2
  58. data/lib/super_diff/differs/{multi_line_string.rb → multiline_string.rb} +6 -5
  59. data/lib/super_diff/equality_matcher.rb +9 -22
  60. data/lib/super_diff/equality_matchers.rb +19 -1
  61. data/lib/super_diff/equality_matchers/array.rb +6 -4
  62. data/lib/super_diff/equality_matchers/base.rb +8 -16
  63. data/lib/super_diff/equality_matchers/default.rb +60 -0
  64. data/lib/super_diff/equality_matchers/hash.rb +6 -4
  65. data/lib/super_diff/equality_matchers/{multi_line_string.rb → multiline_string.rb} +9 -6
  66. data/lib/super_diff/equality_matchers/primitive.rb +34 -0
  67. data/lib/super_diff/equality_matchers/{single_line_string.rb → singleline_string.rb} +7 -5
  68. data/lib/super_diff/helpers.rb +17 -81
  69. data/lib/super_diff/no_differ_available_error.rb +22 -0
  70. data/lib/super_diff/{errors.rb → no_operational_sequencer_available_error.rb} +0 -0
  71. data/lib/super_diff/object_inspection.rb +24 -0
  72. data/lib/super_diff/object_inspection/inspection_tree.rb +144 -0
  73. data/lib/super_diff/object_inspection/inspector.rb +27 -0
  74. data/lib/super_diff/object_inspection/inspectors.rb +18 -0
  75. data/lib/super_diff/object_inspection/inspectors/array.rb +22 -0
  76. data/lib/super_diff/object_inspection/inspectors/custom_object.rb +27 -0
  77. data/lib/super_diff/object_inspection/inspectors/default_object.rb +47 -0
  78. data/lib/super_diff/object_inspection/inspectors/hash.rb +22 -0
  79. data/lib/super_diff/object_inspection/inspectors/primitive.rb +13 -0
  80. data/lib/super_diff/object_inspection/inspectors/string.rb +13 -0
  81. data/lib/super_diff/object_inspection/map.rb +28 -0
  82. data/lib/super_diff/object_inspection/nodes.rb +49 -0
  83. data/lib/super_diff/object_inspection/nodes/base.rb +86 -0
  84. data/lib/super_diff/object_inspection/nodes/break.rb +15 -0
  85. data/lib/super_diff/object_inspection/nodes/inspection.rb +15 -0
  86. data/lib/super_diff/object_inspection/nodes/nesting.rb +16 -0
  87. data/lib/super_diff/object_inspection/nodes/text.rb +15 -0
  88. data/lib/super_diff/object_inspection/nodes/when_empty.rb +30 -0
  89. data/lib/super_diff/object_inspection/nodes/when_multiline.rb +22 -0
  90. data/lib/super_diff/object_inspection/nodes/when_non_empty.rb +30 -0
  91. data/lib/super_diff/object_inspection/nodes/when_singleline.rb +24 -0
  92. data/lib/super_diff/operation_sequences.rb +9 -0
  93. data/lib/super_diff/operation_sequences/base.rb +1 -1
  94. data/lib/super_diff/operation_sequences/{object.rb → custom_object.rb} +4 -3
  95. data/lib/super_diff/operation_sequences/default_object.rb +25 -0
  96. data/lib/super_diff/operational_sequencer.rb +23 -18
  97. data/lib/super_diff/operational_sequencers.rb +12 -1
  98. data/lib/super_diff/operational_sequencers/array.rb +65 -62
  99. data/lib/super_diff/operational_sequencers/base.rb +18 -26
  100. data/lib/super_diff/operational_sequencers/custom_object.rb +35 -0
  101. data/lib/super_diff/operational_sequencers/{object.rb → default_object.rb} +21 -11
  102. data/lib/super_diff/operational_sequencers/hash.rb +8 -5
  103. data/lib/super_diff/operational_sequencers/{multi_line_string.rb → multiline_string.rb} +11 -6
  104. data/lib/super_diff/operations.rb +6 -0
  105. data/lib/super_diff/operations/binary_operation.rb +14 -34
  106. data/lib/super_diff/operations/unary_operation.rb +11 -2
  107. data/lib/super_diff/rails.rb +1 -0
  108. data/lib/super_diff/recursion_guard.rb +47 -0
  109. data/lib/super_diff/rspec-rails.rb +2 -0
  110. data/lib/super_diff/rspec.rb +52 -8
  111. data/lib/super_diff/rspec/augmented_matcher.rb +98 -0
  112. data/lib/super_diff/rspec/configuration.rb +31 -0
  113. data/lib/super_diff/rspec/differ.rb +60 -16
  114. data/lib/super_diff/rspec/differs.rb +13 -0
  115. data/lib/super_diff/rspec/differs/collection_containing_exactly.rb +23 -0
  116. data/lib/super_diff/rspec/differs/partial_array.rb +22 -0
  117. data/lib/super_diff/rspec/differs/partial_hash.rb +22 -0
  118. data/lib/super_diff/rspec/differs/partial_object.rb +22 -0
  119. data/lib/super_diff/rspec/matcher_text_builders.rb +24 -0
  120. data/lib/super_diff/rspec/matcher_text_builders/base.rb +155 -0
  121. data/lib/super_diff/rspec/matcher_text_builders/be_predicate.rb +78 -0
  122. data/lib/super_diff/rspec/matcher_text_builders/contain_exactly.rb +14 -0
  123. data/lib/super_diff/rspec/matcher_text_builders/match.rb +23 -0
  124. data/lib/super_diff/rspec/matcher_text_builders/raise_error.rb +13 -0
  125. data/lib/super_diff/rspec/matcher_text_builders/respond_to.rb +99 -0
  126. data/lib/super_diff/rspec/matcher_text_template.rb +240 -0
  127. data/lib/super_diff/rspec/monkey_patches.rb +601 -98
  128. data/lib/super_diff/rspec/object_inspection.rb +8 -0
  129. data/lib/super_diff/rspec/object_inspection/inspectors.rb +24 -0
  130. data/lib/super_diff/rspec/object_inspection/inspectors/collection_containing_exactly.rb +19 -0
  131. data/lib/super_diff/rspec/object_inspection/inspectors/partial_array.rb +22 -0
  132. data/lib/super_diff/rspec/object_inspection/inspectors/partial_hash.rb +21 -0
  133. data/lib/super_diff/rspec/object_inspection/inspectors/partial_object.rb +21 -0
  134. data/lib/super_diff/rspec/object_inspection/map_extension.rb +23 -0
  135. data/lib/super_diff/rspec/operational_sequencers.rb +22 -0
  136. data/lib/super_diff/rspec/operational_sequencers/collection_containing_exactly.rb +97 -0
  137. data/lib/super_diff/rspec/operational_sequencers/partial_array.rb +23 -0
  138. data/lib/super_diff/rspec/operational_sequencers/partial_hash.rb +32 -0
  139. data/lib/super_diff/rspec/operational_sequencers/partial_object.rb +64 -0
  140. data/lib/super_diff/version.rb +1 -1
  141. data/spec/examples.txt +328 -46
  142. data/spec/integration/rails/active_record_spec.rb +19 -0
  143. data/spec/integration/rails/hash_with_indifferent_access_spec.rb +19 -0
  144. data/spec/integration/rspec/be_falsey_matcher_spec.rb +53 -0
  145. data/spec/integration/rspec/be_matcher_spec.rb +565 -0
  146. data/spec/integration/rspec/be_nil_matcher_spec.rb +53 -0
  147. data/spec/integration/rspec/be_predicate_matcher_spec.rb +546 -0
  148. data/spec/integration/rspec/be_truthy_matcher_spec.rb +57 -0
  149. data/spec/integration/rspec/contain_exactly_matcher_spec.rb +368 -0
  150. data/spec/integration/rspec/eq_matcher_spec.rb +874 -0
  151. data/spec/integration/rspec/have_attributes_matcher_spec.rb +299 -0
  152. data/spec/integration/rspec/include_matcher_spec.rb +350 -0
  153. data/spec/integration/rspec/match_matcher_spec.rb +1258 -0
  154. data/spec/integration/rspec/raise_error_matcher_spec.rb +350 -0
  155. data/spec/integration/rspec/respond_to_matcher_spec.rb +994 -0
  156. data/spec/integration/rspec/unhandled_errors_spec.rb +94 -0
  157. data/spec/spec_helper.rb +19 -4
  158. data/spec/support/colorizer.rb +9 -0
  159. data/spec/support/command_runner.rb +4 -0
  160. data/spec/support/integration/helpers.rb +179 -0
  161. data/spec/support/integration/matchers/produce_output_when_run_matcher.rb +79 -41
  162. data/spec/support/models/a.rb +11 -0
  163. data/spec/support/models/active_record/person.rb +26 -0
  164. data/spec/support/models/active_record/shipping_address.rb +29 -0
  165. data/spec/support/models/customer.rb +24 -0
  166. data/spec/support/models/empty_class.rb +6 -0
  167. data/spec/support/models/item.rb +10 -0
  168. data/spec/support/models/order.rb +9 -0
  169. data/spec/support/models/person.rb +20 -0
  170. data/spec/support/models/player.rb +33 -0
  171. data/spec/support/models/shipping_address.rb +34 -0
  172. data/spec/support/ruby_versions.rb +7 -0
  173. data/spec/support/shared_examples/active_record.rb +338 -0
  174. data/spec/support/shared_examples/hash_with_indifferent_access.rb +233 -0
  175. data/spec/unit/equality_matcher_spec.rb +579 -171
  176. data/spec/unit/object_inspection_spec.rb +1092 -0
  177. data/spec/unit/rspec/matchers/be_compared_to_spec.rb +23 -0
  178. data/spec/unit/rspec/matchers/be_falsey_spec.rb +9 -0
  179. data/spec/unit/rspec/matchers/be_nil_spec.rb +9 -0
  180. data/spec/unit/rspec/matchers/be_predicate_spec.rb +31 -0
  181. data/spec/unit/rspec/matchers/be_spec.rb +17 -0
  182. data/spec/unit/rspec/matchers/be_truthy_spec.rb +9 -0
  183. data/spec/unit/rspec/matchers/contain_exactly_spec.rb +11 -0
  184. data/spec/unit/rspec/matchers/eq_spec.rb +9 -0
  185. data/spec/unit/rspec/matchers/have_attributes_spec.rb +11 -0
  186. data/spec/unit/rspec/matchers/include_spec.rb +21 -0
  187. data/spec/unit/rspec/matchers/match_spec.rb +9 -0
  188. data/spec/unit/rspec/matchers/raise_error_spec.rb +29 -0
  189. data/spec/unit/rspec/matchers/respond_to_spec.rb +78 -0
  190. data/super_diff.gemspec +4 -2
  191. metadata +231 -34
  192. data/lib/super_diff/csi/color_helper.rb +0 -52
  193. data/lib/super_diff/csi/eight_bit_sequence.rb +0 -27
  194. data/lib/super_diff/csi/four_bit_sequence.rb +0 -24
  195. data/lib/super_diff/csi/sequence.rb +0 -22
  196. data/lib/super_diff/csi/twenty_four_bit_sequence.rb +0 -27
  197. data/lib/super_diff/diff_formatters/multi_line_string.rb +0 -31
  198. data/lib/super_diff/differs/object.rb +0 -68
  199. data/lib/super_diff/equality_matchers/object.rb +0 -18
  200. data/lib/super_diff/value_inspection.rb +0 -11
  201. data/spec/integration/rspec_spec.rb +0 -261
  202. data/spec/support/color_helper.rb +0 -49
  203. data/spec/support/person.rb +0 -23
  204. data/spec/support/person_diff_formatter.rb +0 -15
  205. data/spec/support/person_operation_sequence.rb +0 -14
  206. data/spec/support/person_operational_sequencer.rb +0 -19
@@ -1,20 +1,16 @@
1
1
  module SuperDiff
2
2
  class OperationalSequencer
3
- def self.call(*args)
4
- new(*args).call
5
- end
3
+ extend AttrExtras.mixin
6
4
 
7
- def initialize(
8
- expected:,
9
- actual:,
10
- extra_classes: [],
11
- extra_diff_formatter_classes: []
5
+ method_object(
6
+ [
7
+ :expected!,
8
+ :actual!,
9
+ :all_or_nothing!,
10
+ extra_classes: [],
11
+ extra_diff_formatter_classes: [],
12
+ ],
12
13
  )
13
- @expected = expected
14
- @actual = actual
15
- @extra_classes = extra_classes
16
- @extra_diff_formatter_classes = extra_diff_formatter_classes
17
- end
18
14
 
19
15
  def call
20
16
  if resolved_class
@@ -24,19 +20,28 @@ module SuperDiff
24
20
  extra_operational_sequencer_classes: extra_classes,
25
21
  extra_diff_formatter_classes: extra_diff_formatter_classes,
26
22
  )
27
- else
23
+ elsif all_or_nothing?
28
24
  raise NoOperationalSequencerAvailableError.create(expected, actual)
25
+ else
26
+ nil
29
27
  end
30
28
  end
31
29
 
32
30
  private
33
31
 
34
- attr_reader :expected, :actual, :extra_classes,
35
- :extra_diff_formatter_classes
32
+ attr_query :all_or_nothing?
36
33
 
37
34
  def resolved_class
38
- (OperationalSequencers::DEFAULTS + extra_classes).find do |klass|
39
- klass.applies_to?(expected) && klass.applies_to?(actual)
35
+ available_classes.find { |klass| klass.applies_to?(expected, actual) }
36
+ end
37
+
38
+ def available_classes
39
+ classes = extra_classes + OperationalSequencers::DEFAULTS
40
+
41
+ if all_or_nothing?
42
+ classes + [OperationalSequencers::DefaultObject]
43
+ else
44
+ classes
40
45
  end
41
46
  end
42
47
  end
@@ -1,5 +1,16 @@
1
1
  module SuperDiff
2
2
  module OperationalSequencers
3
- DEFAULTS = [Array, Hash].freeze
3
+ autoload :Array, "super_diff/operational_sequencers/array"
4
+ autoload :Base, "super_diff/operational_sequencers/base"
5
+ autoload :CustomObject, "super_diff/operational_sequencers/custom_object"
6
+ autoload :DefaultObject, "super_diff/operational_sequencers/default_object"
7
+ autoload :Hash, "super_diff/operational_sequencers/hash"
8
+ # TODO: Where is this used?
9
+ autoload(
10
+ :MultilineString,
11
+ "super_diff/operational_sequencers/multiline_string",
12
+ )
13
+
14
+ DEFAULTS = [Array, Hash, CustomObject].freeze
4
15
  end
5
16
  end
@@ -1,46 +1,46 @@
1
1
  module SuperDiff
2
2
  module OperationalSequencers
3
3
  class Array < Base
4
- def self.applies_to?(value)
5
- value.is_a?(::Array)
4
+ def self.applies_to?(expected, actual)
5
+ expected.is_a?(::Array) && actual.is_a?(::Array)
6
6
  end
7
7
 
8
- def initialize(*args)
9
- super(*args)
8
+ def call
9
+ Diff::LCS.traverse_balanced(expected, actual, lcs_callbacks)
10
+ operations
11
+ end
10
12
 
11
- @lcs_callbacks = LcsCallbacks.new(
13
+ private
14
+
15
+ def lcs_callbacks
16
+ @_lcs_callbacks ||= LcsCallbacks.new(
17
+ operations: operations,
12
18
  expected: expected,
13
19
  actual: actual,
14
20
  extra_operational_sequencer_classes: extra_operational_sequencer_classes,
15
21
  extra_diff_formatter_classes: extra_diff_formatter_classes,
22
+ sequence: method(:sequence),
16
23
  )
17
24
  end
18
25
 
19
- def call
20
- Diff::LCS.traverse_balanced(expected, actual, lcs_callbacks)
21
- lcs_callbacks.operations
26
+ def operations
27
+ @_operations ||= OperationSequences::Array.new([])
22
28
  end
23
29
 
24
- private
25
-
26
- attr_reader :lcs_callbacks
27
-
28
30
  class LcsCallbacks
29
- attr_reader :operations
31
+ extend AttrExtras.mixin
30
32
 
31
- def initialize(
32
- expected:,
33
- actual:,
34
- extra_operational_sequencer_classes:,
35
- extra_diff_formatter_classes:
33
+ pattr_initialize(
34
+ [
35
+ :operations!,
36
+ :expected!,
37
+ :actual!,
38
+ :extra_operational_sequencer_classes!,
39
+ :extra_diff_formatter_classes!,
40
+ :sequence!
41
+ ],
36
42
  )
37
- @expected = expected
38
- @actual = actual
39
- @operations = OperationSequences::Array.new([])
40
- @extra_operational_sequencer_classes =
41
- extra_operational_sequencer_classes
42
- @extra_diff_formatter_classes = extra_diff_formatter_classes
43
- end
43
+ public :operations
44
44
 
45
45
  def match(event)
46
46
  operations << ::SuperDiff::Operations::UnaryOperation.new(
@@ -49,6 +49,7 @@ module SuperDiff
49
49
  key: event.new_position,
50
50
  value: event.new_element,
51
51
  index: event.new_position,
52
+ index_in_collection: actual.index(event.new_element),
52
53
  )
53
54
  end
54
55
 
@@ -59,6 +60,7 @@ module SuperDiff
59
60
  key: event.old_position,
60
61
  value: event.old_element,
61
62
  index: event.old_position,
63
+ index_in_collection: expected.index(event.old_element),
62
64
  )
63
65
  end
64
66
 
@@ -69,57 +71,58 @@ module SuperDiff
69
71
  key: event.new_position,
70
72
  value: event.new_element,
71
73
  index: event.new_position,
74
+ index_in_collection: actual.index(event.new_element),
72
75
  )
73
76
  end
74
77
 
75
78
  def change(event)
76
- child_operations = sequence(event.old_element, event.new_element)
79
+ child_operations = sequence.call(event.old_element, event.new_element)
77
80
 
78
81
  if child_operations
79
- operations << ::SuperDiff::Operations::BinaryOperation.new(
80
- name: :change,
81
- left_collection: expected,
82
- right_collection: actual,
83
- left_key: event.old_position,
84
- right_key: event.new_position,
85
- left_value: event.old_element,
86
- right_value: event.new_element,
87
- left_index: event.old_position,
88
- right_index: event.new_position,
89
- child_operations: child_operations,
90
- )
82
+ add_change_operation(event, child_operations)
91
83
  else
92
- operations << Operations::UnaryOperation.new(
93
- name: :delete,
94
- collection: expected,
95
- key: event.old_position,
96
- value: event.old_element,
97
- index: event.old_position,
98
- )
99
- operations << Operations::UnaryOperation.new(
100
- name: :insert,
101
- collection: actual,
102
- key: event.new_position,
103
- value: event.new_element,
104
- index: event.new_position,
105
- )
84
+ add_delete_operation(event)
85
+ add_insert_operation(event)
106
86
  end
107
87
  end
108
88
 
109
89
  private
110
90
 
111
- attr_reader :expected, :actual, :extra_operational_sequencer_classes,
112
- :extra_diff_formatter_classes
91
+ def add_change_operation(event, child_operations)
92
+ operations << ::SuperDiff::Operations::BinaryOperation.new(
93
+ name: :change,
94
+ left_collection: expected,
95
+ right_collection: actual,
96
+ left_key: event.old_position,
97
+ right_key: event.new_position,
98
+ left_value: event.old_element,
99
+ right_value: event.new_element,
100
+ left_index: event.old_position,
101
+ right_index: event.new_position,
102
+ child_operations: child_operations,
103
+ )
104
+ end
105
+
106
+ def add_delete_operation(event)
107
+ operations << Operations::UnaryOperation.new(
108
+ name: :delete,
109
+ collection: expected,
110
+ key: event.old_position,
111
+ value: event.old_element,
112
+ index: event.old_position,
113
+ index_in_collection: expected.index(event.old_element),
114
+ )
115
+ end
113
116
 
114
- def sequence(expected, actual)
115
- OperationalSequencer.call(
116
- expected: expected,
117
- actual: actual,
118
- extra_classes: extra_operational_sequencer_classes,
119
- extra_diff_formatter_classes: extra_diff_formatter_classes,
117
+ def add_insert_operation(event)
118
+ operations << Operations::UnaryOperation.new(
119
+ name: :insert,
120
+ collection: actual,
121
+ key: event.new_position,
122
+ value: event.new_element,
123
+ index: event.new_position,
124
+ index_in_collection: actual.index(event.new_element),
120
125
  )
121
- rescue NoOperationalSequencerAvailableError
122
- nil
123
126
  end
124
127
  end
125
128
  end
@@ -1,30 +1,24 @@
1
1
  module SuperDiff
2
2
  module OperationalSequencers
3
3
  class Base
4
- def self.applies_to?(_value)
4
+ def self.applies_to?(_expected, _actual)
5
5
  raise NotImplementedError
6
6
  end
7
7
 
8
- def self.call(*args)
9
- new(*args).call
10
- end
8
+ extend AttrExtras.mixin
11
9
 
12
- def initialize(
13
- expected:,
14
- actual:,
15
- extra_operational_sequencer_classes: [],
16
- extra_diff_formatter_classes: []
10
+ method_object(
11
+ [
12
+ :expected!,
13
+ :actual!,
14
+ extra_operational_sequencer_classes: [],
15
+ extra_diff_formatter_classes: [],
16
+ ],
17
17
  )
18
- @expected = expected
19
- @actual = actual
20
- @extra_operational_sequencer_classes =
21
- extra_operational_sequencer_classes
22
- @extra_diff_formatter_classes = extra_diff_formatter_classes
23
- end
24
18
 
25
19
  def call
26
20
  i = 0
27
- operations = operation_sequence_class.new([])
21
+ operations = build_operation_sequencer
28
22
 
29
23
  while i < unary_operations.length
30
24
  operation = unary_operations[i]
@@ -60,18 +54,17 @@ module SuperDiff
60
54
  raise NotImplementedError
61
55
  end
62
56
 
63
- def operation_sequence_class
57
+ def build_operation_sequencer
64
58
  raise NotImplementedError
65
59
  end
66
60
 
67
61
  private
68
62
 
69
- attr_reader :expected, :actual, :extra_operational_sequencer_classes,
70
- :extra_diff_formatter_classes
71
-
72
63
  def possible_comparison_of(operation, next_operation)
73
64
  if should_compare?(operation, next_operation)
74
- sequence(operation, next_operation)
65
+ sequence(operation.value, next_operation.value)
66
+ else
67
+ nil
75
68
  end
76
69
  end
77
70
 
@@ -82,15 +75,14 @@ module SuperDiff
82
75
  next_operation.index == operation.index
83
76
  end
84
77
 
85
- def sequence(operation, next_operation)
78
+ def sequence(expected, actual)
86
79
  OperationalSequencer.call(
87
- expected: operation.value,
88
- actual: next_operation.value,
80
+ expected: expected,
81
+ actual: actual,
82
+ all_or_nothing: false,
89
83
  extra_classes: extra_operational_sequencer_classes,
90
84
  extra_diff_formatter_classes: extra_diff_formatter_classes,
91
85
  )
92
- rescue NoOperationalSequencerAvailableError
93
- nil
94
86
  end
95
87
  end
96
88
  end
@@ -0,0 +1,35 @@
1
+ module SuperDiff
2
+ module OperationalSequencers
3
+ class CustomObject < DefaultObject
4
+ def self.applies_to?(expected, actual)
5
+ expected.class == actual.class &&
6
+ expected.respond_to?(:attributes_for_super_diff) &&
7
+ actual.respond_to?(:attributes_for_super_diff)
8
+ end
9
+
10
+ def build_operation_sequencer
11
+ # XXX This assumes that `expected` and `actual` are the same
12
+ OperationSequences::CustomObject.new([], value_class: expected.class)
13
+ end
14
+
15
+ def attribute_names
16
+ expected.attributes_for_super_diff.keys &
17
+ actual.attributes_for_super_diff.keys
18
+ end
19
+
20
+ private
21
+
22
+ attr_reader :expected_attributes, :actual_attributes
23
+
24
+ def establish_expected_and_actual_attributes
25
+ @expected_attributes = attribute_names.reduce({}) do |hash, name|
26
+ hash.merge(name => expected.public_send(name))
27
+ end
28
+
29
+ @actual_attributes = attribute_names.reduce({}) do |hash, name|
30
+ hash.merge(name => actual.public_send(name))
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -1,16 +1,14 @@
1
1
  module SuperDiff
2
2
  module OperationalSequencers
3
- class Object < Base
3
+ class DefaultObject < Base
4
+ def self.applies_to?(_expected, _actual)
5
+ true
6
+ end
7
+
4
8
  def initialize(*args)
5
9
  super(*args)
6
10
 
7
- @expected_attributes = attribute_names.reduce({}) do |hash, name|
8
- hash.merge(name => expected.public_send(name))
9
- end
10
-
11
- @actual_attributes = attribute_names.reduce({}) do |hash, name|
12
- hash.merge(name => actual.public_send(name))
13
- end
11
+ establish_expected_and_actual_attributes
14
12
  end
15
13
 
16
14
  protected
@@ -24,18 +22,30 @@ module SuperDiff
24
22
  end
25
23
  end
26
24
 
27
- def operation_sequence_class
28
- OperationSequences::Object
25
+ def build_operation_sequencer
26
+ # XXX This assumes that `expected` and `actual` are the same
27
+ OperationSequences::DefaultObject.new([], value_class: expected.class)
29
28
  end
30
29
 
31
30
  def attribute_names
32
- raise NotImplementedError
31
+ (expected.instance_variables.sort & actual.instance_variables.sort).
32
+ map { |variable_name| variable_name[1..-1] }
33
33
  end
34
34
 
35
35
  private
36
36
 
37
37
  attr_reader :expected_attributes, :actual_attributes
38
38
 
39
+ def establish_expected_and_actual_attributes
40
+ @expected_attributes = attribute_names.reduce({}) do |hash, name|
41
+ hash.merge(name => expected.instance_variable_get("@#{name}"))
42
+ end
43
+
44
+ @actual_attributes = attribute_names.reduce({}) do |hash, name|
45
+ hash.merge(name => actual.instance_variable_get("@#{name}"))
46
+ end
47
+ end
48
+
39
49
  def possibly_add_noop_operation_to(operations, attribute_name)
40
50
  if should_add_noop_operation?(attribute_name)
41
51
  operations << Operations::UnaryOperation.new(
@@ -1,8 +1,8 @@
1
1
  module SuperDiff
2
2
  module OperationalSequencers
3
3
  class Hash < Base
4
- def self.applies_to?(value)
5
- value.is_a?(::Hash)
4
+ def self.applies_to?(expected, actual)
5
+ expected.is_a?(::Hash) && actual.is_a?(::Hash)
6
6
  end
7
7
 
8
8
  protected
@@ -16,14 +16,14 @@ module SuperDiff
16
16
  end
17
17
  end
18
18
 
19
- def operation_sequence_class
20
- OperationSequences::Hash
19
+ def build_operation_sequencer
20
+ OperationSequences::Hash.new([])
21
21
  end
22
22
 
23
23
  private
24
24
 
25
25
  def all_keys
26
- (expected.keys | actual.keys)
26
+ actual.keys | expected.keys
27
27
  end
28
28
 
29
29
  def possibly_add_noop_to(operations, key)
@@ -33,6 +33,7 @@ module SuperDiff
33
33
  collection: actual,
34
34
  key: key,
35
35
  index: all_keys.index(key),
36
+ index_in_collection: actual.keys.index(key),
36
37
  value: actual[key],
37
38
  )
38
39
  end
@@ -51,6 +52,7 @@ module SuperDiff
51
52
  collection: expected,
52
53
  key: key,
53
54
  index: all_keys.index(key),
55
+ index_in_collection: expected.keys.index(key),
54
56
  value: expected[key],
55
57
  )
56
58
  end
@@ -68,6 +70,7 @@ module SuperDiff
68
70
  collection: actual,
69
71
  key: key,
70
72
  index: all_keys.index(key),
73
+ index_in_collection: actual.keys.index(key),
71
74
  value: actual[key],
72
75
  )
73
76
  end