enhanced_errors 2.1.0 → 2.1.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 +4 -4
- data/.yardoc/checksums +4 -4
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/README.md +5 -1
- data/doc/Enhanced/Colors.html +25 -18
- data/doc/Enhanced.html +3 -7
- data/doc/EnhancedErrors.html +1784 -795
- data/doc/Exception.html +2 -2
- data/doc/Minitest.html +238 -0
- data/doc/_index.html +5 -22
- data/doc/class_list.html +1 -1
- data/doc/file.README.html +76 -80
- data/doc/index.html +76 -80
- data/doc/method_list.html +144 -16
- data/doc/top-level-namespace.html +3 -3
- data/enhanced_errors.gemspec +1 -1
- data/examples/demo_rspec.rb +16 -1
- data/lib/enhanced_errors.rb +136 -94
- metadata +4 -3
@@ -82,7 +82,7 @@
|
|
82
82
|
<p class="children">
|
83
83
|
|
84
84
|
|
85
|
-
<strong class="modules">Modules:</strong> <span class='object_link'><a href="Enhanced.html" title="Enhanced (module)">Enhanced</a></span>
|
85
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="Enhanced.html" title="Enhanced (module)">Enhanced</a></span>, <span class='object_link'><a href="Minitest.html" title="Minitest (module)">Minitest</a></span>
|
86
86
|
|
87
87
|
|
88
88
|
|
@@ -122,9 +122,9 @@
|
|
122
122
|
</div>
|
123
123
|
|
124
124
|
<div id="footer">
|
125
|
-
Generated on Mon Dec
|
125
|
+
Generated on Mon Dec 16 10:41:42 2024 by
|
126
126
|
<a href="https://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
127
|
-
0.9.37 (ruby-3.
|
127
|
+
0.9.37 (ruby-3.3.6).
|
128
128
|
</div>
|
129
129
|
|
130
130
|
</div>
|
data/enhanced_errors.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
2
|
spec.name = "enhanced_errors"
|
3
|
-
spec.version = "2.1.
|
3
|
+
spec.version = "2.1.2"
|
4
4
|
spec.authors = ["Eric Beland"]
|
5
5
|
|
6
6
|
spec.summary = "Automatically enhance your errors with messages containing variable values from the moment they were raised."
|
data/examples/demo_rspec.rb
CHANGED
@@ -14,8 +14,12 @@ RSpec.configure do |config|
|
|
14
14
|
EnhancedErrors.start_rspec_binding_capture
|
15
15
|
end
|
16
16
|
|
17
|
+
config.before(:example) do |_example|
|
18
|
+
EnhancedErrors.start_rspec_binding_capture
|
19
|
+
end
|
20
|
+
|
17
21
|
config.after(:example) do |example|
|
18
|
-
EnhancedErrors.
|
22
|
+
EnhancedErrors.override_rspec_message(example, EnhancedErrors.stop_rspec_binding_capture)
|
19
23
|
end
|
20
24
|
# -- End EnhancedErrors config
|
21
25
|
|
@@ -36,6 +40,17 @@ RSpec.describe 'Neo' do
|
|
36
40
|
stop = 'bullets'
|
37
41
|
raise 'No!'
|
38
42
|
end
|
43
|
+
|
44
|
+
it "dodges multiple exception-bullets at once" do
|
45
|
+
foo = 'bar'
|
46
|
+
expect(1).to eq(2)
|
47
|
+
expect(true).to eq(false)
|
48
|
+
end
|
49
|
+
|
50
|
+
after(:each) do
|
51
|
+
raise "This is another error"
|
52
|
+
end
|
53
|
+
|
39
54
|
end
|
40
55
|
end
|
41
56
|
|
data/lib/enhanced_errors.rb
CHANGED
@@ -21,70 +21,71 @@ class EnhancedErrors
|
|
21
21
|
@monitor ||= Monitor.new
|
22
22
|
end
|
23
23
|
|
24
|
-
attr_accessor :enabled, :config_block, :on_capture_hook, :eligible_for_capture, :
|
24
|
+
attr_accessor :enabled, :config_block, :on_capture_hook, :eligible_for_capture, :exception_trace, :override_messages
|
25
25
|
|
26
26
|
GEMS_REGEX = %r{[\/\\]gems[\/\\]}
|
27
|
-
RSPEC_EXAMPLE_REGEXP = /RSpec::ExampleGroups::[A-Z0-9]+.*/
|
28
27
|
DEFAULT_MAX_LENGTH = 2000
|
29
28
|
MAX_BINDING_INFOS = 3
|
30
29
|
|
31
30
|
RSPEC_SKIP_LIST = [
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
31
|
+
:@__inspect_output,
|
32
|
+
:@__memoized,
|
33
|
+
:@assertion_delegator,
|
34
|
+
:@assertion_instance,
|
35
|
+
:@assertions,
|
36
|
+
:@connection_subscriber,
|
37
|
+
:@example,
|
38
|
+
:@fixture_cache,
|
39
|
+
:@fixture_cache_key,
|
40
|
+
:@fixture_connection_pools,
|
41
|
+
:@fixture_connections,
|
42
|
+
:@integration_session,
|
43
|
+
:@legacy_saved_pool_configs,
|
44
|
+
:@loaded_fixtures,
|
45
|
+
:@matcher_definitions,
|
46
|
+
:@saved_pool_configs
|
47
|
+
].freeze
|
49
48
|
|
50
49
|
RAILS_SKIP_LIST = [
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
50
|
+
:@new_record,
|
51
|
+
:@attributes,
|
52
|
+
:@association_cache,
|
53
|
+
:@readonly,
|
54
|
+
:@previously_new_record,
|
55
|
+
:@_routes,
|
56
|
+
:@routes,
|
57
|
+
:@app,
|
58
|
+
:@arel_table,
|
59
|
+
:@assertion_instance,
|
60
|
+
:@association_cache,
|
61
|
+
:@attributes,
|
62
|
+
:@destroyed,
|
63
|
+
:@destroyed_by_association,
|
64
|
+
:@find_by_statement_cache,
|
65
|
+
:@generated_relation_method,
|
66
|
+
:@integration_session,
|
67
|
+
:@marked_for_destruction,
|
68
|
+
:@mutations_before_last_save,
|
69
|
+
:@mutations_from_database,
|
70
|
+
:@new_record,
|
71
|
+
:@predicate_builder,
|
72
|
+
:@previously_new_record,
|
73
|
+
:@primary_key,
|
74
|
+
:@readonly,
|
75
|
+
:@relation_delegate_cache,
|
76
|
+
:@response,
|
77
|
+
:@response_klass,
|
78
|
+
:@routes,
|
79
|
+
:@strict_loading,
|
80
|
+
:@strict_loading_mode
|
81
|
+
].freeze
|
83
82
|
|
84
83
|
MINITEST_SKIP_LIST = [:@NAME, :@failures, :@time].freeze
|
85
84
|
|
86
85
|
DEFAULT_SKIP_LIST = (RAILS_SKIP_LIST + RSPEC_SKIP_LIST + MINITEST_SKIP_LIST)
|
87
86
|
|
87
|
+
RSPEC_HANDLER_NAMES = ['RSpec::Expectations::PositiveExpectationHandler', 'RSpec::Expectations::NegativeExpectationHandler']
|
88
|
+
|
88
89
|
@enabled = false
|
89
90
|
@max_length = nil
|
90
91
|
@capture_rescue = nil
|
@@ -94,12 +95,11 @@ class EnhancedErrors
|
|
94
95
|
@output_format = nil
|
95
96
|
@eligible_for_capture = nil
|
96
97
|
@original_global_variables = nil
|
97
|
-
@
|
98
|
+
@exception_trace = nil
|
98
99
|
@override_messages = nil
|
99
|
-
@rspec_failure_message_loaded = nil
|
100
100
|
|
101
101
|
# Default values
|
102
|
-
@max_capture_events = -1
|
102
|
+
@max_capture_events = -1 # -1 means no limit
|
103
103
|
@capture_events_count = 0
|
104
104
|
|
105
105
|
# Thread-safe getters and setters
|
@@ -116,11 +116,11 @@ class EnhancedErrors
|
|
116
116
|
end
|
117
117
|
|
118
118
|
def capture_rescue
|
119
|
-
mutex.synchronize {
|
119
|
+
mutex.synchronize { @capture_rescue }
|
120
120
|
end
|
121
121
|
|
122
122
|
def capture_events_count
|
123
|
-
mutex.synchronize { @capture_events_count }
|
123
|
+
mutex.synchronize { @capture_events_count || 0 }
|
124
124
|
end
|
125
125
|
|
126
126
|
def capture_events_count=(val)
|
@@ -128,7 +128,7 @@ class EnhancedErrors
|
|
128
128
|
end
|
129
129
|
|
130
130
|
def max_capture_events
|
131
|
-
mutex.synchronize { @max_capture_events }
|
131
|
+
mutex.synchronize { @max_capture_events || -1 }
|
132
132
|
end
|
133
133
|
|
134
134
|
def max_capture_events=(value)
|
@@ -139,7 +139,7 @@ class EnhancedErrors
|
|
139
139
|
if @enabled
|
140
140
|
puts "EnhancedErrors: max_capture_events set to 0, disabling capturing."
|
141
141
|
@enabled = false
|
142
|
-
@
|
142
|
+
@exception_trace&.disable
|
143
143
|
@rspec_tracepoint&.disable
|
144
144
|
@minitest_trace&.disable
|
145
145
|
end
|
@@ -147,23 +147,36 @@ class EnhancedErrors
|
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
150
|
+
def enforce_capture_limit!
|
151
|
+
disable_capturing! if capture_limit_exceeded?
|
152
|
+
end
|
153
|
+
|
154
|
+
def capture_limit_exceeded?
|
155
|
+
mutex.synchronize do
|
156
|
+
max_capture_events > 0 && capture_events_count >= max_capture_events
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def disable_capturing!
|
161
|
+
mutex.synchronize do
|
162
|
+
@enabled = false
|
163
|
+
@rspec_tracepoint&.disable
|
164
|
+
@minitest_trace&.disable
|
165
|
+
@exception_trace&.disable
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
150
169
|
def increment_capture_events_count
|
151
170
|
mutex.synchronize do
|
171
|
+
@capture_events_count ||= 0
|
172
|
+
@max_capture_events ||= -1
|
152
173
|
@capture_events_count += 1
|
153
|
-
# Check if we've hit the limit
|
154
|
-
if @max_capture_events > 0 && @capture_events_count >= @max_capture_events
|
155
|
-
# puts "EnhancedErrors: max_capture_events limit (#{@max_capture_events}) reached, disabling capturing."
|
156
|
-
@enabled = false
|
157
|
-
end
|
158
174
|
end
|
159
175
|
end
|
160
176
|
|
161
177
|
def reset_capture_events_count
|
162
178
|
mutex.synchronize do
|
163
179
|
@capture_events_count = 0
|
164
|
-
@enabled = true
|
165
|
-
@rspec_tracepoint.enable if @rspec_tracepoint
|
166
|
-
@trace.enable if @trace
|
167
180
|
end
|
168
181
|
end
|
169
182
|
|
@@ -184,6 +197,19 @@ class EnhancedErrors
|
|
184
197
|
end
|
185
198
|
end
|
186
199
|
|
200
|
+
def override_rspec_message(example, binding_or_bindings)
|
201
|
+
exception_obj = example.exception
|
202
|
+
case exception_obj
|
203
|
+
when nil
|
204
|
+
return nil
|
205
|
+
when RSpec::Core::MultipleExceptionError
|
206
|
+
override_exception_message(exception_obj.all_exceptions.first, binding_or_bindings)
|
207
|
+
else
|
208
|
+
override_exception_message(exception_obj, binding_or_bindings)
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
187
213
|
def override_exception_message(exception, binding_or_bindings)
|
188
214
|
return nil unless exception
|
189
215
|
rspec_binding = !(binding_or_bindings.nil? || binding_or_bindings.empty?)
|
@@ -211,8 +237,8 @@ class EnhancedErrors
|
|
211
237
|
|
212
238
|
def enhance_exceptions!(enabled: true, debug: false, capture_events: nil, override_messages: false, **options, &block)
|
213
239
|
mutex.synchronize do
|
214
|
-
@
|
215
|
-
@
|
240
|
+
@exception_trace&.disable
|
241
|
+
@exception_trace = nil
|
216
242
|
|
217
243
|
@output_format = nil
|
218
244
|
@eligible_for_capture = nil
|
@@ -220,7 +246,9 @@ class EnhancedErrors
|
|
220
246
|
@override_messages = override_messages
|
221
247
|
|
222
248
|
# Ensure these are not nil
|
223
|
-
|
249
|
+
if @max_capture_events.nil?
|
250
|
+
@max_capture_events = -1
|
251
|
+
end
|
224
252
|
@capture_events_count = 0
|
225
253
|
|
226
254
|
@rspec_failure_message_loaded = true
|
@@ -256,13 +284,13 @@ class EnhancedErrors
|
|
256
284
|
end
|
257
285
|
|
258
286
|
events = @capture_events ? @capture_events.to_a : default_capture_events
|
259
|
-
@
|
287
|
+
@exception_trace = TracePoint.new(*events) do |tp|
|
260
288
|
handle_tracepoint_event(tp)
|
261
289
|
end
|
262
290
|
|
263
291
|
# Only enable trace if still enabled and not limited
|
264
292
|
if @enabled && (@max_capture_events == -1 || @capture_events_count < @max_capture_events)
|
265
|
-
@
|
293
|
+
@exception_trace.enable
|
266
294
|
end
|
267
295
|
end
|
268
296
|
end
|
@@ -278,23 +306,12 @@ class EnhancedErrors
|
|
278
306
|
end
|
279
307
|
end
|
280
308
|
|
281
|
-
def safely_prepend_rspec_custom_failure_message
|
282
|
-
mutex.synchronize do
|
283
|
-
return if @rspec_failure_message_loaded
|
284
|
-
if defined?(RSpec::Core::Example) && !RSpec::Core::Example < Enhanced::Integrations::RSpecErrorFailureMessage
|
285
|
-
RSpec::Core::Example.prepend(Enhanced::Integrations::RSpecErrorFailureMessage)
|
286
|
-
@rspec_failure_message_loaded = true
|
287
|
-
end
|
288
|
-
end
|
289
|
-
rescue => e
|
290
|
-
puts "Failed to prepend RSpec custom failure message: #{e.message}"
|
291
|
-
end
|
292
|
-
|
293
309
|
def is_a_minitest?(klass)
|
294
310
|
klass.ancestors.include?(Minitest::Test) && klass.name != 'Minitest::Test'
|
295
311
|
end
|
296
312
|
|
297
313
|
def start_minitest_binding_capture
|
314
|
+
return if capture_limit_exceeded?
|
298
315
|
mutex.synchronize do
|
299
316
|
@minitest_trace = TracePoint.new(:return) do |tp|
|
300
317
|
next unless tp.method_id.to_s.start_with?('test_') && is_a_minitest?(tp.defined_class)
|
@@ -305,6 +322,7 @@ class EnhancedErrors
|
|
305
322
|
end
|
306
323
|
|
307
324
|
def stop_minitest_binding_capture
|
325
|
+
disable_capturing! if capture_limit_exceeded?
|
308
326
|
mutex.synchronize do
|
309
327
|
@minitest_trace&.disable
|
310
328
|
@minitest_trace = nil
|
@@ -312,26 +330,48 @@ class EnhancedErrors
|
|
312
330
|
end
|
313
331
|
end
|
314
332
|
|
333
|
+
def class_to_string(klass)
|
334
|
+
return '' if klass.nil?
|
335
|
+
if klass.singleton_class?
|
336
|
+
(match = klass.to_s.match(/#<Class:(.*?)>/)) ? match[1] : klass.to_s
|
337
|
+
else
|
338
|
+
klass.to_s
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
def is_rspec_example?(tracepoint)
|
343
|
+
tracepoint.method_id.nil? && !(tracepoint.path.include?('rspec')) && tracepoint.path.end_with?('_spec.rb')
|
344
|
+
end
|
345
|
+
|
315
346
|
def start_rspec_binding_capture
|
347
|
+
return if capture_limit_exceeded?
|
316
348
|
mutex.synchronize do
|
317
349
|
@rspec_example_binding = nil
|
318
350
|
@capture_next_binding = false
|
319
351
|
@rspec_tracepoint&.disable
|
320
|
-
@enabled = true if @enabled.nil?
|
321
352
|
|
322
353
|
@rspec_tracepoint = TracePoint.new(:raise, :b_return) do |tp|
|
323
|
-
#
|
354
|
+
# puts "name #{tp.raised_exception.class.name rescue ''} method:#{tp.method_id} tp.binding:#{tp.binding.local_variables rescue ''}"
|
355
|
+
# puts "event: #{tp.event} defined_class#{class_to_string(tp.defined_class)} #{tp.path}:#{tp.lineno} #{tp.callee_id} "
|
356
|
+
# This trickery below is to help us identify the anonymous block return we want to grab
|
357
|
+
# Very kluge-y and edge cases have grown it, but it works
|
324
358
|
if tp.event == :b_return
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
359
|
+
if RSPEC_HANDLER_NAMES.include?(class_to_string(tp.defined_class))
|
360
|
+
@capture_next_binding = :next
|
361
|
+
next
|
362
|
+
end
|
363
|
+
next unless @capture_next_binding
|
364
|
+
|
365
|
+
if @capture_next_binding == :next || @capture_next_binding == :next_matching && is_rspec_example?(tp)
|
366
|
+
increment_capture_events_count
|
367
|
+
@capture_next_binding = false
|
368
|
+
@rspec_example_binding = tp.binding
|
331
369
|
end
|
332
370
|
elsif tp.event == :raise
|
333
|
-
|
334
|
-
|
371
|
+
class_name = tp.raised_exception.class.name
|
372
|
+
case class_name
|
373
|
+
when 'RSpec::Expectations::ExpectationNotMetError'
|
374
|
+
@capture_next_binding = :next_matching
|
335
375
|
else
|
336
376
|
handle_tracepoint_event(tp)
|
337
377
|
end
|
@@ -342,6 +382,7 @@ class EnhancedErrors
|
|
342
382
|
end
|
343
383
|
|
344
384
|
def stop_rspec_binding_capture
|
385
|
+
disable_capturing! if capture_limit_exceeded?
|
345
386
|
mutex.synchronize do
|
346
387
|
@rspec_tracepoint&.disable
|
347
388
|
@rspec_tracepoint = nil
|
@@ -567,6 +608,7 @@ class EnhancedErrors
|
|
567
608
|
|
568
609
|
def handle_tracepoint_event(tp)
|
569
610
|
# Check enabled outside the synchronized block for speed, but still safe due to re-check inside.
|
611
|
+
enforce_capture_limit!
|
570
612
|
return unless mutex.synchronize { @enabled }
|
571
613
|
return if Thread.current[:enhanced_errors_processing] || Thread.current[:on_capture] || ignored_exception?(tp.raised_exception)
|
572
614
|
|
@@ -712,7 +754,7 @@ class EnhancedErrors
|
|
712
754
|
end
|
713
755
|
|
714
756
|
def valid_capture_events?(capture_events)
|
715
|
-
capture_events.is_a?(Array) && [:raise, :rescue]
|
757
|
+
capture_events.is_a?(Array) && capture_events.all? { |ev| [:raise, :rescue].include?(ev) }
|
716
758
|
end
|
717
759
|
|
718
760
|
def extract_arguments(tp, method_name)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: enhanced_errors
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Beland
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-12-
|
11
|
+
date: 2024-12-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|
@@ -90,6 +90,7 @@ files:
|
|
90
90
|
- doc/Enhanced/Integrations/RSpecErrorFailureMessage.html
|
91
91
|
- doc/EnhancedErrors.html
|
92
92
|
- doc/Exception.html
|
93
|
+
- doc/Minitest.html
|
93
94
|
- doc/_index.html
|
94
95
|
- doc/class_list.html
|
95
96
|
- doc/css/common.css
|
@@ -135,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
135
136
|
- !ruby/object:Gem::Version
|
136
137
|
version: '0'
|
137
138
|
requirements: []
|
138
|
-
rubygems_version: 3.
|
139
|
+
rubygems_version: 3.5.22
|
139
140
|
signing_key:
|
140
141
|
specification_version: 4
|
141
142
|
summary: Automatically enhance your errors with messages containing variable values
|