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,5 +1,14 @@
1
1
  module SuperDiff
2
2
  module DiffFormatters
3
- DEFAULTS = [Array, Hash, MultiLineString].freeze
3
+ autoload :Array, "super_diff/diff_formatters/array"
4
+ autoload :Base, "super_diff/diff_formatters/base"
5
+ autoload :Collection, "super_diff/diff_formatters/collection"
6
+ autoload :CustomObject, "super_diff/diff_formatters/custom_object"
7
+ autoload :DefaultObject, "super_diff/diff_formatters/default_object"
8
+ autoload :Hash, "super_diff/diff_formatters/hash"
9
+ autoload :MultilineString, "super_diff/diff_formatters/multiline_string"
10
+
11
+ # TODO: Why doesn't this include CustomObject and DefaultObject?
12
+ DEFAULTS = [Array, Hash, MultilineString].freeze
4
13
  end
5
14
  end
@@ -5,33 +5,28 @@ module SuperDiff
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
- operations,
14
- indent_level:,
15
- collection_prefix: "",
16
- add_comma: false
10
+ method_object(
11
+ :operations,
12
+ [
13
+ :indent_level!,
14
+ collection_prefix: "",
15
+ add_comma: false,
16
+ ],
17
17
  )
18
- @operations = operations
19
- @indent_level = indent_level
20
- @collection_prefix = collection_prefix
21
- @add_comma = add_comma
22
- end
23
18
 
24
19
  def call
25
20
  raise NotImplementedError
26
21
  end
27
22
 
23
+ # rubocop:disable Lint/UselessAccessModifier
24
+
28
25
  private
29
26
 
30
- attr_reader :operations, :indent_level, :collection_prefix
27
+ # rubocop:enable Lint/UselessAccessModifier
31
28
 
32
- def add_comma?
33
- @add_comma
34
- end
29
+ attr_query :add_comma?
35
30
  end
36
31
  end
37
32
  end
@@ -1,30 +1,22 @@
1
1
  module SuperDiff
2
2
  module DiffFormatters
3
3
  class Collection
4
- ICONS = { delete: "-", insert: "+" }.freeze
5
- STYLES = { insert: :inserted, delete: :deleted, noop: :normal }.freeze
4
+ extend AttrExtras.mixin
6
5
 
7
- def self.call(*args, &block)
8
- new(*args, &block).call
9
- end
6
+ ICONS = { delete: "-", insert: "+" }.freeze
7
+ STYLES = { insert: :beta, delete: :alpha, noop: :plain }.freeze
10
8
 
11
- def initialize(
12
- open_token:,
13
- close_token:,
14
- operations:,
15
- indent_level:,
16
- add_comma:,
17
- collection_prefix:,
18
- build_item_prefix:
9
+ method_object(
10
+ [
11
+ :open_token!,
12
+ :close_token!,
13
+ :operations!,
14
+ :indent_level!,
15
+ :add_comma!,
16
+ :collection_prefix!,
17
+ :build_item_prefix!,
18
+ ],
19
19
  )
20
- @open_token = open_token
21
- @close_token = close_token
22
- @operations = operations
23
- @indent_level = indent_level
24
- @add_comma = add_comma
25
- @collection_prefix = collection_prefix
26
- @build_item_prefix = build_item_prefix
27
- end
28
20
 
29
21
  def call
30
22
  lines.join("\n")
@@ -32,8 +24,7 @@ module SuperDiff
32
24
 
33
25
  private
34
26
 
35
- attr_reader :open_token, :close_token, :operations, :indent_level,
36
- :add_comma, :collection_prefix, :build_item_prefix
27
+ attr_query :add_comma?
37
28
 
38
29
  def lines
39
30
  [
@@ -46,42 +37,82 @@ module SuperDiff
46
37
  def contents
47
38
  operations.map do |operation|
48
39
  if operation.name == :change
40
+ handle_change_operation(operation)
41
+ else
42
+ handle_non_change_operation(operation)
43
+ end
44
+ end
45
+ end
46
+
47
+ def handle_change_operation(operation)
48
+ SuperDiff::RecursionGuard.guarding_recursion_of(
49
+ operation.left_collection,
50
+ operation.right_collection,
51
+ ) do |already_seen|
52
+ if already_seen
53
+ raise "Infinite recursion!"
54
+ else
49
55
  operation.child_operations.to_diff(
50
56
  indent_level: indent_level + 1,
51
57
  collection_prefix: build_item_prefix.call(operation),
52
58
  add_comma: operation.should_add_comma_after_displaying?,
53
59
  )
54
- else
55
- icon = ICONS.fetch(operation.name, " ")
56
- style_name = STYLES.fetch(operation.name, :normal)
57
- chunk = build_chunk(
58
- Helpers.inspect_object(operation.value, single_line: false),
59
- prefix: build_item_prefix.call(operation),
60
- icon: icon,
61
- )
60
+ end
61
+ end
62
+ end
62
63
 
63
- if operation.should_add_comma_after_displaying?
64
- chunk << ","
65
- end
64
+ def handle_non_change_operation(operation)
65
+ icon = ICONS.fetch(operation.name, " ")
66
+ style_name = STYLES.fetch(operation.name, :normal)
67
+ chunk = build_chunk_for(
68
+ operation,
69
+ prefix: build_item_prefix.call(operation),
70
+ icon: icon,
71
+ )
66
72
 
67
- style_chunk(style_name, chunk)
68
- end
73
+ if operation.should_add_comma_after_displaying?
74
+ chunk << ","
69
75
  end
76
+
77
+ style_chunk(style_name, chunk)
70
78
  end
71
79
 
72
- def build_chunk(content, prefix:, icon:)
73
- lines =
74
- if content.is_a?(ValueInspection)
75
- [
76
- indentation(offset: 1) + prefix + content.beginning,
77
- *content.middle.map { |line| indentation(offset: 2) + line },
78
- indentation(offset: 1) + content.end,
79
- ]
80
- else
81
- [indentation(offset: 1) + prefix + content]
82
- end
80
+ def build_chunk_for(operation, prefix:, icon:)
81
+ if operation.value.equal?(operation.collection)
82
+ build_chunk_from_string(
83
+ SuperDiff::RecursionGuard::PLACEHOLDER,
84
+ prefix: build_item_prefix.call(operation),
85
+ icon: icon,
86
+ )
87
+ else
88
+ build_chunk_by_inspecting(
89
+ operation.value,
90
+ prefix: build_item_prefix.call(operation),
91
+ icon: icon,
92
+ )
93
+ end
94
+ end
83
95
 
84
- lines.map { |line| icon + " " + line }.join("\n")
96
+ def build_chunk_by_inspecting(value, prefix:, icon:)
97
+ inspection = ObjectInspection.inspect(
98
+ value,
99
+ as_single_line: false,
100
+ )
101
+ build_chunk_from_string(inspection, prefix: prefix, icon: icon)
102
+ end
103
+
104
+ def build_chunk_from_string(value, prefix:, icon:)
105
+ value.split("\n").
106
+ map.with_index { |line, index|
107
+ [
108
+ icon,
109
+ " ",
110
+ indentation(offset: 1),
111
+ (index == 0 ? prefix : ""),
112
+ line,
113
+ ].join
114
+ }.
115
+ join("\n")
85
116
  end
86
117
 
87
118
  def style_chunk(style_name, chunk)
@@ -92,11 +123,11 @@ module SuperDiff
92
123
  end
93
124
 
94
125
  def indentation(offset: 0)
95
- " " * ((indent_level + offset) * 2)
126
+ " " * (indent_level + offset)
96
127
  end
97
128
 
98
129
  def comma
99
- if add_comma
130
+ if add_comma?
100
131
  ","
101
132
  else
102
133
  ""
@@ -1,8 +1,8 @@
1
1
  module SuperDiff
2
2
  module DiffFormatters
3
- class Object < Base
3
+ class CustomObject < DefaultObject
4
4
  def self.applies_to?(operations)
5
- operations.is_a?(OperationSequences::Object)
5
+ operations.is_a?(OperationSequences::CustomObject)
6
6
  end
7
7
 
8
8
  def call
@@ -10,18 +10,21 @@ module SuperDiff
10
10
  open_token: "#<#{value_class} {",
11
11
  close_token: "}>",
12
12
  collection_prefix: collection_prefix,
13
- build_item_prefix: -> (operation) { "#{operation.key}: " },
13
+ build_item_prefix: -> (operation) {
14
+ key =
15
+ if operation.respond_to?(:left_key)
16
+ operation.left_key
17
+ else
18
+ operation.key
19
+ end
20
+
21
+ "#{key}: "
22
+ },
14
23
  operations: operations,
15
24
  indent_level: indent_level,
16
25
  add_comma: add_comma?,
17
26
  )
18
27
  end
19
-
20
- protected
21
-
22
- def value_class
23
- raise NotImplementedError
24
- end
25
28
  end
26
29
  end
27
30
  end
@@ -0,0 +1,48 @@
1
+ module SuperDiff
2
+ module DiffFormatters
3
+ class DefaultObject < Base
4
+ def self.applies_to?(operations)
5
+ operations.is_a?(OperationSequences::DefaultObject)
6
+ end
7
+
8
+ def initialize(operations, value_class: nil, **rest)
9
+ super(operations, **rest)
10
+
11
+ @value_class = value_class
12
+ end
13
+
14
+ def call
15
+ Collection.call(
16
+ open_token: "#<#{value_class} {",
17
+ close_token: "}>",
18
+ collection_prefix: collection_prefix,
19
+ build_item_prefix: -> (operation) {
20
+ key =
21
+ if operation.respond_to?(:left_key)
22
+ operation.left_key
23
+ else
24
+ operation.key
25
+ end
26
+
27
+ "@#{key}="
28
+ },
29
+ operations: operations,
30
+ indent_level: indent_level,
31
+ add_comma: add_comma?,
32
+ )
33
+ end
34
+
35
+ protected
36
+
37
+ def value_class
38
+ if @value_class
39
+ @value_class
40
+ else
41
+ raise NotImplementedError.new(
42
+ "You must override #value_class in your subclass.",
43
+ )
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,31 @@
1
+ module SuperDiff
2
+ module DiffFormatters
3
+ class MultilineString < Base
4
+ def self.applies_to?(operations)
5
+ operations.is_a?(OperationSequences::MultilineString)
6
+ end
7
+
8
+ def call
9
+ lines.join("\n")
10
+ end
11
+
12
+ private
13
+
14
+ def lines
15
+ operations.reduce([]) do |array, operation|
16
+ case operation.name
17
+ when :change
18
+ array << Helpers.style(:alpha, "- #{operation.left_value}")
19
+ array << Helpers.style(:beta, "+ #{operation.right_value}")
20
+ when :delete
21
+ array << Helpers.style(:alpha, "- #{operation.value}")
22
+ when :insert
23
+ array << Helpers.style(:beta, "+ #{operation.value}")
24
+ else
25
+ array << Helpers.style(:plain, " #{operation.value}")
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,47 +1,50 @@
1
1
  module SuperDiff
2
2
  class Differ
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
- indent_level: 0,
11
- index_in_collection: nil,
12
- extra_classes: [],
13
- extra_operational_sequencer_classes: [],
14
- extra_diff_formatter_classes: []
5
+ method_object(
6
+ :expected,
7
+ :actual,
8
+ [
9
+ indent_level: 0,
10
+ index_in_collection: nil,
11
+ omit_empty: false,
12
+ extra_classes: [],
13
+ extra_operational_sequencer_classes: [],
14
+ extra_diff_formatter_classes: [],
15
+ ],
15
16
  )
16
- @expected = expected
17
- @actual = actual
18
- @indent_level = indent_level
19
- @index_in_collection = index_in_collection
20
- @extra_classes = extra_classes
21
- @extra_operational_sequencer_classes = extra_operational_sequencer_classes
22
- @extra_diff_formatter_classes = extra_diff_formatter_classes
23
- end
24
17
 
25
18
  def call
26
- resolved_class.call(
27
- expected,
28
- actual,
29
- indent_level: indent_level,
30
- index_in_collection: index_in_collection,
31
- extra_operational_sequencer_classes: extra_operational_sequencer_classes,
32
- extra_diff_formatter_classes: extra_diff_formatter_classes,
33
- )
19
+ if resolved_class
20
+ resolved_class.call(
21
+ expected,
22
+ actual,
23
+ indent_level: indent_level,
24
+ index_in_collection: index_in_collection,
25
+ extra_operational_sequencer_classes: extra_operational_sequencer_classes,
26
+ extra_diff_formatter_classes: extra_diff_formatter_classes,
27
+ )
28
+ else
29
+ raise NoDifferAvailableError.create(expected, actual)
30
+ end
34
31
  end
35
32
 
36
33
  private
37
34
 
38
- attr_reader :expected, :actual, :indent_level, :index_in_collection,
39
- :extra_classes, :extra_operational_sequencer_classes,
40
- :extra_diff_formatter_classes
35
+ attr_query :omit_empty?
41
36
 
42
37
  def resolved_class
43
- (Differs::DEFAULTS + extra_classes).find do |klass|
44
- klass.applies_to?(expected) && klass.applies_to?(actual)
38
+ available_classes.find { |klass| klass.applies_to?(expected, actual) }
39
+ end
40
+
41
+ def available_classes
42
+ classes = extra_classes + Differs::DEFAULTS
43
+
44
+ if omit_empty?
45
+ classes - [Differs::Empty]
46
+ else
47
+ classes
45
48
  end
46
49
  end
47
50
  end
@@ -1,5 +1,20 @@
1
1
  module SuperDiff
2
2
  module Differs
3
- DEFAULTS = [Array, Hash, MultiLineString, Object, Empty].freeze
3
+ autoload :Array, "super_diff/differs/array"
4
+ autoload :Base, "super_diff/differs/base"
5
+ autoload :CustomObject, "super_diff/differs/custom_object"
6
+ autoload :DefaultObject, "super_diff/differs/default_object"
7
+ autoload :Empty, "super_diff/differs/empty"
8
+ autoload :Hash, "super_diff/differs/hash"
9
+ autoload :MultilineString, "super_diff/differs/multiline_string"
10
+
11
+ DEFAULTS = [
12
+ Array,
13
+ Hash,
14
+ MultilineString,
15
+ CustomObject,
16
+ DefaultObject,
17
+ Empty,
18
+ ].freeze
4
19
  end
5
20
  end