enhanced_errors 0.1.4 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.yardoc/checksums +2 -2
- data/.yardoc/object_types +0 -0
- data/.yardoc/objects/root.dat +0 -0
- data/README.md +57 -10
- data/benchmark/memory_bench.rb +78 -0
- data/doc/Binding.html +1 -1
- data/doc/Colors.html +1 -1
- data/doc/Debugging.html +1 -1
- data/doc/EnhancedErrors.html +197 -183
- data/doc/ErrorEnhancements.html +15 -9
- data/doc/_index.html +1 -1
- data/doc/file.README.html +42 -53
- data/doc/index.html +42 -53
- data/doc/top-level-namespace.html +38 -1
- data/enhanced_errors.gemspec +2 -2
- data/lib/enhanced_errors.rb +69 -12
- data/lib/error_enhancements.rb +7 -4
- metadata +6 -5
data/lib/enhanced_errors.rb
CHANGED
@@ -5,6 +5,20 @@ require_relative 'colors'
|
|
5
5
|
require_relative 'error_enhancements'
|
6
6
|
require_relative 'binding'
|
7
7
|
|
8
|
+
# While we could just catch StandardError, we would miss a number of things.
|
9
|
+
|
10
|
+
IGNORED_EXCEPTIONS = [
|
11
|
+
SystemExit,
|
12
|
+
NoMemoryError,
|
13
|
+
SignalException,
|
14
|
+
Interrupt,
|
15
|
+
ScriptError,
|
16
|
+
LoadError,
|
17
|
+
NotImplementedError,
|
18
|
+
SyntaxError,
|
19
|
+
SystemStackError
|
20
|
+
]
|
21
|
+
|
8
22
|
# The EnhancedErrors class provides mechanisms to enhance exception handling by capturing
|
9
23
|
# additional context such as binding information, variables, and method arguments when exceptions are raised.
|
10
24
|
# It offers customization options for formatting and filtering captured data.
|
@@ -147,7 +161,8 @@ class EnhancedErrors
|
|
147
161
|
# @param options [Hash] Additional configuration options.
|
148
162
|
# @yield [void] A block for additional configuration.
|
149
163
|
# @return [void]
|
150
|
-
def enhance!(enabled: true, debug: false, **options, &block)
|
164
|
+
def enhance!(enabled: true, debug: false, capture_events: default_capture_events, **options, &block)
|
165
|
+
capture_events = Array(capture_events)
|
151
166
|
@output_format = nil
|
152
167
|
@eligible_for_capture = nil
|
153
168
|
@original_global_variables = nil
|
@@ -160,6 +175,7 @@ class EnhancedErrors
|
|
160
175
|
@debug = debug
|
161
176
|
@original_global_variables = global_variables
|
162
177
|
|
178
|
+
validate_and_set_capture_events(capture_events)
|
163
179
|
options.each do |key, value|
|
164
180
|
setter_method = "#{key}="
|
165
181
|
if respond_to?(setter_method)
|
@@ -311,7 +327,7 @@ class EnhancedErrors
|
|
311
327
|
def apply_skip_list(binding_info)
|
312
328
|
unless @debug
|
313
329
|
variables = binding_info[:variables]
|
314
|
-
variables[:instances]&.reject! { |var, _| skip_list.include?(var) || var.to_s.start_with?('@
|
330
|
+
variables[:instances]&.reject! { |var, _| skip_list.include?(var) || (var.to_s.start_with?('@_') && !@debug) }
|
315
331
|
variables[:locals]&.reject! { |var, _| skip_list.include?(var) }
|
316
332
|
variables[:globals]&.reject! { |var, _| skip_list.include?(var) }
|
317
333
|
end
|
@@ -323,7 +339,7 @@ class EnhancedErrors
|
|
323
339
|
# @param binding_info [Hash] The binding information to validate.
|
324
340
|
# @return [Hash, nil] The validated binding information or `nil` if invalid.
|
325
341
|
def validate_binding_format(binding_info)
|
326
|
-
unless binding_info.keys.include?(:
|
342
|
+
unless binding_info.keys.include?(:capture_event) && binding_info[:variables].is_a?(Hash)
|
327
343
|
puts "Invalid binding_info format."
|
328
344
|
return nil
|
329
345
|
end
|
@@ -335,8 +351,8 @@ class EnhancedErrors
|
|
335
351
|
# @param binding_info [Hash] The binding information to format.
|
336
352
|
# @return [String] The formatted string.
|
337
353
|
def binding_info_string(binding_info)
|
338
|
-
|
339
|
-
result = "#{Colors.red(
|
354
|
+
capture_event = binding_info[:capture_event].to_s.capitalize
|
355
|
+
result = "#{Colors.red(capture_event)}: #{Colors.blue(binding_info[:source])}"
|
340
356
|
|
341
357
|
result += method_and_args_desc(binding_info[:method_and_args])
|
342
358
|
|
@@ -348,7 +364,6 @@ class EnhancedErrors
|
|
348
364
|
|
349
365
|
instance_vars_to_display = variables[:instances] || {}
|
350
366
|
|
351
|
-
|
352
367
|
if instance_vars_to_display && !instance_vars_to_display.empty?
|
353
368
|
result += "\n#{Colors.green('Instances:')}\n#{variable_description(instance_vars_to_display)}"
|
354
369
|
end
|
@@ -365,6 +380,11 @@ class EnhancedErrors
|
|
365
380
|
result = result[0...max_length] + "... (truncated)"
|
366
381
|
end
|
367
382
|
result + "\n"
|
383
|
+
rescue => e
|
384
|
+
# we swallow and don't re-raise to avoid any recursion problems. We don't want to
|
385
|
+
# mess up the original exception handling.
|
386
|
+
puts "EnhancedErrors error in binding_info_string: #{e.message} #{e.backtrace}"
|
387
|
+
return ''
|
368
388
|
end
|
369
389
|
|
370
390
|
private
|
@@ -375,11 +395,10 @@ class EnhancedErrors
|
|
375
395
|
def start_tracing
|
376
396
|
return if @trace && @trace.enabled?
|
377
397
|
|
378
|
-
events = [:raise]
|
379
|
-
events << :rescue if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.3.0')
|
398
|
+
events = @capture_events ? @capture_events.to_a : [:raise]
|
380
399
|
|
381
400
|
@trace = TracePoint.new(*events) do |tp|
|
382
|
-
next if Thread.current[:enhanced_errors_processing] || tp.raised_exception
|
401
|
+
next if Thread.current[:enhanced_errors_processing] || IGNORED_EXCEPTIONS.include?(tp.raised_exception)
|
383
402
|
Thread.current[:enhanced_errors_processing] = true
|
384
403
|
exception = tp.raised_exception
|
385
404
|
capture_me = EnhancedErrors.eligible_for_capture.call(exception)
|
@@ -425,10 +444,9 @@ class EnhancedErrors
|
|
425
444
|
globals = (global_variables - @original_global_variables).map { |var|
|
426
445
|
[var, get_global_variable_value(var)]
|
427
446
|
}.to_h
|
428
|
-
puts "Global Variables: #{globals.inspect}"
|
429
447
|
end
|
430
448
|
|
431
|
-
|
449
|
+
capture_event = tp.event.to_s # 'raise' or 'rescue'
|
432
450
|
location = "#{tp.path}:#{tp.lineno}"
|
433
451
|
|
434
452
|
binding_info = {
|
@@ -444,7 +462,7 @@ class EnhancedErrors
|
|
444
462
|
globals: globals
|
445
463
|
},
|
446
464
|
exception: exception.class.name,
|
447
|
-
|
465
|
+
capture_event: capture_event.to_s
|
448
466
|
}
|
449
467
|
|
450
468
|
if on_capture_hook
|
@@ -469,6 +487,7 @@ class EnhancedErrors
|
|
469
487
|
@trace.enable
|
470
488
|
end
|
471
489
|
|
490
|
+
|
472
491
|
# Retrieves the current test name from RSpec, if available.
|
473
492
|
#
|
474
493
|
# @return [String, nil] The current test name or `nil` if not in a test context.
|
@@ -480,6 +499,42 @@ class EnhancedErrors
|
|
480
499
|
nil
|
481
500
|
end
|
482
501
|
|
502
|
+
# Helper method to determine the default capture types based on Ruby version
|
503
|
+
#
|
504
|
+
# @return [Set<Symbol>] The default set of capture types
|
505
|
+
def default_capture_events
|
506
|
+
default_events = [:raise]
|
507
|
+
default_events << :rescue if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.3.0')
|
508
|
+
Set.new(default_events)
|
509
|
+
end
|
510
|
+
|
511
|
+
def validate_and_set_capture_events(capture_events)
|
512
|
+
if capture_events.nil? || !valid_capture_events?(capture_events)
|
513
|
+
puts "EnhancedErrors: Invalid capture_events provided. Falling back to defaults."
|
514
|
+
capture_events = default_capture_events
|
515
|
+
end
|
516
|
+
|
517
|
+
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.3.0') && capture_events.include?(:rescue)
|
518
|
+
puts "EnhancedErrors: Warning: :rescue capture_event is not supported in Ruby versions below 3.3.0 and will be ignored."
|
519
|
+
capture_events.delete(:rescue)
|
520
|
+
end
|
521
|
+
|
522
|
+
if capture_events.empty?
|
523
|
+
puts "No valid capture_events provided to EnhancedErrors.enhance! Falling back to defaults."
|
524
|
+
capture_events = default_capture_events
|
525
|
+
end
|
526
|
+
|
527
|
+
@capture_events = capture_events.to_a
|
528
|
+
end
|
529
|
+
|
530
|
+
|
531
|
+
# Validate capture_events: must be an Array or Set containing only :raise and/or :rescue.
|
532
|
+
def valid_capture_events?(capture_events)
|
533
|
+
return false unless capture_events.is_a?(Array) || capture_events.is_a?(Set)
|
534
|
+
valid_types = [:raise, :rescue].to_set
|
535
|
+
capture_events.to_set.subset?(valid_types)
|
536
|
+
end
|
537
|
+
|
483
538
|
# Extracts method arguments from the TracePoint binding.
|
484
539
|
#
|
485
540
|
# @param tp [TracePoint] The current TracePoint.
|
@@ -560,6 +615,8 @@ class EnhancedErrors
|
|
560
615
|
# @return [String] The formatted variable.
|
561
616
|
def format_variable(variable)
|
562
617
|
(awesome_print_available? && Colors.enabled?) ? variable.ai : variable.inspect
|
618
|
+
rescue => e
|
619
|
+
return "#{variable.to_s.truncate(30)}: [Inspection Error]"
|
563
620
|
end
|
564
621
|
|
565
622
|
# Checks if the `AwesomePrint` gem is available.
|
data/lib/error_enhancements.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
module ErrorEnhancements
|
2
2
|
def message
|
3
3
|
original_message = super()
|
4
|
-
|
4
|
+
if original_message.include?(variables_message)
|
5
|
+
original_message
|
6
|
+
else
|
7
|
+
"#{original_message}\n#{variables_message}"
|
8
|
+
end
|
5
9
|
rescue => e
|
6
|
-
puts "Error in message method: #{e.message}"
|
7
10
|
original_message
|
8
11
|
end
|
9
12
|
|
@@ -31,7 +34,7 @@ module ErrorEnhancements
|
|
31
34
|
bindings_of_interest = []
|
32
35
|
|
33
36
|
binding_infos.each do |info|
|
34
|
-
if info[:
|
37
|
+
if info[:capture_event] == 'raise' && !info[:library]
|
35
38
|
bindings_of_interest << info
|
36
39
|
break
|
37
40
|
end
|
@@ -43,7 +46,7 @@ module ErrorEnhancements
|
|
43
46
|
|
44
47
|
# find the last rescue binding if there is one
|
45
48
|
binding_infos.reverse.each do |info|
|
46
|
-
if info[:
|
49
|
+
if info[:capture_event] == 'rescue'
|
47
50
|
bindings_of_interest << info
|
48
51
|
break
|
49
52
|
end
|
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: 0.1.
|
4
|
+
version: 0.1.6
|
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-10
|
11
|
+
date: 2024-11-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|
@@ -52,9 +52,9 @@ dependencies:
|
|
52
52
|
- - ">"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0.9'
|
55
|
-
description:
|
56
|
-
|
57
|
-
|
55
|
+
description: 'EnhancedErrors will automatically enhance your errors with messages
|
56
|
+
containing variable values from the moment they were raised, using no extra dependencies,
|
57
|
+
and only Ruby''s built-in TracePoint. '
|
58
58
|
email:
|
59
59
|
executables: []
|
60
60
|
extensions: []
|
@@ -68,6 +68,7 @@ files:
|
|
68
68
|
- LICENSE
|
69
69
|
- README.md
|
70
70
|
- benchmark/benchmark.rb
|
71
|
+
- benchmark/memory_bench.rb
|
71
72
|
- benchmark/stackprofile.rb
|
72
73
|
- doc/Binding.html
|
73
74
|
- doc/Colors.html
|