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.
- checksums.yaml +4 -4
- data/README.md +117 -89
- data/lib/super_diff.rb +33 -47
- data/lib/super_diff/active_record.rb +41 -0
- data/lib/super_diff/active_record/diff_formatters.rb +10 -0
- data/lib/super_diff/active_record/diff_formatters/active_record_relation.rb +23 -0
- data/lib/super_diff/active_record/differs.rb +10 -0
- data/lib/super_diff/active_record/differs/active_record_relation.rb +30 -0
- data/lib/super_diff/active_record/object_inspection.rb +14 -0
- data/lib/super_diff/active_record/object_inspection/inspectors.rb +16 -0
- data/lib/super_diff/active_record/object_inspection/inspectors/active_record_model.rb +38 -0
- data/lib/super_diff/active_record/object_inspection/inspectors/active_record_relation.rb +18 -0
- data/lib/super_diff/active_record/object_inspection/map_extension.rb +18 -0
- data/lib/super_diff/active_record/operation_sequences.rb +10 -0
- data/lib/super_diff/active_record/operation_sequences/active_record_relation.rb +16 -0
- data/lib/super_diff/active_record/operational_sequencers.rb +14 -0
- data/lib/super_diff/active_record/operational_sequencers/active_record_model.rb +19 -0
- data/lib/super_diff/active_record/operational_sequencers/active_record_relation.rb +24 -0
- data/lib/super_diff/active_support.rb +33 -0
- data/lib/super_diff/active_support/diff_formatters.rb +10 -0
- data/lib/super_diff/active_support/diff_formatters/hash_with_indifferent_access.rb +36 -0
- data/lib/super_diff/active_support/differs.rb +10 -0
- data/lib/super_diff/active_support/differs/hash_with_indifferent_access.rb +36 -0
- data/lib/super_diff/active_support/object_inspection.rb +14 -0
- data/lib/super_diff/active_support/object_inspection/inspectors.rb +12 -0
- data/lib/super_diff/active_support/object_inspection/inspectors/hash_with_indifferent_access.rb +18 -0
- data/lib/super_diff/active_support/object_inspection/map_extension.rb +15 -0
- data/lib/super_diff/active_support/operation_sequences.rb +10 -0
- data/lib/super_diff/active_support/operation_sequences/hash_with_indifferent_access.rb +16 -0
- data/lib/super_diff/active_support/operational_sequencers.rb +10 -0
- data/lib/super_diff/active_support/operational_sequencers/hash_with_indifferent_access.rb +21 -0
- data/lib/super_diff/colorized_document_extensions.rb +17 -0
- data/lib/super_diff/csi.rb +45 -15
- data/lib/super_diff/csi/bold_sequence.rb +9 -0
- data/lib/super_diff/csi/color.rb +62 -0
- data/lib/super_diff/csi/color_sequence_block.rb +28 -0
- data/lib/super_diff/csi/colorized_document.rb +72 -0
- data/lib/super_diff/csi/document.rb +183 -0
- data/lib/super_diff/csi/eight_bit_color.rb +72 -26
- data/lib/super_diff/csi/four_bit_color.rb +63 -29
- data/lib/super_diff/csi/twenty_four_bit_color.rb +79 -18
- data/lib/super_diff/csi/uncolorized_document.rb +29 -0
- data/lib/super_diff/diff_formatter.rb +10 -15
- data/lib/super_diff/diff_formatters.rb +10 -1
- data/lib/super_diff/diff_formatters/base.rb +12 -17
- data/lib/super_diff/diff_formatters/collection.rb +81 -50
- data/lib/super_diff/diff_formatters/{object.rb → custom_object.rb} +12 -9
- data/lib/super_diff/diff_formatters/default_object.rb +48 -0
- data/lib/super_diff/diff_formatters/multiline_string.rb +31 -0
- data/lib/super_diff/differ.rb +35 -32
- data/lib/super_diff/differs.rb +16 -1
- data/lib/super_diff/differs/array.rb +2 -2
- data/lib/super_diff/differs/base.rb +11 -21
- data/lib/super_diff/differs/custom_object.rb +26 -0
- data/lib/super_diff/differs/default_object.rb +25 -0
- data/lib/super_diff/differs/empty.rb +1 -1
- data/lib/super_diff/differs/hash.rb +2 -2
- data/lib/super_diff/differs/{multi_line_string.rb → multiline_string.rb} +6 -5
- data/lib/super_diff/equality_matcher.rb +9 -22
- data/lib/super_diff/equality_matchers.rb +19 -1
- data/lib/super_diff/equality_matchers/array.rb +6 -4
- data/lib/super_diff/equality_matchers/base.rb +8 -16
- data/lib/super_diff/equality_matchers/default.rb +60 -0
- data/lib/super_diff/equality_matchers/hash.rb +6 -4
- data/lib/super_diff/equality_matchers/{multi_line_string.rb → multiline_string.rb} +9 -6
- data/lib/super_diff/equality_matchers/primitive.rb +34 -0
- data/lib/super_diff/equality_matchers/{single_line_string.rb → singleline_string.rb} +7 -5
- data/lib/super_diff/helpers.rb +17 -81
- data/lib/super_diff/no_differ_available_error.rb +22 -0
- data/lib/super_diff/{errors.rb → no_operational_sequencer_available_error.rb} +0 -0
- data/lib/super_diff/object_inspection.rb +24 -0
- data/lib/super_diff/object_inspection/inspection_tree.rb +144 -0
- data/lib/super_diff/object_inspection/inspector.rb +27 -0
- data/lib/super_diff/object_inspection/inspectors.rb +18 -0
- data/lib/super_diff/object_inspection/inspectors/array.rb +22 -0
- data/lib/super_diff/object_inspection/inspectors/custom_object.rb +27 -0
- data/lib/super_diff/object_inspection/inspectors/default_object.rb +47 -0
- data/lib/super_diff/object_inspection/inspectors/hash.rb +22 -0
- data/lib/super_diff/object_inspection/inspectors/primitive.rb +13 -0
- data/lib/super_diff/object_inspection/inspectors/string.rb +13 -0
- data/lib/super_diff/object_inspection/map.rb +28 -0
- data/lib/super_diff/object_inspection/nodes.rb +49 -0
- data/lib/super_diff/object_inspection/nodes/base.rb +86 -0
- data/lib/super_diff/object_inspection/nodes/break.rb +15 -0
- data/lib/super_diff/object_inspection/nodes/inspection.rb +15 -0
- data/lib/super_diff/object_inspection/nodes/nesting.rb +16 -0
- data/lib/super_diff/object_inspection/nodes/text.rb +15 -0
- data/lib/super_diff/object_inspection/nodes/when_empty.rb +30 -0
- data/lib/super_diff/object_inspection/nodes/when_multiline.rb +22 -0
- data/lib/super_diff/object_inspection/nodes/when_non_empty.rb +30 -0
- data/lib/super_diff/object_inspection/nodes/when_singleline.rb +24 -0
- data/lib/super_diff/operation_sequences.rb +9 -0
- data/lib/super_diff/operation_sequences/base.rb +1 -1
- data/lib/super_diff/operation_sequences/{object.rb → custom_object.rb} +4 -3
- data/lib/super_diff/operation_sequences/default_object.rb +25 -0
- data/lib/super_diff/operational_sequencer.rb +23 -18
- data/lib/super_diff/operational_sequencers.rb +12 -1
- data/lib/super_diff/operational_sequencers/array.rb +65 -62
- data/lib/super_diff/operational_sequencers/base.rb +18 -26
- data/lib/super_diff/operational_sequencers/custom_object.rb +35 -0
- data/lib/super_diff/operational_sequencers/{object.rb → default_object.rb} +21 -11
- data/lib/super_diff/operational_sequencers/hash.rb +8 -5
- data/lib/super_diff/operational_sequencers/{multi_line_string.rb → multiline_string.rb} +11 -6
- data/lib/super_diff/operations.rb +6 -0
- data/lib/super_diff/operations/binary_operation.rb +14 -34
- data/lib/super_diff/operations/unary_operation.rb +11 -2
- data/lib/super_diff/rails.rb +1 -0
- data/lib/super_diff/recursion_guard.rb +47 -0
- data/lib/super_diff/rspec-rails.rb +2 -0
- data/lib/super_diff/rspec.rb +52 -8
- data/lib/super_diff/rspec/augmented_matcher.rb +98 -0
- data/lib/super_diff/rspec/configuration.rb +31 -0
- data/lib/super_diff/rspec/differ.rb +60 -16
- data/lib/super_diff/rspec/differs.rb +13 -0
- data/lib/super_diff/rspec/differs/collection_containing_exactly.rb +23 -0
- data/lib/super_diff/rspec/differs/partial_array.rb +22 -0
- data/lib/super_diff/rspec/differs/partial_hash.rb +22 -0
- data/lib/super_diff/rspec/differs/partial_object.rb +22 -0
- data/lib/super_diff/rspec/matcher_text_builders.rb +24 -0
- data/lib/super_diff/rspec/matcher_text_builders/base.rb +155 -0
- data/lib/super_diff/rspec/matcher_text_builders/be_predicate.rb +78 -0
- data/lib/super_diff/rspec/matcher_text_builders/contain_exactly.rb +14 -0
- data/lib/super_diff/rspec/matcher_text_builders/match.rb +23 -0
- data/lib/super_diff/rspec/matcher_text_builders/raise_error.rb +13 -0
- data/lib/super_diff/rspec/matcher_text_builders/respond_to.rb +99 -0
- data/lib/super_diff/rspec/matcher_text_template.rb +240 -0
- data/lib/super_diff/rspec/monkey_patches.rb +601 -98
- data/lib/super_diff/rspec/object_inspection.rb +8 -0
- data/lib/super_diff/rspec/object_inspection/inspectors.rb +24 -0
- data/lib/super_diff/rspec/object_inspection/inspectors/collection_containing_exactly.rb +19 -0
- data/lib/super_diff/rspec/object_inspection/inspectors/partial_array.rb +22 -0
- data/lib/super_diff/rspec/object_inspection/inspectors/partial_hash.rb +21 -0
- data/lib/super_diff/rspec/object_inspection/inspectors/partial_object.rb +21 -0
- data/lib/super_diff/rspec/object_inspection/map_extension.rb +23 -0
- data/lib/super_diff/rspec/operational_sequencers.rb +22 -0
- data/lib/super_diff/rspec/operational_sequencers/collection_containing_exactly.rb +97 -0
- data/lib/super_diff/rspec/operational_sequencers/partial_array.rb +23 -0
- data/lib/super_diff/rspec/operational_sequencers/partial_hash.rb +32 -0
- data/lib/super_diff/rspec/operational_sequencers/partial_object.rb +64 -0
- data/lib/super_diff/version.rb +1 -1
- data/spec/examples.txt +328 -46
- data/spec/integration/rails/active_record_spec.rb +19 -0
- data/spec/integration/rails/hash_with_indifferent_access_spec.rb +19 -0
- data/spec/integration/rspec/be_falsey_matcher_spec.rb +53 -0
- data/spec/integration/rspec/be_matcher_spec.rb +565 -0
- data/spec/integration/rspec/be_nil_matcher_spec.rb +53 -0
- data/spec/integration/rspec/be_predicate_matcher_spec.rb +546 -0
- data/spec/integration/rspec/be_truthy_matcher_spec.rb +57 -0
- data/spec/integration/rspec/contain_exactly_matcher_spec.rb +368 -0
- data/spec/integration/rspec/eq_matcher_spec.rb +874 -0
- data/spec/integration/rspec/have_attributes_matcher_spec.rb +299 -0
- data/spec/integration/rspec/include_matcher_spec.rb +350 -0
- data/spec/integration/rspec/match_matcher_spec.rb +1258 -0
- data/spec/integration/rspec/raise_error_matcher_spec.rb +350 -0
- data/spec/integration/rspec/respond_to_matcher_spec.rb +994 -0
- data/spec/integration/rspec/unhandled_errors_spec.rb +94 -0
- data/spec/spec_helper.rb +19 -4
- data/spec/support/colorizer.rb +9 -0
- data/spec/support/command_runner.rb +4 -0
- data/spec/support/integration/helpers.rb +179 -0
- data/spec/support/integration/matchers/produce_output_when_run_matcher.rb +79 -41
- data/spec/support/models/a.rb +11 -0
- data/spec/support/models/active_record/person.rb +26 -0
- data/spec/support/models/active_record/shipping_address.rb +29 -0
- data/spec/support/models/customer.rb +24 -0
- data/spec/support/models/empty_class.rb +6 -0
- data/spec/support/models/item.rb +10 -0
- data/spec/support/models/order.rb +9 -0
- data/spec/support/models/person.rb +20 -0
- data/spec/support/models/player.rb +33 -0
- data/spec/support/models/shipping_address.rb +34 -0
- data/spec/support/ruby_versions.rb +7 -0
- data/spec/support/shared_examples/active_record.rb +338 -0
- data/spec/support/shared_examples/hash_with_indifferent_access.rb +233 -0
- data/spec/unit/equality_matcher_spec.rb +579 -171
- data/spec/unit/object_inspection_spec.rb +1092 -0
- data/spec/unit/rspec/matchers/be_compared_to_spec.rb +23 -0
- data/spec/unit/rspec/matchers/be_falsey_spec.rb +9 -0
- data/spec/unit/rspec/matchers/be_nil_spec.rb +9 -0
- data/spec/unit/rspec/matchers/be_predicate_spec.rb +31 -0
- data/spec/unit/rspec/matchers/be_spec.rb +17 -0
- data/spec/unit/rspec/matchers/be_truthy_spec.rb +9 -0
- data/spec/unit/rspec/matchers/contain_exactly_spec.rb +11 -0
- data/spec/unit/rspec/matchers/eq_spec.rb +9 -0
- data/spec/unit/rspec/matchers/have_attributes_spec.rb +11 -0
- data/spec/unit/rspec/matchers/include_spec.rb +21 -0
- data/spec/unit/rspec/matchers/match_spec.rb +9 -0
- data/spec/unit/rspec/matchers/raise_error_spec.rb +29 -0
- data/spec/unit/rspec/matchers/respond_to_spec.rb +78 -0
- data/super_diff.gemspec +4 -2
- metadata +231 -34
- data/lib/super_diff/csi/color_helper.rb +0 -52
- data/lib/super_diff/csi/eight_bit_sequence.rb +0 -27
- data/lib/super_diff/csi/four_bit_sequence.rb +0 -24
- data/lib/super_diff/csi/sequence.rb +0 -22
- data/lib/super_diff/csi/twenty_four_bit_sequence.rb +0 -27
- data/lib/super_diff/diff_formatters/multi_line_string.rb +0 -31
- data/lib/super_diff/differs/object.rb +0 -68
- data/lib/super_diff/equality_matchers/object.rb +0 -18
- data/lib/super_diff/value_inspection.rb +0 -11
- data/spec/integration/rspec_spec.rb +0 -261
- data/spec/support/color_helper.rb +0 -49
- data/spec/support/person.rb +0 -23
- data/spec/support/person_diff_formatter.rb +0 -15
- data/spec/support/person_operation_sequence.rb +0 -14
- data/spec/support/person_operational_sequencer.rb +0 -19
@@ -0,0 +1,240 @@
|
|
1
|
+
module SuperDiff
|
2
|
+
module RSpec
|
3
|
+
class MatcherTextTemplate
|
4
|
+
MAX_LINE_LENGTH = 100
|
5
|
+
|
6
|
+
def self.generate(&block)
|
7
|
+
new(&block).to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@tokens = []
|
12
|
+
|
13
|
+
if block_given?
|
14
|
+
yield self
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def add_text(*args, &block)
|
19
|
+
add_token(PlainText, *args, &block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_text_in_color(*args, &block)
|
23
|
+
add_token(ColorizedText, *args, &block)
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_text_in_singleline_mode(*args, &block)
|
27
|
+
add_token(PlainTextInSinglelineMode, *args, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def add_text_in_multiline_mode(*args, &block)
|
31
|
+
add_token(PlainTextInMultilineMode, *args, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def add_list_in_color(*args, &block)
|
35
|
+
add_token(ColorizedList, *args, &block)
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_break(*args, &block)
|
39
|
+
add_token(Break, *args, &block)
|
40
|
+
end
|
41
|
+
|
42
|
+
def insert(*args, &block)
|
43
|
+
add_token(Insertion, *args, &block)
|
44
|
+
end
|
45
|
+
|
46
|
+
def length_of_first_paragraph
|
47
|
+
Csi.decolorize(to_string_in_singleline_mode).
|
48
|
+
split(/\n\n/).
|
49
|
+
first.
|
50
|
+
length
|
51
|
+
end
|
52
|
+
|
53
|
+
def to_s(as_single_line: nil)
|
54
|
+
if length_of_first_paragraph > MAX_LINE_LENGTH || as_single_line == false
|
55
|
+
to_string_in_multiline_mode
|
56
|
+
elsif length_of_first_paragraph <= MAX_LINE_LENGTH || as_single_line == true
|
57
|
+
to_string_in_singleline_mode
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_string_in_singleline_mode
|
62
|
+
tokens.map(&:to_string_in_singleline_mode).join
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_string_in_multiline_mode
|
66
|
+
tokens.map(&:to_string_in_multiline_mode).join
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
attr_reader :tokens
|
72
|
+
|
73
|
+
def add_token(klass, *args, &block)
|
74
|
+
tokens << klass.new(*args, &block)
|
75
|
+
end
|
76
|
+
|
77
|
+
class Base
|
78
|
+
def to_string_in_singleline_mode
|
79
|
+
raise NotImplementedError.new(
|
80
|
+
"#{self.class} must support #to_string_in_singleline_mode",
|
81
|
+
)
|
82
|
+
end
|
83
|
+
|
84
|
+
def to_string_in_multiline_mode
|
85
|
+
raise NotImplementedError.new(
|
86
|
+
"#{self.class} must support #to_string_in_multiline_mode",
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
def length
|
91
|
+
to_string_in_singleline_mode.length
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class Text < Base
|
96
|
+
def initialize(immediate_value = nil, &block)
|
97
|
+
@immediate_value = immediate_value
|
98
|
+
@block = block
|
99
|
+
end
|
100
|
+
|
101
|
+
def to_string_in_singleline_mode
|
102
|
+
to_s
|
103
|
+
end
|
104
|
+
|
105
|
+
def to_string_in_multiline_mode
|
106
|
+
to_s
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_s
|
110
|
+
raise NotImplementedError.new("#{self.class} must support #to_s")
|
111
|
+
end
|
112
|
+
|
113
|
+
protected
|
114
|
+
|
115
|
+
attr_reader :immediate_value, :block
|
116
|
+
|
117
|
+
def evaluate
|
118
|
+
if immediate_value && block
|
119
|
+
raise ArgumentError.new(
|
120
|
+
"Cannot provide both immediate value and block",
|
121
|
+
)
|
122
|
+
end
|
123
|
+
|
124
|
+
immediate_value || block.call
|
125
|
+
end
|
126
|
+
|
127
|
+
def to_sentence(values)
|
128
|
+
case values.length
|
129
|
+
when 0
|
130
|
+
""
|
131
|
+
when 1
|
132
|
+
values[0]
|
133
|
+
else
|
134
|
+
# TODO: Use Oxford comma
|
135
|
+
values[0..-2].join(", ") + " and #{values[-1]}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
class PlainText < Text
|
141
|
+
def to_s
|
142
|
+
evaluate.to_s
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
class ColorizedText < Text
|
147
|
+
def initialize(color, *args, &block)
|
148
|
+
super(*args, &block)
|
149
|
+
|
150
|
+
@color = color
|
151
|
+
end
|
152
|
+
|
153
|
+
def to_s
|
154
|
+
colorizer.wrap(evaluate.to_s, color)
|
155
|
+
end
|
156
|
+
|
157
|
+
def length
|
158
|
+
evaluate.to_s.length
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
attr_reader :color
|
164
|
+
|
165
|
+
def colorizer
|
166
|
+
::RSpec::Core::Formatters::ConsoleCodes
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
class ColorizedList < Text
|
171
|
+
def initialize(color, *args, &block)
|
172
|
+
super(*args, &block)
|
173
|
+
|
174
|
+
@color = color
|
175
|
+
end
|
176
|
+
|
177
|
+
def to_s
|
178
|
+
to_sentence(colorized_values)
|
179
|
+
end
|
180
|
+
|
181
|
+
private
|
182
|
+
|
183
|
+
attr_reader :color
|
184
|
+
|
185
|
+
def colorized_values
|
186
|
+
evaluate.map do |value|
|
187
|
+
colorizer.wrap(
|
188
|
+
::RSpec::Support::ObjectFormatter.format(value),
|
189
|
+
color,
|
190
|
+
)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def colorizer
|
195
|
+
::RSpec::Core::Formatters::ConsoleCodes
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
class PlainTextInSinglelineMode < Text
|
200
|
+
def to_string_in_singleline_mode
|
201
|
+
evaluate.to_s
|
202
|
+
end
|
203
|
+
|
204
|
+
def to_string_in_multiline_mode
|
205
|
+
""
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
class PlainTextInMultilineMode < Text
|
210
|
+
def to_string_in_singleline_mode
|
211
|
+
""
|
212
|
+
end
|
213
|
+
|
214
|
+
def to_string_in_multiline_mode
|
215
|
+
evaluate.to_s
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
class Break < Base
|
220
|
+
def to_string_in_singleline_mode
|
221
|
+
" "
|
222
|
+
end
|
223
|
+
|
224
|
+
def to_string_in_multiline_mode
|
225
|
+
"\n"
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
class Insertion < Text
|
230
|
+
def to_string_in_singleline_mode
|
231
|
+
evaluate.to_string_in_singleline_mode
|
232
|
+
end
|
233
|
+
|
234
|
+
def to_string_in_multiline_mode
|
235
|
+
evaluate.to_string_in_multiline_mode
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
@@ -1,122 +1,625 @@
|
|
1
|
-
RSpec::Expectations.instance_eval do
|
2
|
-
def differ
|
3
|
-
SuperDiff::RSpec::Differ
|
4
|
-
end
|
5
|
-
end
|
6
|
-
|
7
1
|
# rubocop:disable all
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
2
|
+
require "rspec/matchers"
|
3
|
+
require "rspec/expectations/fail_with"
|
4
|
+
require "rspec/expectations/handler"
|
5
|
+
require "rspec/support/object_formatter"
|
6
|
+
require "rspec/matchers/built_in/be"
|
7
|
+
require "rspec/matchers/built_in/contain_exactly"
|
8
|
+
require "rspec/matchers/built_in/eq"
|
9
|
+
require "rspec/matchers/built_in/have_attributes"
|
10
|
+
require "rspec/matchers/built_in/include"
|
11
|
+
require "rspec/matchers/built_in/match"
|
12
|
+
|
13
|
+
module RSpec
|
14
|
+
module Expectations
|
15
|
+
def self.differ
|
16
|
+
SuperDiff::RSpec::Differ
|
17
|
+
end
|
18
|
+
|
19
|
+
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
|
32
|
+
|
33
|
+
actual =
|
34
|
+
if matcher.respond_to?(:actual_for_diff)
|
35
|
+
matcher.actual_for_diff
|
36
|
+
else
|
37
|
+
matcher.actual
|
38
|
+
end
|
39
|
+
|
40
|
+
::RSpec::Expectations.fail_with(message, expected, actual)
|
41
|
+
else
|
42
|
+
::RSpec::Expectations.fail_with(message)
|
19
43
|
end
|
20
44
|
end
|
21
45
|
end
|
22
46
|
end
|
23
47
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
48
|
+
module Core
|
49
|
+
module Formatters
|
50
|
+
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
|
62
|
+
code_or_symbol
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
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
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class ExceptionPresenter
|
79
|
+
# UPDATE: Copy from SyntaxHighlighter::CodeRayImplementation
|
80
|
+
RESET_CODE = "\e[0m"
|
81
|
+
|
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
|
+
lines: options[:failure_lines],
|
96
|
+
already_colored: false
|
97
|
+
}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# Override to only color uncolored lines in red
|
102
|
+
def colorized_message_lines(colorizer=::RSpec::Core::Formatters::ConsoleCodes)
|
103
|
+
lines = failure_line_groups.flat_map do |group|
|
104
|
+
if group[:already_colored]
|
105
|
+
group[:lines]
|
106
|
+
else
|
107
|
+
group[:lines].map do |line|
|
108
|
+
colorizer.wrap(line, message_color)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
add_shared_group_lines(lines, colorizer)
|
114
|
+
end
|
115
|
+
|
116
|
+
private
|
117
|
+
|
118
|
+
def add_shared_group_lines(lines, colorizer)
|
119
|
+
return lines if @skip_shared_group_trace
|
120
|
+
|
121
|
+
example.metadata[:shared_group_inclusion_backtrace].each do |frame|
|
122
|
+
# Use red instead of the default color
|
123
|
+
lines << colorizer.wrap(frame.description, :failure)
|
124
|
+
end
|
125
|
+
|
126
|
+
lines
|
127
|
+
end
|
128
|
+
|
129
|
+
# Considering that `failure_slash_error_lines` is already colored,
|
130
|
+
# extract this from the other lines so that they, too, can be colored,
|
131
|
+
# later
|
132
|
+
def failure_line_groups
|
133
|
+
@failure_line_groups ||= [].tap do |groups|
|
134
|
+
groups << {
|
135
|
+
lines: failure_slash_error_lines,
|
136
|
+
already_colored: true
|
137
|
+
}
|
138
|
+
|
139
|
+
sections = [failure_slash_error_lines, exception_lines]
|
140
|
+
separate_groups = (
|
141
|
+
sections.any? { |section| section.size > 1 } &&
|
142
|
+
!exception_lines.first.empty?
|
143
|
+
)
|
144
|
+
if separate_groups
|
145
|
+
groups << { lines: [''], already_colored: true }
|
146
|
+
end
|
147
|
+
already_has_coloration = exception_lines.any? do |line|
|
148
|
+
line.match?(/\e\[\d+m/)
|
149
|
+
end
|
150
|
+
|
151
|
+
groups << {
|
152
|
+
lines: exception_lines[0..0],
|
153
|
+
already_colored: already_has_coloration
|
154
|
+
}
|
155
|
+
groups << {
|
156
|
+
lines: exception_lines[1..-1] + extra_failure_lines,
|
157
|
+
already_colored: true
|
158
|
+
}
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
# Style the first part in white and don't style the snippet of the line
|
163
|
+
def failure_slash_error_lines
|
164
|
+
lines = read_failed_lines
|
165
|
+
|
166
|
+
failure_slash_error = ConsoleCodes.wrap("Failure/Error: ", :bold)
|
167
|
+
|
168
|
+
if lines.count == 1
|
169
|
+
lines[0] = failure_slash_error + lines[0].strip
|
170
|
+
else
|
171
|
+
least_indentation = SnippetExtractor.least_indentation_from(lines)
|
172
|
+
lines = lines.map do |line|
|
173
|
+
line.sub(/^#{least_indentation}/, ' ')
|
174
|
+
end
|
175
|
+
lines.unshift(failure_slash_error)
|
176
|
+
end
|
177
|
+
|
178
|
+
lines
|
179
|
+
end
|
180
|
+
|
181
|
+
# Exclude this file from being included in backtraces, so that the
|
182
|
+
# SnippetExtractor prints the right thing
|
183
|
+
def find_failed_line
|
184
|
+
line_regex = RSpec.configuration.in_project_source_dir_regex
|
185
|
+
loaded_spec_files = RSpec.configuration.loaded_spec_files
|
186
|
+
|
187
|
+
exception_backtrace.find do |line|
|
188
|
+
next unless (line_path = line[/(.+?):(\d+)(|:\d+)/, 1])
|
189
|
+
path = File.expand_path(line_path)
|
190
|
+
path != __FILE__ && (loaded_spec_files.include?(path) || path =~ line_regex)
|
191
|
+
end || exception_backtrace.first
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
class SyntaxHighlighter
|
196
|
+
private
|
197
|
+
|
198
|
+
def implementation
|
199
|
+
RSpec::Core::Formatters::SyntaxHighlighter::NoSyntaxHighlightingImplementation
|
200
|
+
end
|
201
|
+
end
|
30
202
|
end
|
31
203
|
end
|
32
|
-
end
|
33
204
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
# UPDATE: Use no color by default
|
42
|
-
@message_color = options[:message_color]
|
43
|
-
@description = options.fetch(:description) { example.full_description }
|
44
|
-
@detail_formatter = options.fetch(:detail_formatter) { Proc.new {} }
|
45
|
-
@extra_detail_formatter = options.fetch(:extra_detail_formatter) { Proc.new {} }
|
46
|
-
@backtrace_formatter = options.fetch(:backtrace_formatter) { RSpec.configuration.backtrace_formatter }
|
47
|
-
@indentation = options.fetch(:indentation, 2)
|
48
|
-
@skip_shared_group_trace = options.fetch(:skip_shared_group_trace, false)
|
49
|
-
@failure_lines = options[:failure_lines]
|
205
|
+
module Support
|
206
|
+
class ObjectFormatter
|
207
|
+
# Override to use our formatting algorithm
|
208
|
+
def format(value)
|
209
|
+
SuperDiff::ObjectInspection.inspect(value, as_single_line: true)
|
210
|
+
end
|
211
|
+
end
|
50
212
|
end
|
51
213
|
|
52
|
-
|
53
|
-
|
214
|
+
module Matchers
|
215
|
+
class ExpectedsForMultipleDiffs
|
216
|
+
# Add a key for different sides
|
217
|
+
def self.from(expected)
|
218
|
+
return expected if self === expected
|
54
219
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
220
|
+
text =
|
221
|
+
colorizer.wrap("Diff:", SuperDiff::COLORS.fetch(:header)) +
|
222
|
+
"\n\n" +
|
223
|
+
colorizer.wrap(
|
224
|
+
"┌ (Key) ──────────────────────────┐",
|
225
|
+
SuperDiff::COLORS.fetch(:border)
|
226
|
+
) +
|
227
|
+
"\n" +
|
228
|
+
colorizer.wrap("│ ", SuperDiff::COLORS.fetch(:border)) +
|
229
|
+
colorizer.wrap(
|
230
|
+
"‹-› in expected, not in actual",
|
231
|
+
SuperDiff::COLORS.fetch(:alpha)
|
232
|
+
) +
|
233
|
+
colorizer.wrap(" │", SuperDiff::COLORS.fetch(:border)) +
|
234
|
+
"\n" +
|
235
|
+
colorizer.wrap("│ ", SuperDiff::COLORS.fetch(:border)) +
|
236
|
+
colorizer.wrap(
|
237
|
+
"‹+› in actual, not in expected",
|
238
|
+
SuperDiff::COLORS.fetch(:beta)
|
239
|
+
) +
|
240
|
+
colorizer.wrap(" │", SuperDiff::COLORS.fetch(:border)) +
|
241
|
+
"\n" +
|
242
|
+
colorizer.wrap("│ ", SuperDiff::COLORS.fetch(:border)) +
|
243
|
+
"‹ › in both expected and actual" +
|
244
|
+
colorizer.wrap(" │", SuperDiff::COLORS.fetch(:border)) +
|
245
|
+
"\n" +
|
246
|
+
colorizer.wrap(
|
247
|
+
"└─────────────────────────────────┘",
|
248
|
+
SuperDiff::COLORS.fetch(:border)
|
249
|
+
)
|
59
250
|
|
60
|
-
|
61
|
-
|
251
|
+
new([[expected, text]])
|
252
|
+
end
|
253
|
+
|
254
|
+
def self.colorizer
|
255
|
+
RSpec::Core::Formatters::ConsoleCodes
|
256
|
+
end
|
257
|
+
|
258
|
+
# Add an extra line break
|
259
|
+
def message_with_diff(message, differ, actual)
|
260
|
+
diff = diffs(differ, actual)
|
261
|
+
|
262
|
+
if diff.empty?
|
263
|
+
message
|
264
|
+
else
|
265
|
+
"#{message.rstrip}\n\n#{diff}"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
private
|
62
270
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
)
|
72
|
-
|
73
|
-
if lines.count == 1
|
74
|
-
lines[0] =
|
75
|
-
failure_slash_error +
|
76
|
-
RSpec::Core::Formatters::ConsoleCodes.wrap(lines[0].strip, :white)
|
77
|
-
else
|
78
|
-
least_indentation =
|
79
|
-
RSpec::Core::Formatters::SnippetExtractor.least_indentation_from(lines)
|
80
|
-
lines = lines.map do |line|
|
81
|
-
RSpec::Core::Formatters::ConsoleCodes.wrap(
|
82
|
-
line.sub(/^#{least_indentation}/, ' '),
|
83
|
-
:white
|
84
|
-
)
|
85
|
-
end
|
86
|
-
lines.unshift(failure_slash_error)
|
271
|
+
# Add extra line breaks in between diffs, and colorize the word "Diff"
|
272
|
+
def diffs(differ, actual)
|
273
|
+
@expected_list.map do |(expected, diff_label)|
|
274
|
+
diff = differ.diff(actual, expected)
|
275
|
+
next if diff.strip.empty?
|
276
|
+
diff_label + diff
|
277
|
+
end.compact.join("\n\n")
|
278
|
+
end
|
87
279
|
end
|
88
280
|
|
89
|
-
|
90
|
-
|
91
|
-
|
281
|
+
module BuiltIn
|
282
|
+
class Be
|
283
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
92
284
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
end
|
285
|
+
prepend(Module.new do
|
286
|
+
def expected_for_matcher_text
|
287
|
+
"truthy"
|
288
|
+
end
|
289
|
+
end)
|
290
|
+
end
|
100
291
|
|
101
|
-
|
102
|
-
|
103
|
-
colorizer.wrap("expected: value != #{expected_formatted}\n", :failure) +
|
104
|
-
colorizer.wrap(" got: #{actual_formatted}\n\n", :success) +
|
105
|
-
colorizer.wrap("(compared using ==)\n", :detail)
|
106
|
-
end
|
292
|
+
class BeComparedTo
|
293
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
107
294
|
|
108
|
-
|
295
|
+
prepend(Module.new do
|
296
|
+
def expected_action_for_matcher_text
|
297
|
+
if [:==, :===, :=~].include?(@operator)
|
298
|
+
"#{@operator}"
|
299
|
+
else
|
300
|
+
"be #{@operator}"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end)
|
304
|
+
end
|
109
305
|
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
306
|
+
class BeTruthy
|
307
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
308
|
+
|
309
|
+
prepend(Module.new do
|
310
|
+
def expected_action_for_matcher_text
|
311
|
+
"be"
|
312
|
+
end
|
313
|
+
|
314
|
+
def expected_for_matcher_text
|
315
|
+
"truthy"
|
316
|
+
end
|
317
|
+
end)
|
318
|
+
end
|
319
|
+
|
320
|
+
class BeFalsey
|
321
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
322
|
+
|
323
|
+
prepend(Module.new do
|
324
|
+
def expected_action_for_matcher_text
|
325
|
+
"be"
|
326
|
+
end
|
114
327
|
|
115
|
-
|
116
|
-
|
328
|
+
def expected_for_matcher_text
|
329
|
+
"falsey"
|
330
|
+
end
|
331
|
+
end)
|
332
|
+
end
|
333
|
+
|
334
|
+
class BeNil
|
335
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
336
|
+
|
337
|
+
prepend(Module.new do
|
338
|
+
def expected_action_for_matcher_text
|
339
|
+
"be"
|
340
|
+
end
|
341
|
+
|
342
|
+
def expected_for_matcher_text
|
343
|
+
"nil"
|
344
|
+
end
|
345
|
+
end)
|
346
|
+
end
|
347
|
+
|
348
|
+
class BePredicate
|
349
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
350
|
+
|
351
|
+
prepend(Module.new do
|
352
|
+
def actual_for_matcher_text
|
353
|
+
actual
|
354
|
+
end
|
355
|
+
|
356
|
+
def expected_for_matcher_text
|
357
|
+
expected
|
358
|
+
end
|
359
|
+
|
360
|
+
def expected_action_for_matcher_text
|
361
|
+
"return true for"
|
362
|
+
end
|
363
|
+
|
364
|
+
def matcher_text_builder_class
|
365
|
+
SuperDiff::RSpec::MatcherTextBuilders::BePredicate
|
366
|
+
end
|
367
|
+
|
368
|
+
def matcher_text_builder_args
|
369
|
+
super.merge(
|
370
|
+
predicate_accessible: predicate_accessible?,
|
371
|
+
private_predicate: private_predicate?,
|
372
|
+
expected_predicate_method_name: predicate
|
373
|
+
)
|
374
|
+
end
|
375
|
+
end)
|
376
|
+
end
|
377
|
+
|
378
|
+
class Eq
|
379
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
380
|
+
end
|
381
|
+
|
382
|
+
class Equal
|
383
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
384
|
+
end
|
385
|
+
|
386
|
+
class ContainExactly
|
387
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
388
|
+
|
389
|
+
prepend(Module.new do
|
390
|
+
# Override this method so that the differ knows that this is a partial
|
391
|
+
# collection
|
392
|
+
def expected_for_diff
|
393
|
+
matchers.a_collection_containing_exactly(*expected)
|
394
|
+
end
|
395
|
+
|
396
|
+
private
|
397
|
+
|
398
|
+
def expected_for_matcher_text
|
399
|
+
expected
|
400
|
+
end
|
401
|
+
|
402
|
+
def matcher_text_builder_class
|
403
|
+
SuperDiff::RSpec::MatcherTextBuilders::ContainExactly
|
404
|
+
end
|
405
|
+
end)
|
406
|
+
end
|
407
|
+
|
408
|
+
class Include
|
409
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
410
|
+
|
411
|
+
prepend(Module.new do
|
412
|
+
# Override this method so that the differ knows that this is a partial
|
413
|
+
# array or hash
|
414
|
+
def expected_for_diff
|
415
|
+
if expecteds.all? { |item| item.is_a?(Hash) }
|
416
|
+
matchers.a_collection_including(expecteds.first)
|
417
|
+
else
|
418
|
+
matchers.a_collection_including(*expecteds)
|
419
|
+
end
|
420
|
+
end
|
421
|
+
|
422
|
+
private
|
423
|
+
|
424
|
+
# Override to capitalize message and add period at end
|
425
|
+
def build_failure_message(negated:)
|
426
|
+
message = super
|
427
|
+
|
428
|
+
if actual.respond_to?(:include?)
|
429
|
+
message
|
430
|
+
elsif message.end_with?(".")
|
431
|
+
message.sub("\.$", ", ") + "but it does not respond to `include?`."
|
432
|
+
else
|
433
|
+
message + "\n\nBut it does not respond to `include?`."
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
# Override to use readable_list_of
|
438
|
+
def expected_for_description
|
439
|
+
readable_list_of(expecteds).lstrip
|
440
|
+
end
|
441
|
+
|
442
|
+
# Override to use readable_list_of
|
443
|
+
def expected_for_failure_message
|
444
|
+
# TODO: Switch to using @divergent_items and handle this in the text
|
445
|
+
# builder
|
446
|
+
readable_list_of(@divergent_items).lstrip
|
447
|
+
end
|
448
|
+
|
449
|
+
# Update to use (...) as delimiter instead of {...}
|
450
|
+
def readable_list_of(items)
|
451
|
+
if items && items.all? { |item| item.is_a?(Hash) }
|
452
|
+
description_of(items.inject(:merge)).
|
453
|
+
sub(/^\{ /, '(').
|
454
|
+
sub(/ \}$/, ')')
|
455
|
+
else
|
456
|
+
super
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end)
|
460
|
+
end
|
461
|
+
|
462
|
+
class Match
|
463
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
464
|
+
|
465
|
+
prepend(Module.new do
|
466
|
+
def matcher_text_builder_class
|
467
|
+
SuperDiff::RSpec::MatcherTextBuilders::Match
|
468
|
+
end
|
469
|
+
|
470
|
+
def matcher_text_builder_args
|
471
|
+
super.merge(expected_captures: @expected_captures)
|
472
|
+
end
|
473
|
+
end)
|
474
|
+
end
|
475
|
+
|
476
|
+
class HaveAttributes
|
477
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
478
|
+
|
479
|
+
prepend(Module.new do
|
480
|
+
# Use the message in the base matcher
|
481
|
+
def failure_message
|
482
|
+
respond_to_failure_message_or { super }
|
483
|
+
end
|
484
|
+
|
485
|
+
# Use the message in the base matcher
|
486
|
+
def failure_message_when_negated
|
487
|
+
respond_to_failure_message_or { super }
|
488
|
+
end
|
489
|
+
|
490
|
+
# Override to use the whole object, not just part of it
|
491
|
+
def actual_for_matcher_text
|
492
|
+
description_of(@actual)
|
493
|
+
end
|
494
|
+
|
495
|
+
# Override to use (...) as delimiters rather than {...}
|
496
|
+
def expected_for_matcher_text
|
497
|
+
super.sub(/^\{ /, '(').gsub(/ \}$/, ')')
|
498
|
+
end
|
499
|
+
|
500
|
+
# Override so that the differ knows that this is a partial object
|
501
|
+
def actual_for_diff
|
502
|
+
@actual
|
503
|
+
end
|
504
|
+
|
505
|
+
# Override so that the differ knows that this is a partial object
|
506
|
+
def expected_for_diff
|
507
|
+
if respond_to_failed
|
508
|
+
matchers.an_object_having_attributes(
|
509
|
+
@expected.select { |k, v| !@actual.respond_to?(k) }
|
510
|
+
)
|
511
|
+
else
|
512
|
+
matchers.an_object_having_attributes(@expected)
|
513
|
+
end
|
514
|
+
end
|
515
|
+
end)
|
516
|
+
|
517
|
+
# Override to force @values to get populated so that we can show a
|
518
|
+
# proper diff
|
519
|
+
def respond_to_attributes?
|
520
|
+
cache_all_values
|
521
|
+
matches = respond_to_matcher.matches?(@actual)
|
522
|
+
@respond_to_failed = !matches
|
523
|
+
matches
|
524
|
+
end
|
525
|
+
|
526
|
+
# Override this method to skip non-existent attributes, and to use
|
527
|
+
# public_send
|
528
|
+
def cache_all_values
|
529
|
+
@values = @expected.keys.inject({}) do |hash, attribute_key|
|
530
|
+
if @actual.respond_to?(attribute_key)
|
531
|
+
actual_value = @actual.public_send(attribute_key)
|
532
|
+
hash.merge(attribute_key => actual_value)
|
533
|
+
else
|
534
|
+
hash
|
535
|
+
end
|
536
|
+
end
|
537
|
+
end
|
538
|
+
|
539
|
+
def actual_has_attribute?(attribute_key, attribute_value)
|
540
|
+
values_match?(attribute_value, @values.fetch(attribute_key))
|
541
|
+
end
|
542
|
+
|
543
|
+
# Override to not improve_hash_formatting
|
544
|
+
def respond_to_failure_message_or
|
545
|
+
if respond_to_failed
|
546
|
+
respond_to_matcher.failure_message
|
547
|
+
else
|
548
|
+
yield
|
549
|
+
end
|
550
|
+
end
|
551
|
+
end
|
117
552
|
|
118
|
-
|
119
|
-
|
553
|
+
class RespondTo
|
554
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
555
|
+
|
556
|
+
prepend(Module.new do
|
557
|
+
def matcher_text_builder_class
|
558
|
+
SuperDiff::RSpec::MatcherTextBuilders::RespondTo
|
559
|
+
end
|
560
|
+
|
561
|
+
def matcher_text_builder_args
|
562
|
+
super.merge(
|
563
|
+
expected_arity: @expected_arity,
|
564
|
+
arbitrary_keywords: @arbitrary_keywords,
|
565
|
+
expected_keywords: @expected_keywords,
|
566
|
+
unlimited_arguments: @unlimited_arguments
|
567
|
+
)
|
568
|
+
end
|
569
|
+
|
570
|
+
def expected_for_description
|
571
|
+
@names
|
572
|
+
end
|
573
|
+
|
574
|
+
def expected_for_failure_message
|
575
|
+
@failing_method_names
|
576
|
+
end
|
577
|
+
end)
|
578
|
+
end
|
579
|
+
|
580
|
+
class RaiseError
|
581
|
+
prepend SuperDiff::RSpec::AugmentedMatcher
|
582
|
+
|
583
|
+
prepend(Module.new do
|
584
|
+
def actual_for_matcher_text
|
585
|
+
if @actual_error
|
586
|
+
"#<#{@actual_error.class.name} #{@actual_error.message.inspect}>"
|
587
|
+
end
|
588
|
+
end
|
589
|
+
|
590
|
+
def actual_for_diff
|
591
|
+
@actual_error.message
|
592
|
+
end
|
593
|
+
|
594
|
+
def expected_for_matcher_text
|
595
|
+
if @expected_message
|
596
|
+
"#<#{@expected_error.name} #{@expected_message.inspect}>"
|
597
|
+
else
|
598
|
+
"#<#{@expected_error.name}>"
|
599
|
+
end
|
600
|
+
end
|
601
|
+
|
602
|
+
def expected_for_diff
|
603
|
+
@expected_message
|
604
|
+
end
|
605
|
+
|
606
|
+
def diffable?
|
607
|
+
!@expected_message.to_s.empty?
|
608
|
+
end
|
609
|
+
|
610
|
+
def expected_action_for_failure_message
|
611
|
+
"match"
|
612
|
+
end
|
613
|
+
|
614
|
+
def matcher_text_builder_class
|
615
|
+
SuperDiff::RSpec::MatcherTextBuilders::RaiseError
|
616
|
+
end
|
617
|
+
end)
|
618
|
+
|
619
|
+
def self.matcher_name
|
620
|
+
'raise error'
|
621
|
+
end
|
622
|
+
end
|
623
|
+
end
|
120
624
|
end
|
121
625
|
end
|
122
|
-
# rubocop:enable all
|