super_diff 0.6.1 → 0.6.2

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: 0fc8e5b83b3b02559e96bbd06f8703b688d56b32588639f7d49a4774d6869433
4
- data.tar.gz: 5f0c9d472aa1170df1a52cc41eab384c4526342cf336e380cdbd01f9e95a3b61
3
+ metadata.gz: be7fd08d833b19c6a99401a1c7b80c448903c315d198b09e55baf70ee663dcfc
4
+ data.tar.gz: ea79d7bb6469e711058b71716c9ce1a23d6353381a8ae876c6bb180a57e78e2a
5
5
  SHA512:
6
- metadata.gz: 24306d1fba59520092a8a446e0a9219a3e9e89813fd3818f2769f737084cc8f6565b12497c86bacb4b9a8f9c5a4b13bafe0479e330cc8169a6c574e11cc74a56
7
- data.tar.gz: 514af50e6272ae3095b752d778b7f3bc776923bccb87a2ab8a50c2f8019c9aba991e129d2dad88248c621594ab5972029a798ada0e64eb8f8a27acc0e7cde496
6
+ metadata.gz: 75a1258f1d15d4a830a89ad898cefed4d6379d012fd7aa50d61f82672f10d0acacbf32e88177970fe46afa977dbce42c30212194867eefa1a72eb874417a1156
7
+ data.tar.gz: eb40c7881a21263fc89c6c2cfd1e54c5277449f98a32fb266bc720c43177772480d9834b61c4614102c236942d46ffcea82bc4e5090ad5f70dfc6d15f1d9e184
data/lib/super_diff.rb CHANGED
@@ -30,10 +30,34 @@ module SuperDiff
30
30
  @_configuration ||= Configuration.new
31
31
  end
32
32
 
33
+ def self.inspect_object(object, as_single_line:, indent_level: 0)
34
+ ObjectInspection::Inspectors::Main.call(
35
+ object,
36
+ as_single_line: as_single_line,
37
+ indent_level: indent_level,
38
+ )
39
+ end
40
+
33
41
  def self.time_like?(value)
34
42
  # Check for ActiveSupport's #acts_like_time? for their time-like objects
35
43
  # (like ActiveSupport::TimeWithZone).
36
44
  (value.respond_to?(:acts_like_time?) && value.acts_like_time?) ||
37
45
  value.is_a?(Time)
38
46
  end
47
+
48
+ def self.insert_overrides(target_module, mod = nil, &block)
49
+ if mod
50
+ target_module.prepend(mod)
51
+ else
52
+ target_module.prepend(Module.new(&block))
53
+ end
54
+ end
55
+
56
+ def self.insert_singleton_overrides(target_module, mod = nil, &block)
57
+ if mod
58
+ target_module.singleton_class.prepend(mod)
59
+ else
60
+ target_module.singleton_class.prepend(Module.new(&block))
61
+ end
62
+ end
39
63
  end
@@ -94,7 +94,7 @@ module SuperDiff
94
94
  end
95
95
 
96
96
  def build_chunk_by_inspecting(value, prefix:, icon:)
97
- inspection = ObjectInspection.inspect(
97
+ inspection = SuperDiff.inspect_object(
98
98
  value,
99
99
  as_single_line: false,
100
100
  )
@@ -13,14 +13,14 @@ module SuperDiff
13
13
  Helpers.style(
14
14
  :expected,
15
15
  "Expected: " +
16
- ObjectInspection.inspect(expected, as_single_line: true),
16
+ SuperDiff.inspect_object(expected, as_single_line: true),
17
17
  )
18
18
  }
19
19
  #{
20
20
  Helpers.style(
21
21
  :actual,
22
22
  " Actual: " +
23
- ObjectInspection.inspect(actual, as_single_line: true),
23
+ SuperDiff.inspect_object(actual, as_single_line: true),
24
24
  )
25
25
  }
26
26
 
@@ -21,7 +21,7 @@ module SuperDiff
21
21
  Helpers.style(
22
22
  :expected,
23
23
  "Expected: " +
24
- ObjectInspection.inspect(expected, as_single_line: true),
24
+ SuperDiff.inspect_object(expected, as_single_line: true),
25
25
  )
26
26
  end
27
27
 
@@ -29,7 +29,7 @@ module SuperDiff
29
29
  Helpers.style(
30
30
  :actual,
31
31
  " Actual: " +
32
- ObjectInspection.inspect(actual, as_single_line: true),
32
+ SuperDiff.inspect_object(actual, as_single_line: true),
33
33
  )
34
34
  end
35
35
 
@@ -13,14 +13,14 @@ module SuperDiff
13
13
  Helpers.style(
14
14
  :expected,
15
15
  "Expected: " +
16
- ObjectInspection.inspect(expected, as_single_line: true),
16
+ SuperDiff.inspect_object(expected, as_single_line: true),
17
17
  )
18
18
  }
19
19
  #{
20
20
  Helpers.style(
21
21
  :actual,
22
22
  " Actual: " +
23
- ObjectInspection.inspect(actual, as_single_line: true),
23
+ SuperDiff.inspect_object(actual, as_single_line: true),
24
24
  )
25
25
  }
26
26
 
@@ -14,14 +14,14 @@ module SuperDiff
14
14
  Helpers.style(
15
15
  :expected,
16
16
  "Expected: " +
17
- ObjectInspection.inspect(expected, as_single_line: true),
17
+ SuperDiff.inspect_object(expected, as_single_line: true),
18
18
  )
19
19
  }
20
20
  #{
21
21
  Helpers.style(
22
22
  :actual,
23
23
  " Actual: " +
24
- ObjectInspection.inspect(actual, as_single_line: true),
24
+ SuperDiff.inspect_object(actual, as_single_line: true),
25
25
  )
26
26
  }
27
27
 
@@ -17,14 +17,14 @@ module SuperDiff
17
17
  Helpers.style(
18
18
  :expected,
19
19
  "Expected: " +
20
- ObjectInspection.inspect(expected, as_single_line: true),
20
+ SuperDiff.inspect_object(expected, as_single_line: true),
21
21
  )
22
22
  }
23
23
  #{
24
24
  Helpers.style(
25
25
  :actual,
26
26
  " Actual: " +
27
- ObjectInspection.inspect(actual, as_single_line: true),
27
+ SuperDiff.inspect_object(actual, as_single_line: true),
28
28
  )
29
29
  }
30
30
  OUTPUT
@@ -13,14 +13,14 @@ module SuperDiff
13
13
  Helpers.style(
14
14
  :expected,
15
15
  "Expected: " +
16
- ObjectInspection.inspect(expected, as_single_line: true),
16
+ SuperDiff.inspect_object(expected, as_single_line: true),
17
17
  )
18
18
  }
19
19
  #{
20
20
  Helpers.style(
21
21
  :actual,
22
22
  " Actual: " +
23
- ObjectInspection.inspect(actual, as_single_line: true),
23
+ SuperDiff.inspect_object(actual, as_single_line: true),
24
24
  )
25
25
  }
26
26
  OUTPUT
@@ -3,13 +3,5 @@ module SuperDiff
3
3
  autoload :InspectionTree, "super_diff/object_inspection/inspection_tree"
4
4
  autoload :Inspectors, "super_diff/object_inspection/inspectors"
5
5
  autoload :Nodes, "super_diff/object_inspection/nodes"
6
-
7
- def self.inspect(object, as_single_line:, indent_level: 0)
8
- Inspectors::Main.call(
9
- object,
10
- as_single_line: as_single_line,
11
- indent_level: indent_level,
12
- )
13
- end
14
6
  end
15
7
  end
@@ -10,7 +10,7 @@ module SuperDiff
10
10
  immediate_value
11
11
  end
12
12
 
13
- SuperDiff::ObjectInspection.inspect(
13
+ SuperDiff.inspect_object(
14
14
  value,
15
15
  indent_level: indent_level,
16
16
  as_single_line: as_single_line,
@@ -12,34 +12,38 @@ require "rspec/matchers/built_in/match"
12
12
 
13
13
  module RSpec
14
14
  module Expectations
15
- def self.differ
16
- SuperDiff::RSpec::Differ
15
+ SuperDiff.insert_singleton_overrides(self) do
16
+ def differ
17
+ SuperDiff::RSpec::Differ
18
+ end
17
19
  end
18
20
 
19
21
  module ExpectationHelper
20
- def self.handle_failure(matcher, message, failure_message_method)
21
- message = message.call if message.respond_to?(:call)
22
- message ||= matcher.__send__(failure_message_method)
23
-
24
- if matcher.respond_to?(:diffable?) && matcher.diffable?
25
- # Look for expected_for_diff and actual_for_diff if possible
26
- expected =
27
- if matcher.respond_to?(:expected_for_diff)
28
- matcher.expected_for_diff
29
- else
30
- matcher.expected
31
- end
22
+ SuperDiff.insert_singleton_overrides(self) do
23
+ def handle_failure(matcher, message, failure_message_method)
24
+ message = message.call if message.respond_to?(:call)
25
+ message ||= matcher.__send__(failure_message_method)
26
+
27
+ if matcher.respond_to?(:diffable?) && matcher.diffable?
28
+ # Look for expected_for_diff and actual_for_diff if possible
29
+ expected =
30
+ if matcher.respond_to?(:expected_for_diff)
31
+ matcher.expected_for_diff
32
+ else
33
+ matcher.expected
34
+ end
32
35
 
33
- actual =
34
- if matcher.respond_to?(:actual_for_diff)
35
- matcher.actual_for_diff
36
- else
37
- matcher.actual
38
- end
36
+ actual =
37
+ if matcher.respond_to?(:actual_for_diff)
38
+ matcher.actual_for_diff
39
+ else
40
+ matcher.actual
41
+ end
39
42
 
40
- ::RSpec::Expectations.fail_with(message, expected, actual)
41
- else
42
- ::RSpec::Expectations.fail_with(message)
43
+ ::RSpec::Expectations.fail_with(message, expected, actual)
44
+ else
45
+ ::RSpec::Expectations.fail_with(message)
46
+ end
43
47
  end
44
48
  end
45
49
  end
@@ -48,29 +52,31 @@ module RSpec
48
52
  module Core
49
53
  module Formatters
50
54
  module ConsoleCodes
51
- # Patch so it returns nothing if code_or_symbol is nil, and that it uses
52
- # code_or_symbol if it can't be found in VT100_CODE_VALUES to allow for
53
- # customization
54
- def self.console_code_for(code_or_symbol)
55
- if code_or_symbol
56
- if (config_method = config_colors_to_methods[code_or_symbol])
57
- console_code_for RSpec.configuration.__send__(config_method)
58
- elsif RSpec::Core::Formatters::ConsoleCodes::VT100_CODE_VALUES.key?(code_or_symbol)
59
- code_or_symbol
60
- else
61
- RSpec::Core::Formatters::ConsoleCodes::VT100_CODES.fetch(code_or_symbol) do
55
+ SuperDiff.insert_singleton_overrides(self) do
56
+ # Patch so it returns nothing if code_or_symbol is nil, and that it uses
57
+ # code_or_symbol if it can't be found in VT100_CODE_VALUES to allow for
58
+ # customization
59
+ def console_code_for(code_or_symbol)
60
+ if code_or_symbol
61
+ if (config_method = config_colors_to_methods[code_or_symbol])
62
+ console_code_for RSpec.configuration.__send__(config_method)
63
+ elsif RSpec::Core::Formatters::ConsoleCodes::VT100_CODE_VALUES.key?(code_or_symbol)
62
64
  code_or_symbol
65
+ else
66
+ RSpec::Core::Formatters::ConsoleCodes::VT100_CODES.fetch(code_or_symbol) do
67
+ code_or_symbol
68
+ end
63
69
  end
64
70
  end
65
71
  end
66
- end
67
72
 
68
- # Patch so it does not apply a color if code_or_symbol is nil
69
- def self.wrap(text, code_or_symbol)
70
- if RSpec.configuration.color_enabled? && code = console_code_for(code_or_symbol)
71
- "\e[#{code}m#{text}\e[0m"
72
- else
73
- text
73
+ # Patch so it does not apply a color if code_or_symbol is nil
74
+ def wrap(text, code_or_symbol)
75
+ if RSpec.configuration.color_enabled? && code = console_code_for(code_or_symbol)
76
+ "\e[#{code}m#{text}\e[0m"
77
+ else
78
+ text
79
+ end
74
80
  end
75
81
  end
76
82
  end
@@ -79,173 +85,177 @@ module RSpec
79
85
  # UPDATE: Copy from SyntaxHighlighter::CodeRayImplementation
80
86
  RESET_CODE = "\e[0m"
81
87
 
82
- def initialize(exception, example, options={})
83
- @exception = exception
84
- @example = example
85
- @message_color = options.fetch(:message_color) { RSpec.configuration.failure_color }
86
- @description = options.fetch(:description) { example.full_description }
87
- @detail_formatter = options.fetch(:detail_formatter) { Proc.new {} }
88
- @extra_detail_formatter = options.fetch(:extra_detail_formatter) { Proc.new {} }
89
- @backtrace_formatter = options.fetch(:backtrace_formatter) { RSpec.configuration.backtrace_formatter }
90
- @indentation = options.fetch(:indentation, 2)
91
- @skip_shared_group_trace = options.fetch(:skip_shared_group_trace, false)
92
- # Patch to convert options[:failure_lines] to groups
93
- if options.include?(:failure_lines)
94
- @failure_line_groups = [
95
- {
96
- lines: options[:failure_lines],
97
- already_colorized: false
98
- }
99
- ]
88
+ SuperDiff.insert_overrides(self) do
89
+ def initialize(exception, example, options={})
90
+ @exception = exception
91
+ @example = example
92
+ @message_color = options.fetch(:message_color) { RSpec.configuration.failure_color }
93
+ @description = options.fetch(:description) { example.full_description }
94
+ @detail_formatter = options.fetch(:detail_formatter) { Proc.new {} }
95
+ @extra_detail_formatter = options.fetch(:extra_detail_formatter) { Proc.new {} }
96
+ @backtrace_formatter = options.fetch(:backtrace_formatter) { RSpec.configuration.backtrace_formatter }
97
+ @indentation = options.fetch(:indentation, 2)
98
+ @skip_shared_group_trace = options.fetch(:skip_shared_group_trace, false)
99
+ # Patch to convert options[:failure_lines] to groups
100
+ if options.include?(:failure_lines)
101
+ @failure_line_groups = [
102
+ {
103
+ lines: options[:failure_lines],
104
+ already_colorized: false
105
+ }
106
+ ]
107
+ end
100
108
  end
101
- end
102
109
 
103
- # Override to only color uncolored lines in red
104
- # and to not color empty lines
105
- def colorized_message_lines(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
106
- lines = failure_line_groups.flat_map do |group|
107
- if group[:already_colorized]
108
- group[:lines]
109
- else
110
- group[:lines].map do |line|
111
- if line.strip.empty?
112
- line
113
- else
114
- indentation = line[/^[ ]+/]
115
- rest = colorizer.wrap(line.sub(/^[ ]+/, ''), message_color)
116
-
117
- if indentation
118
- indentation + rest
110
+ # Override to only color uncolored lines in red
111
+ # and to not color empty lines
112
+ def colorized_message_lines(colorizer = ::RSpec::Core::Formatters::ConsoleCodes)
113
+ lines = failure_line_groups.flat_map do |group|
114
+ if group[:already_colorized]
115
+ group[:lines]
116
+ else
117
+ group[:lines].map do |line|
118
+ if line.strip.empty?
119
+ line
119
120
  else
120
- rest
121
+ indentation = line[/^[ ]+/]
122
+ rest = colorizer.wrap(line.sub(/^[ ]+/, ''), message_color)
123
+
124
+ if indentation
125
+ indentation + rest
126
+ else
127
+ rest
128
+ end
121
129
  end
122
130
  end
123
131
  end
124
132
  end
125
- end
126
-
127
- add_shared_group_lines(lines, colorizer)
128
- end
129
-
130
- private
131
133
 
132
- def add_shared_group_lines(lines, colorizer)
133
- return lines if @skip_shared_group_trace
134
-
135
- example.metadata[:shared_group_inclusion_backtrace].each do |frame|
136
- # Use red instead of the default color
137
- lines << colorizer.wrap(frame.description, :failure)
134
+ add_shared_group_lines(lines, colorizer)
138
135
  end
139
136
 
140
- lines
141
- end
137
+ private
142
138
 
143
- # Considering that `failure_slash_error_lines` is already colored,
144
- # extract this from the other lines so that they, too, can be colored,
145
- # later
146
- #
147
- # TODO: Refactor this somehow
148
- #
149
- def failure_line_groups
150
- if defined?(@failure_line_groups)
151
- @failure_line_groups
152
- else
153
- @failure_line_groups = [
154
- {
155
- lines: failure_slash_error_lines,
156
- already_colorized: true
157
- }
158
- ]
159
-
160
- sections = [failure_slash_error_lines, exception_lines]
161
- separate_groups = (
162
- sections.any? { |section| section.size > 1 } &&
163
- !exception_lines.first.empty?
164
- )
139
+ def add_shared_group_lines(lines, colorizer)
140
+ return lines if @skip_shared_group_trace
165
141
 
166
- if separate_groups
167
- @failure_line_groups << { lines: [''], already_colorized: true }
142
+ example.metadata[:shared_group_inclusion_backtrace].each do |frame|
143
+ # Use red instead of the default color
144
+ lines << colorizer.wrap(frame.description, :failure)
168
145
  end
169
146
 
170
- already_colorized = exception_lines.any? do |line|
171
- SuperDiff::Csi.already_colorized?(line)
172
- end
147
+ lines
148
+ end
173
149
 
174
- if already_colorized
175
- @failure_line_groups << {
176
- lines: exception_lines,
177
- already_colorized: true
178
- }
150
+ # Considering that `failure_slash_error_lines` is already colored,
151
+ # extract this from the other lines so that they, too, can be colored,
152
+ # later
153
+ #
154
+ # TODO: Refactor this somehow
155
+ #
156
+ def failure_line_groups
157
+ if defined?(@failure_line_groups)
158
+ @failure_line_groups
179
159
  else
180
- locatable_exception_lines =
181
- exception_lines.each_with_index.map do |line, index|
182
- { text: line, index: index }
183
- end
160
+ @failure_line_groups = [
161
+ {
162
+ lines: failure_slash_error_lines,
163
+ already_colorized: true
164
+ }
165
+ ]
184
166
 
185
- boundary_line =
186
- locatable_exception_lines.find do |line, index|
187
- line[:text].strip.empty? || line[:text].match?(/^ /)
188
- end
167
+ sections = [failure_slash_error_lines, exception_lines]
168
+ separate_groups = (
169
+ sections.any? { |section| section.size > 1 } &&
170
+ !exception_lines.first.empty?
171
+ )
189
172
 
190
- if boundary_line
191
- @failure_line_groups << {
192
- lines: exception_lines[0..boundary_line[:index] - 1],
193
- already_colorized: false
194
- }
173
+ if separate_groups
174
+ @failure_line_groups << { lines: [''], already_colorized: true }
175
+ end
176
+
177
+ already_colorized = exception_lines.any? do |line|
178
+ SuperDiff::Csi.already_colorized?(line)
179
+ end
180
+
181
+ if already_colorized
195
182
  @failure_line_groups << {
196
- lines: exception_lines[boundary_line[:index]..-1],
183
+ lines: exception_lines,
197
184
  already_colorized: true
198
185
  }
199
186
  else
200
- @failure_line_groups << {
201
- lines: exception_lines,
202
- already_colorized: false
203
- }
187
+ locatable_exception_lines =
188
+ exception_lines.each_with_index.map do |line, index|
189
+ { text: line, index: index }
190
+ end
191
+
192
+ boundary_line =
193
+ locatable_exception_lines.find do |line, index|
194
+ line[:text].strip.empty? || line[:text].match?(/^ /)
195
+ end
196
+
197
+ if boundary_line
198
+ @failure_line_groups << {
199
+ lines: exception_lines[0..boundary_line[:index] - 1],
200
+ already_colorized: false
201
+ }
202
+ @failure_line_groups << {
203
+ lines: exception_lines[boundary_line[:index]..-1],
204
+ already_colorized: true
205
+ }
206
+ else
207
+ @failure_line_groups << {
208
+ lines: exception_lines,
209
+ already_colorized: false
210
+ }
211
+ end
204
212
  end
205
- end
206
213
 
207
- @failure_line_groups
214
+ @failure_line_groups
215
+ end
208
216
  end
209
- end
210
217
 
211
- # Style the first part in white and don't style the snippet of the line
212
- def failure_slash_error_lines
213
- lines = read_failed_lines
218
+ # Style the first part in white and don't style the snippet of the line
219
+ def failure_slash_error_lines
220
+ lines = read_failed_lines
214
221
 
215
- failure_slash_error = ConsoleCodes.wrap("Failure/Error: ", :bold)
222
+ failure_slash_error = ConsoleCodes.wrap("Failure/Error: ", :bold)
216
223
 
217
- if lines.count == 1
218
- lines[0] = failure_slash_error + lines[0].strip
219
- else
220
- least_indentation = SnippetExtractor.least_indentation_from(lines)
221
- lines = lines.map do |line|
222
- line.sub(/^#{least_indentation}/, ' ')
224
+ if lines.count == 1
225
+ lines[0] = failure_slash_error + lines[0].strip
226
+ else
227
+ least_indentation = SnippetExtractor.least_indentation_from(lines)
228
+ lines = lines.map do |line|
229
+ line.sub(/^#{least_indentation}/, ' ')
230
+ end
231
+ lines.unshift(failure_slash_error)
223
232
  end
224
- lines.unshift(failure_slash_error)
233
+
234
+ lines
225
235
  end
226
236
 
227
- lines
228
- end
237
+ # Exclude this file from being included in backtraces, so that the
238
+ # SnippetExtractor prints the right thing
239
+ def find_failed_line
240
+ line_regex = RSpec.configuration.in_project_source_dir_regex
241
+ loaded_spec_files = RSpec.configuration.loaded_spec_files
229
242
 
230
- # Exclude this file from being included in backtraces, so that the
231
- # SnippetExtractor prints the right thing
232
- def find_failed_line
233
- line_regex = RSpec.configuration.in_project_source_dir_regex
234
- loaded_spec_files = RSpec.configuration.loaded_spec_files
235
-
236
- exception_backtrace.find do |line|
237
- next unless (line_path = line[/(.+?):(\d+)(|:\d+)/, 1])
238
- path = File.expand_path(line_path)
239
- path != __FILE__ && (loaded_spec_files.include?(path) || path =~ line_regex)
240
- end || exception_backtrace.first
243
+ exception_backtrace.find do |line|
244
+ next unless (line_path = line[/(.+?):(\d+)(|:\d+)/, 1])
245
+ path = File.expand_path(line_path)
246
+ path != __FILE__ && (loaded_spec_files.include?(path) || path =~ line_regex)
247
+ end || exception_backtrace.first
248
+ end
241
249
  end
242
250
  end
243
251
 
244
252
  class SyntaxHighlighter
245
- private
253
+ SuperDiff.insert_overrides(self) do
254
+ private
246
255
 
247
- def implementation
248
- RSpec::Core::Formatters::SyntaxHighlighter::NoSyntaxHighlightingImplementation
256
+ def implementation
257
+ RSpec::Core::Formatters::SyntaxHighlighter::NoSyntaxHighlightingImplementation
258
+ end
249
259
  end
250
260
  end
251
261
  end
@@ -253,100 +263,108 @@ module RSpec
253
263
 
254
264
  module Support
255
265
  class ObjectFormatter
256
- # Override to use our formatting algorithm
257
- def self.format(value)
258
- SuperDiff::ObjectInspection.inspect(value, as_single_line: true)
266
+ SuperDiff.insert_singleton_overrides(self) do
267
+ # Override to use our formatting algorithm
268
+ def format(value)
269
+ SuperDiff.inspect_object(value, as_single_line: true)
270
+ end
259
271
  end
260
272
 
261
- # Override to use our formatting algorithm
262
- def format(value)
263
- SuperDiff::ObjectInspection.inspect(value, as_single_line: true)
273
+ SuperDiff.insert_overrides(self) do
274
+ # Override to use our formatting algorithm
275
+ def format(value)
276
+ SuperDiff.inspect_object(value, as_single_line: true)
277
+ end
264
278
  end
265
279
  end
266
280
  end
267
281
 
268
282
  module Matchers
269
283
  class ExpectedsForMultipleDiffs
270
- # Add a key for different sides
271
- def self.from(expected)
272
- return expected if self === expected
273
-
274
- text =
275
- colorizer.wrap("Diff:", SuperDiff.configuration.header_color) +
276
- "\n\n" +
277
- colorizer.wrap(
278
- "┌ (Key) ──────────────────────────┐",
279
- SuperDiff.configuration.border_color
280
- ) +
281
- "\n" +
282
- colorizer.wrap("", SuperDiff.configuration.border_color) +
283
- colorizer.wrap(
284
- "‹-› in expected, not in actual",
285
- SuperDiff.configuration.expected_color
286
- ) +
287
- colorizer.wrap(" │", SuperDiff.configuration.border_color) +
288
- "\n" +
289
- colorizer.wrap("", SuperDiff.configuration.border_color) +
290
- colorizer.wrap(
291
- "‹+› in actual, not in expected",
292
- SuperDiff.configuration.actual_color
293
- ) +
294
- colorizer.wrap(" │", SuperDiff.configuration.border_color) +
295
- "\n" +
296
- colorizer.wrap("", SuperDiff.configuration.border_color) +
297
- " in both expected and actual" +
298
- colorizer.wrap(" ", SuperDiff.configuration.border_color) +
299
- "\n" +
300
- colorizer.wrap(
301
- "└─────────────────────────────────┘",
302
- SuperDiff.configuration.border_color
303
- )
304
-
305
- new([[expected, text]])
306
- end
284
+ SuperDiff.insert_singleton_overrides(self) do
285
+ # Add a key for different sides
286
+ def from(expected)
287
+ return expected if self === expected
288
+
289
+ text =
290
+ colorizer.wrap("Diff:", SuperDiff.configuration.header_color) +
291
+ "\n\n" +
292
+ colorizer.wrap(
293
+ "┌ (Key) ──────────────────────────┐",
294
+ SuperDiff.configuration.border_color
295
+ ) +
296
+ "\n" +
297
+ colorizer.wrap("│ ", SuperDiff.configuration.border_color) +
298
+ colorizer.wrap(
299
+ "‹-› in expected, not in actual",
300
+ SuperDiff.configuration.expected_color
301
+ ) +
302
+ colorizer.wrap("", SuperDiff.configuration.border_color) +
303
+ "\n" +
304
+ colorizer.wrap("│ ", SuperDiff.configuration.border_color) +
305
+ colorizer.wrap(
306
+ "‹+› in actual, not in expected",
307
+ SuperDiff.configuration.actual_color
308
+ ) +
309
+ colorizer.wrap("", SuperDiff.configuration.border_color) +
310
+ "\n" +
311
+ colorizer.wrap(" ", SuperDiff.configuration.border_color) +
312
+ " › in both expected and actual" +
313
+ colorizer.wrap("", SuperDiff.configuration.border_color) +
314
+ "\n" +
315
+ colorizer.wrap(
316
+ "└─────────────────────────────────┘",
317
+ SuperDiff.configuration.border_color
318
+ )
307
319
 
308
- def self.colorizer
309
- RSpec::Core::Formatters::ConsoleCodes
320
+ new([[expected, text]])
321
+ end
322
+
323
+ def colorizer
324
+ RSpec::Core::Formatters::ConsoleCodes
325
+ end
310
326
  end
311
327
 
312
- # Add an extra line break
313
- def message_with_diff(message, differ, actual)
314
- diff = diffs(differ, actual)
328
+ SuperDiff.insert_overrides(self) do
329
+ # Add an extra line break
330
+ def message_with_diff(message, differ, actual)
331
+ diff = diffs(differ, actual)
315
332
 
316
- if diff.empty?
317
- message
318
- else
319
- "#{message.rstrip}\n\n#{diff}"
333
+ if diff.empty?
334
+ message
335
+ else
336
+ "#{message.rstrip}\n\n#{diff}"
337
+ end
320
338
  end
321
- end
322
339
 
323
- private
340
+ private
324
341
 
325
- # Add extra line breaks in between diffs, and colorize the word "Diff"
326
- def diffs(differ, actual)
327
- @expected_list.map do |(expected, diff_label)|
328
- diff = differ.diff(actual, expected)
329
- next if diff.strip.empty?
330
- diff_label + diff
331
- end.compact.join("\n\n")
342
+ # Add extra line breaks in between diffs, and colorize the word "Diff"
343
+ def diffs(differ, actual)
344
+ @expected_list.map do |(expected, diff_label)|
345
+ diff = differ.diff(actual, expected)
346
+ next if diff.strip.empty?
347
+ diff_label + diff
348
+ end.compact.join("\n\n")
349
+ end
332
350
  end
333
351
  end
334
352
 
335
353
  module BuiltIn
336
354
  class Be
337
- prepend SuperDiff::RSpec::AugmentedMatcher
355
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
338
356
 
339
- prepend(Module.new do
357
+ SuperDiff.insert_overrides(self) do
340
358
  def expected_for_matcher_text
341
359
  "truthy"
342
360
  end
343
- end)
361
+ end
344
362
  end
345
363
 
346
364
  class BeComparedTo
347
- prepend SuperDiff::RSpec::AugmentedMatcher
365
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
348
366
 
349
- prepend(Module.new do
367
+ SuperDiff.insert_overrides(self) do
350
368
  def expected_action_for_matcher_text
351
369
  if [:==, :===, :=~].include?(@operator)
352
370
  "#{@operator}"
@@ -354,13 +372,13 @@ module RSpec
354
372
  "be #{@operator}"
355
373
  end
356
374
  end
357
- end)
375
+ end
358
376
  end
359
377
 
360
378
  class BeFalsey
361
- prepend SuperDiff::RSpec::AugmentedMatcher
379
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
362
380
 
363
- prepend(Module.new do
381
+ SuperDiff.insert_overrides(self) do
364
382
  def expected_action_for_matcher_text
365
383
  "be"
366
384
  end
@@ -368,13 +386,13 @@ module RSpec
368
386
  def expected_for_matcher_text
369
387
  "falsey"
370
388
  end
371
- end)
389
+ end
372
390
  end
373
391
 
374
392
  class BeNil
375
- prepend SuperDiff::RSpec::AugmentedMatcher
393
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
376
394
 
377
- prepend(Module.new do
395
+ SuperDiff.insert_overrides(self) do
378
396
  def expected_action_for_matcher_text
379
397
  "be"
380
398
  end
@@ -382,13 +400,13 @@ module RSpec
382
400
  def expected_for_matcher_text
383
401
  "nil"
384
402
  end
385
- end)
403
+ end
386
404
  end
387
405
 
388
406
  class BePredicate
389
- prepend SuperDiff::RSpec::AugmentedMatcher
407
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
390
408
 
391
- prepend(Module.new do
409
+ SuperDiff.insert_overrides(self) do
392
410
  def actual_for_matcher_text
393
411
  actual
394
412
  end
@@ -416,13 +434,13 @@ module RSpec
416
434
  expected_predicate_method_name: predicate
417
435
  )
418
436
  end
419
- end)
437
+ end
420
438
  end
421
439
 
422
440
  class BeTruthy
423
- prepend SuperDiff::RSpec::AugmentedMatcher
441
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
424
442
 
425
- prepend(Module.new do
443
+ SuperDiff.insert_overrides(self) do
426
444
  def expected_action_for_matcher_text
427
445
  "be"
428
446
  end
@@ -430,13 +448,13 @@ module RSpec
430
448
  def expected_for_matcher_text
431
449
  "truthy"
432
450
  end
433
- end)
451
+ end
434
452
  end
435
453
 
436
454
  class ContainExactly
437
- prepend SuperDiff::RSpec::AugmentedMatcher
455
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
438
456
 
439
- prepend(Module.new do
457
+ SuperDiff.insert_overrides(self) do
440
458
  # Override this method so that the differ knows that this is a partial
441
459
  # collection
442
460
  def expected_for_diff
@@ -452,21 +470,26 @@ module RSpec
452
470
  def matcher_text_builder_class
453
471
  SuperDiff::RSpec::MatcherTextBuilders::ContainExactly
454
472
  end
455
- end)
473
+ end
456
474
  end
457
475
 
458
476
  class Eq
459
- prepend SuperDiff::RSpec::AugmentedMatcher
477
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
460
478
  end
461
479
 
462
480
  class Equal
463
- prepend SuperDiff::RSpec::AugmentedMatcher
481
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
464
482
  end
465
483
 
466
484
  class HaveAttributes
467
- prepend SuperDiff::RSpec::AugmentedMatcher
485
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
486
+
487
+ SuperDiff.insert_overrides(self) do
488
+ def initialize(*)
489
+ super
490
+ @actual = nil
491
+ end
468
492
 
469
- prepend(Module.new do
470
493
  # Use the message in the base matcher
471
494
  def failure_message
472
495
  respond_to_failure_message_or { super }
@@ -502,48 +525,48 @@ module RSpec
502
525
  matchers.an_object_having_attributes(@expected)
503
526
  end
504
527
  end
505
- end)
506
528
 
507
- # Override to force @values to get populated so that we can show a
508
- # proper diff
509
- def respond_to_attributes?
510
- cache_all_values
511
- matches = respond_to_matcher.matches?(@actual)
512
- @respond_to_failed = !matches
513
- matches
514
- end
529
+ # Override to force @values to get populated so that we can show a
530
+ # proper diff
531
+ def respond_to_attributes?
532
+ cache_all_values
533
+ matches = respond_to_matcher.matches?(@actual)
534
+ @respond_to_failed = !matches
535
+ matches
536
+ end
515
537
 
516
- # Override this method to skip non-existent attributes, and to use
517
- # public_send
518
- def cache_all_values
519
- @values = @expected.keys.inject({}) do |hash, attribute_key|
520
- if @actual.respond_to?(attribute_key)
521
- actual_value = @actual.public_send(attribute_key)
522
- hash.merge(attribute_key => actual_value)
523
- else
524
- hash
538
+ # Override this method to skip non-existent attributes, and to use
539
+ # public_send
540
+ def cache_all_values
541
+ @values = @expected.keys.inject({}) do |hash, attribute_key|
542
+ if @actual.respond_to?(attribute_key)
543
+ actual_value = @actual.public_send(attribute_key)
544
+ hash.merge(attribute_key => actual_value)
545
+ else
546
+ hash
547
+ end
525
548
  end
526
549
  end
527
- end
528
550
 
529
- def actual_has_attribute?(attribute_key, attribute_value)
530
- values_match?(attribute_value, @values.fetch(attribute_key))
531
- end
551
+ def actual_has_attribute?(attribute_key, attribute_value)
552
+ values_match?(attribute_value, @values.fetch(attribute_key))
553
+ end
532
554
 
533
- # Override to not improve_hash_formatting
534
- def respond_to_failure_message_or
535
- if respond_to_failed
536
- respond_to_matcher.failure_message
537
- else
538
- yield
555
+ # Override to not improve_hash_formatting
556
+ def respond_to_failure_message_or
557
+ if respond_to_failed
558
+ respond_to_matcher.failure_message
559
+ else
560
+ yield
561
+ end
539
562
  end
540
563
  end
541
564
  end
542
565
 
543
566
  class Has
544
- prepend SuperDiff::RSpec::AugmentedMatcher
567
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
545
568
 
546
- prepend(Module.new do
569
+ SuperDiff.insert_overrides(self) do
547
570
  def actual_for_matcher_text
548
571
  actual
549
572
  end
@@ -570,13 +593,18 @@ module RSpec
570
593
  private_predicate: private_predicate?
571
594
  )
572
595
  end
573
- end)
596
+ end
574
597
  end
575
598
 
576
599
  class Include
577
- prepend SuperDiff::RSpec::AugmentedMatcher
600
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
601
+
602
+ SuperDiff.insert_overrides(self) do
603
+ def initialize(*)
604
+ super
605
+ @actual = nil
606
+ end
578
607
 
579
- prepend(Module.new do
580
608
  # Override this method so that the differ knows that this is a partial
581
609
  # array or hash
582
610
  def expected_for_diff
@@ -611,7 +639,11 @@ module RSpec
611
639
  def expected_for_failure_message
612
640
  # TODO: Switch to using @divergent_items and handle this in the text
613
641
  # builder
614
- readable_list_of(@divergent_items).lstrip
642
+ if defined?(@divergent_items)
643
+ readable_list_of(@divergent_items).lstrip
644
+ else
645
+ ""
646
+ end
615
647
  end
616
648
 
617
649
  # Update to use (...) as delimiter instead of {...}
@@ -624,13 +656,13 @@ module RSpec
624
656
  super
625
657
  end
626
658
  end
627
- end)
659
+ end
628
660
  end
629
661
 
630
662
  class Match
631
- prepend SuperDiff::RSpec::AugmentedMatcher
663
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
632
664
 
633
- prepend(Module.new do
665
+ SuperDiff.insert_overrides(self) do
634
666
  def matcher_text_builder_class
635
667
  SuperDiff::RSpec::MatcherTextBuilders::Match
636
668
  end
@@ -638,7 +670,7 @@ module RSpec
638
670
  def matcher_text_builder_args
639
671
  super.merge(expected_captures: @expected_captures)
640
672
  end
641
- end)
673
+ end
642
674
  end
643
675
 
644
676
  class MatchArray < ContainExactly
@@ -652,9 +684,9 @@ module RSpec
652
684
  end
653
685
 
654
686
  class RaiseError
655
- prepend SuperDiff::RSpec::AugmentedMatcher
687
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
656
688
 
657
- prepend(Module.new do
689
+ SuperDiff.insert_overrides(self) do
658
690
  def actual_for_matcher_text
659
691
  if @actual_error
660
692
  "#<#{@actual_error.class.name} #{@actual_error.message.inspect}>"
@@ -696,7 +728,7 @@ module RSpec
696
728
  def matcher_text_builder_class
697
729
  SuperDiff::RSpec::MatcherTextBuilders::RaiseError
698
730
  end
699
- end)
731
+ end
700
732
 
701
733
  def self.matcher_name
702
734
  "raise error"
@@ -704,9 +736,9 @@ module RSpec
704
736
  end
705
737
 
706
738
  class RespondTo
707
- prepend SuperDiff::RSpec::AugmentedMatcher
739
+ SuperDiff.insert_overrides(self, SuperDiff::RSpec::AugmentedMatcher)
708
740
 
709
- prepend(Module.new do
741
+ SuperDiff.insert_overrides(self) do
710
742
  def initialize(*)
711
743
  super
712
744
  @failing_method_names = nil
@@ -732,13 +764,20 @@ module RSpec
732
764
  def expected_for_failure_message
733
765
  @failing_method_names
734
766
  end
735
- end)
767
+ end
736
768
  end
737
769
  end
738
770
 
739
- def match_array(items)
740
- BuiltIn::MatchArray.new(items.is_a?(String) ? [items] : items)
771
+ SuperDiff.insert_overrides(self) do
772
+ def self.prepended(base)
773
+ base.class_eval do
774
+ alias_matcher :an_array_matching, :match_array
775
+ end
776
+ end
777
+
778
+ def match_array(items)
779
+ BuiltIn::MatchArray.new(items.is_a?(String) ? [items] : items)
780
+ end
741
781
  end
742
- alias_matcher :an_array_matching, :match_array
743
782
  end
744
783
  end