enhanced_errors 3.0.3 → 3.0.4

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.
@@ -1,55 +1,54 @@
1
1
  # exception.rb
2
- require_relative 'enhanced_exception_context'
3
-
4
- module ExceptionBindingInfos
5
- def binding_infos
6
- ctx = EnhancedExceptionContext.context_for(self)
7
- unless ctx
8
- ctx = Context.new
9
- EnhancedExceptionContext.store_context(self, ctx)
2
+ require_relative 'exception_context'
3
+
4
+ module Enhanced
5
+ module ExceptionBindingInfos
6
+ def binding_infos
7
+ ctx = Enhanced::ExceptionContext.context_for(self)
8
+ unless ctx
9
+ ctx = Context.new
10
+ Enhanced::ExceptionContext.store_context(self, ctx)
11
+ end
12
+ ctx.binding_infos
10
13
  end
11
- ctx.binding_infos
12
- end
13
14
 
14
- def captured_variables
15
- if binding_infos.any?
15
+ def captured_variables
16
+ return '' unless binding_infos&.any?
16
17
  bindings_of_interest = select_binding_infos
17
18
  EnhancedErrors.format(bindings_of_interest)
18
- else
19
+ rescue
19
20
  ''
20
21
  end
21
- rescue
22
- ''
23
- end
24
22
 
25
- private
23
+ private
26
24
 
27
- def select_binding_infos
28
- # Preference:
29
- # 1. First 'raise' binding that isn't from a library (gem).
30
- # 2. If none, the first binding.
31
- # 3. The last 'rescue' binding if available.
25
+ def select_binding_infos
26
+ # Preference:
27
+ # 1. First 'raise' binding that isn't from a library (gem).
28
+ # 2. If none, the first binding.
29
+ # 3. The last 'rescue' binding if available.
32
30
 
33
- bindings_of_interest = []
31
+ bindings_of_interest = []
34
32
 
35
- first_app_raise = binding_infos.find do |info|
36
- info[:capture_event] == 'raise' && !info[:library]
37
- end
38
- bindings_of_interest << first_app_raise if first_app_raise
33
+ first_app_raise = binding_infos.find do |info|
34
+ info[:capture_event] == 'raise' && !info[:library]
35
+ end
36
+ bindings_of_interest << first_app_raise if first_app_raise
39
37
 
40
- if bindings_of_interest.empty? && binding_infos.first
41
- bindings_of_interest << binding_infos.first
42
- end
38
+ if bindings_of_interest.empty? && binding_infos.first
39
+ bindings_of_interest << binding_infos.first
40
+ end
43
41
 
44
- last_rescue = binding_infos.reverse.find do |info|
45
- info[:capture_event] == 'rescue'
46
- end
47
- bindings_of_interest << last_rescue if last_rescue
42
+ last_rescue = binding_infos.reverse.find do |info|
43
+ info[:capture_event] == 'rescue'
44
+ end
45
+ bindings_of_interest << last_rescue if last_rescue
48
46
 
49
- bindings_of_interest.compact
47
+ bindings_of_interest.compact
48
+ end
50
49
  end
51
50
  end
52
51
 
53
52
  class Exception
54
- prepend ExceptionBindingInfos
53
+ prepend Enhanced::ExceptionBindingInfos
55
54
  end
@@ -0,0 +1,49 @@
1
+ require 'weakref'
2
+
3
+ require_relative 'context'
4
+
5
+ require 'weakref'
6
+ require 'monitor'
7
+
8
+ module Enhanced
9
+ module ExceptionContext
10
+ extend self
11
+
12
+ REGISTRY = {}
13
+ MUTEX = Monitor.new
14
+
15
+ def store_context(exception, context)
16
+ MUTEX.synchronize do
17
+ REGISTRY[exception.object_id] = { weak_exc: WeakRef.new(exception), context: context }
18
+ end
19
+ end
20
+
21
+ def context_for(exception)
22
+ MUTEX.synchronize do
23
+ entry = REGISTRY[exception.object_id]
24
+ return nil unless entry
25
+
26
+ begin
27
+ _ = entry[:weak_exc].__getobj__ # ensure exception is still alive
28
+ entry[:context]
29
+ rescue RefError
30
+ # Exception no longer alive, clean up
31
+ REGISTRY.delete(exception.object_id)
32
+ nil
33
+ end
34
+ end
35
+ end
36
+
37
+ def clear_context(exception)
38
+ MUTEX.synchronize do
39
+ REGISTRY.delete(exception.object_id)
40
+ end
41
+ end
42
+
43
+ def clear_all
44
+ MUTEX.synchronize do
45
+ REGISTRY.clear
46
+ end
47
+ end
48
+ end
49
+ end
@@ -9,7 +9,7 @@ module Minitest
9
9
  begin
10
10
  binding_infos = EnhancedErrors.stop_minitest_binding_capture
11
11
  EnhancedErrors.override_exception_message(result.failures.last, binding_infos) if result.failures.any?
12
- EnhancedExceptionContext.clear_all
12
+ Enhanced::ExceptionContext.clear_all
13
13
  rescue => e
14
14
  puts "Ignored error during error enhancement: #{e}"
15
15
  end
@@ -4,12 +4,12 @@ require 'set'
4
4
  require 'json'
5
5
  require 'monitor'
6
6
 
7
- require_relative 'enhanced/colors'
8
- require_relative 'enhanced/exception'
7
+ module Enhanced; end
9
8
 
10
- IGNORED_EXCEPTIONS = %w[SystemExit NoMemoryError SignalException Interrupt ScriptError LoadError
11
- NotImplementedError SyntaxError RSpec::Expectations::ExpectationNotMetError
12
- RSpec::Matchers::BuiltIn::RaiseError SystemStackError Psych::BadAlias]
9
+ # Exceptions we could handle but overlook for other reasons. These class constants are not always loaded
10
+ # and generally are only be available when `required`, so we detect them by strings.
11
+ IGNORED_EXCEPTIONS = %w[RSpec::Expectations::ExpectationNotMetError RSpec::Matchers::BuiltIn::RaiseError
12
+ JSON::ParserError Zlib::Error OpenSSL::SSL::SSLError Psych::Exception]
13
13
 
14
14
  class EnhancedErrors
15
15
  extend ::Enhanced
@@ -45,13 +45,8 @@ class EnhancedErrors
45
45
  ].freeze
46
46
 
47
47
  RAILS_SKIP_LIST = [
48
- :@new_record,
49
- :@attributes,
50
48
  :@association_cache,
51
- :@readonly,
52
- :@previously_new_record,
53
49
  :@_routes,
54
- :@routes,
55
50
  :@app,
56
51
  :@arel_table,
57
52
  :@assertion_instance,
@@ -127,7 +122,7 @@ class EnhancedErrors
127
122
  mutex.synchronize { @max_capture_length || DEFAULT_MAX_CAPTURE_LENGTH }
128
123
  end
129
124
 
130
- def max_capture_length=(val)
125
+ def max_capture_length=(value)
131
126
  mutex.synchronize { @max_capture_length = value }
132
127
  end
133
128
 
@@ -140,7 +135,6 @@ class EnhancedErrors
140
135
  end
141
136
  end
142
137
 
143
-
144
138
  def reset!
145
139
  mutex.synchronize do
146
140
  @rspec_tracepoint&.disable
@@ -155,7 +149,7 @@ class EnhancedErrors
155
149
 
156
150
  def skip_list
157
151
  mutex.synchronize do
158
- @skip_list ||= DEFAULT_SKIP_LIST
152
+ @skip_list ||= DEFAULT_SKIP_LIST.to_set
159
153
  end
160
154
  end
161
155
 
@@ -187,12 +181,13 @@ class EnhancedErrors
187
181
 
188
182
  def add_to_skip_list(*vars)
189
183
  mutex.synchronize do
190
- @skip_list.concat(vars)
184
+ @skip_list.add(*vars)
191
185
  end
192
186
  end
193
187
 
194
188
  def enhance_exceptions!(enabled: true, debug: false, capture_events: nil, override_messages: false, **options, &block)
195
189
  mutex.synchronize do
190
+ ensure_extensions_are_required
196
191
  @exception_trace&.disable
197
192
  @exception_trace = nil
198
193
 
@@ -223,10 +218,11 @@ class EnhancedErrors
223
218
 
224
219
  events = @capture_events ? @capture_events.to_a : default_capture_events
225
220
  @exception_trace = TracePoint.new(*events) do |tp|
221
+ return unless exception_is_handleable?(tp.raised_exception)
226
222
  handle_tracepoint_event(tp)
227
223
  end
228
224
 
229
- @exception_trace.enable if @enabled
225
+ @exception_trace&.enable if @enabled
230
226
  end
231
227
  end
232
228
 
@@ -235,7 +231,8 @@ class EnhancedErrors
235
231
  end
236
232
 
237
233
  def start_minitest_binding_capture
238
- EnhancedExceptionContext.clear_all
234
+ ensure_extensions_are_required
235
+ Enhanced::ExceptionContext.clear_all
239
236
  @enabled = true if @enabled.nil?
240
237
  return unless @enabled
241
238
  mutex.synchronize do
@@ -243,7 +240,7 @@ class EnhancedErrors
243
240
  next unless tp.method_id.to_s.start_with?('test_') && is_a_minitest?(tp.defined_class)
244
241
  @minitest_test_binding = tp.binding
245
242
  end
246
- @minitest_trace.enable
243
+ @minitest_trace&.enable
247
244
  end
248
245
  end
249
246
 
@@ -269,7 +266,8 @@ class EnhancedErrors
269
266
  end
270
267
 
271
268
  def start_rspec_binding_capture
272
- EnhancedExceptionContext.clear_all
269
+ ensure_extensions_are_required
270
+ Enhanced::ExceptionContext.clear_all
273
271
  @enabled = true if @enabled.nil?
274
272
  return unless @enabled
275
273
 
@@ -277,21 +275,29 @@ class EnhancedErrors
277
275
  @rspec_example_binding = nil
278
276
  @capture_next_binding = false
279
277
  @rspec_tracepoint&.disable
280
-
281
278
  @rspec_tracepoint = TracePoint.new(:raise) do |tp|
282
- class_name = tp.raised_exception.class.name
283
- case class_name
284
- when 'RSpec::Expectations::ExpectationNotMetError'
285
- start_rspec_binding_trap
286
- else
287
- handle_tracepoint_event(tp)
288
- end
279
+ return unless exception_is_handleable?(tp.raised_exception)
280
+ class_name = tp.raised_exception.class.name
281
+ case class_name
282
+ when 'RSpec::Expectations::ExpectationNotMetError'
283
+ start_rspec_binding_trap
284
+ else
285
+ handle_tracepoint_event(tp)
289
286
  end
290
287
  end
291
- @rspec_tracepoint.enable
288
+ end
289
+ @rspec_tracepoint&.enable
292
290
  end
293
291
 
294
- # grab the next rspec binding that goes by, and then stop the expensive listening trace
292
+ # Behavior: Grabs the next rspec spec binding that goes by, and stops the more-expensive b_return trace.
293
+ # This part of RSpec has been stable, since 2015, so although this is kluge-y, it is stable.
294
+ # The optimization does a 2-3x on spec speed vs. opening up the Tracepoint. With it,
295
+ # things are pretty close in speed to plain rspec.
296
+ # Should the behavior change this can be updated by using a trace to print out items
297
+ # and their local variables then, find the exception or call that goes by right
298
+ # before the spec blocks with the variables, and use that to narrow-down the costly part of
299
+ # the probe to just this point in time. The good news is that
300
+ # this part is test-time only, and this optimization and kluge only applies to RSpec.
295
301
  def start_rspec_binding_trap
296
302
  @rspec_binding_trap = TracePoint.new(:b_return) do |tp|
297
303
  # kluge-y hack and will be a pain to maintain
@@ -302,13 +308,12 @@ class EnhancedErrors
302
308
  next unless @capture_next_binding
303
309
  @capture_next_binding = false
304
310
  @rspec_example_binding = tp.binding
305
- @rspec_binding_trap.disable
311
+ @rspec_binding_trap&.disable
306
312
  @rspec_binding_trap = nil
307
313
  end
308
- @rspec_binding_trap.enable
314
+ @rspec_binding_trap&.enable
309
315
  end
310
316
 
311
-
312
317
  def stop_rspec_binding_capture
313
318
  mutex.synchronize do
314
319
  @rspec_tracepoint&.disable
@@ -327,6 +332,8 @@ class EnhancedErrors
327
332
 
328
333
  locals = b.local_variables.map { |var| [var, safe_local_variable_get(b, var)] }.to_h
329
334
  receiver = b.receiver
335
+ return unless safe_to_inspect?(receiver)
336
+
330
337
  instance_vars = receiver.instance_variables
331
338
  instances = instance_vars.map { |var| [var, safe_instance_variable_get(receiver, var)] }.to_h
332
339
 
@@ -355,7 +362,7 @@ class EnhancedErrors
355
362
  globals: {}
356
363
  },
357
364
  exception: 'NoException',
358
- capture_event: 'RSpecContext'
365
+ capture_event: 'test_context'
359
366
  }
360
367
 
361
368
  default_on_capture(binding_info)
@@ -437,11 +444,7 @@ class EnhancedErrors
437
444
  env = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
438
445
  @output_format = case env
439
446
  when 'development', 'test'
440
- if running_in_ci?
441
- :plaintext
442
- else
443
- :terminal
444
- end
447
+ running_in_ci? ? :plaintext : :terminal
445
448
  when 'production'
446
449
  :json
447
450
  else
@@ -453,28 +456,32 @@ class EnhancedErrors
453
456
  def running_in_ci?
454
457
  mutex.synchronize do
455
458
  return @running_in_ci if defined?(@running_in_ci)
456
-
457
459
  @running_in_ci = CI_ENV_VARS.any? { |_, value| value.to_s.downcase == 'true' }
458
460
  end
459
461
  end
460
462
 
461
463
  def apply_skip_list(binding_info)
462
- mutex.synchronize do
463
- variables = binding_info[:variables]
464
- variables[:instances]&.reject! { |var, _| skip_list.include?(var) || (var.to_s.start_with?('@_') && !@debug) }
465
- variables[:locals]&.reject! { |var, _| skip_list.include?(var) }
466
- if @debug
467
- variables[:globals]&.reject! { |var, _| skip_list.include?(var) }
468
- end
464
+ binding_info[:variables][:instances]&.reject! { |var, _| skip_list.include?(var) || (var.to_s[0, 2] == '@_' && !@debug) }
465
+ binding_info[:variables][:locals]&.reject! { |var, _| skip_list.include?(var) }
466
+ if @debug
467
+ binding_info[:variables][:globals]&.reject! { |var, _| skip_list.include?(var) }
469
468
  end
470
469
  binding_info
471
470
  end
472
471
 
473
472
  def validate_binding_format(binding_info)
474
- unless binding_info.keys.include?(:capture_event) && binding_info[:variables].is_a?(Hash)
475
- return nil
473
+ binding_info.keys.include?(:capture_event) && binding_info[:variables].is_a?(Hash)
474
+ end
475
+
476
+ # Here, we are detecting BasicObject, which is surprisingly annoying.
477
+ # We also, importantly, need to detect descendants, as they will also present with a
478
+ # lack of :respond_to? and any other useful method for us.
479
+ def safe_to_inspect?(obj)
480
+ begin
481
+ obj.class
482
+ rescue NoMethodError
483
+ return false
476
484
  end
477
- binding_info
478
485
  end
479
486
 
480
487
  def binding_info_string(binding_info)
@@ -524,7 +531,6 @@ class EnhancedErrors
524
531
 
525
532
  private
526
533
 
527
-
528
534
  def handle_tracepoint_event(tp)
529
535
  # Check enabled outside the synchronized block for speed, but still safe due to re-check inside.
530
536
  return unless enabled
@@ -533,9 +539,13 @@ class EnhancedErrors
533
539
  Thread.current[:enhanced_errors_processing] = true
534
540
  exception = tp.raised_exception
535
541
 
536
- capture_me = mutex.synchronize do
537
- !exception.frozen? && (@eligible_for_capture || method(:default_eligible_for_capture)).call(exception)
538
- end
542
+ return if exception.frozen?
543
+
544
+ capture_me = if @eligible_for_capture
545
+ @eligible_for_capture.call(exception)
546
+ else
547
+ default_eligible_for_capture(exception)
548
+ end
539
549
 
540
550
  unless capture_me
541
551
  Thread.current[:enhanced_errors_processing] = false
@@ -544,32 +554,43 @@ class EnhancedErrors
544
554
 
545
555
  binding_context = tp.binding
546
556
  method_name = tp.method_id
557
+
558
+ locals = {}
559
+
560
+ binding_context.local_variables.each do |var|
561
+ locals[var] = safe_local_variable_get(binding_context, var)
562
+ end
563
+
547
564
  method_and_args = {
548
565
  object_name: determine_object_name(tp, method_name),
549
- args: extract_arguments(tp, method_name)
566
+ args: extract_arguments(tp, method_name, locals)
550
567
  }
551
568
 
552
- locals = binding_context.local_variables.map { |var|
553
- [var, safe_local_variable_get(binding_context, var)]
554
- }.to_h
569
+ instances = {}
570
+ receiver = binding_context.receiver
555
571
 
556
- instance_vars = binding_context.receiver.instance_variables
557
- instances = instance_vars.map { |var|
558
- [var, safe_instance_variable_get(binding_context.receiver, var)]
559
- }.to_h
572
+ begin
573
+ if safe_to_inspect?(receiver)
574
+ receiver.instance_variables.each { |var|
575
+ instances[var] = safe_instance_variable_get(receiver, var)
576
+ }
577
+ end
578
+ rescue => e
579
+ puts "#{e.class.name} #{e.backtrace}"
580
+ end
560
581
 
561
582
  lets = {}
562
583
 
563
584
  globals = {}
564
585
  mutex.synchronize do
565
586
  if @debug
566
- globals = (global_variables - @original_global_variables.to_a).map { |var|
567
- [var, get_global_variable_value(var)]
568
- }.to_h
587
+ globals = (global_variables - @original_global_variables.to_a).each do |var|
588
+ globals[var] = get_global_variable_value(var)
589
+ end
569
590
  end
570
591
  end
571
592
 
572
- capture_event = safe_to_s(tp.event)
593
+ capture_event = tp.event.to_s
573
594
  location = "#{safe_to_s(tp.path)}:#{safe_to_s(tp.lineno)}"
574
595
  binding_info = {
575
596
  source: location,
@@ -583,17 +604,16 @@ class EnhancedErrors
583
604
  lets: lets,
584
605
  globals: globals
585
606
  },
586
- exception: safe_to_s(exception.class.name),
607
+ exception: exception.class.name,
587
608
  capture_event: capture_event
588
609
  }
589
610
 
590
611
  binding_info = default_on_capture(binding_info)
591
- on_capture_hook_local = mutex.synchronize { @on_capture_hook }
592
612
 
593
- if on_capture_hook_local
613
+ if on_capture_hook
594
614
  begin
595
615
  Thread.current[:on_capture] = true
596
- binding_info = on_capture_hook_local.call(binding_info)
616
+ binding_info = on_capture_hook.call(binding_info)
597
617
  rescue
598
618
  binding_info = nil
599
619
  ensure
@@ -601,20 +621,16 @@ class EnhancedErrors
601
621
  end
602
622
  end
603
623
 
604
- if binding_info
605
- binding_info = validate_binding_format(binding_info)
606
- if binding_info && exception.binding_infos.length >= MAX_BINDING_INFOS
607
- exception.binding_infos.delete_at(MAX_BINDING_INFOS / 2.round)
608
- end
609
- if binding_info
610
- exception.binding_infos << binding_info
611
- mutex.synchronize do
612
- override_exception_message(exception, exception.binding_infos) if @override_messages
613
- end
614
- end
624
+ return unless binding_info && validate_binding_format(binding_info)
625
+ if exception.binding_infos.length >= MAX_BINDING_INFOS
626
+ exception.binding_infos.delete_at(MAX_BINDING_INFOS / 2.round)
615
627
  end
616
- rescue
617
- # Avoid raising exceptions here
628
+ exception.binding_infos << binding_info
629
+ mutex.synchronize do
630
+ override_exception_message(exception, exception.binding_infos) if @override_messages
631
+ end
632
+ rescue => e
633
+ puts "Error: #{e&.class&.name} #{e&.backtrace}"
618
634
  ensure
619
635
  Thread.current[:enhanced_errors_processing] = false
620
636
  end
@@ -674,17 +690,15 @@ class EnhancedErrors
674
690
  capture_events.is_a?(Array) && capture_events.all? { |ev| [:raise, :rescue].include?(ev) }
675
691
  end
676
692
 
677
- def extract_arguments(tp, method_name)
693
+ def extract_arguments(tp, method_name, local_vars_hash)
678
694
  return '' unless method_name
679
695
  begin
680
- bind = tp.binding
681
696
  unbound_method = tp.defined_class.instance_method(method_name)
682
697
  method_obj = unbound_method.bind(tp.self)
683
698
  parameters = method_obj.parameters
684
- locals = bind.local_variables
685
699
 
686
700
  parameters.map do |(_, name)|
687
- value = locals.include?(name) ? safe_local_variable_get(bind, name) : nil
701
+ value = local_vars_hash[name]
688
702
  "#{name}=#{safe_inspect(value)}"
689
703
  rescue => e
690
704
  "#{name}=[Error getting argument: #{e.message}]"
@@ -696,17 +710,20 @@ class EnhancedErrors
696
710
 
697
711
  def determine_object_name(tp, method_name = '')
698
712
  begin
699
- self_class = Object.instance_method(:class).bind(tp.self).call
700
- singleton_class = Object.instance_method(:singleton_class).bind(tp.self).call
701
-
702
- if self_class && tp.defined_class == singleton_class
703
- object_identifier = safe_to_s(tp.self)
704
- method_suffix = method_name && !method_name.empty? ? ".#{method_name}" : ""
705
- "#{object_identifier}#{method_suffix}"
713
+ # Check if we're dealing with a singleton method
714
+ if (
715
+ class << tp.self
716
+ self;
717
+ end) == tp.defined_class
718
+ # Singleton method call
719
+ object_str = safe_to_s(tp.self)
720
+ method_suffix = method_name.to_s.empty? ? '' : ".#{method_name}"
721
+ "#{object_str}#{method_suffix}"
706
722
  else
707
- object_class_name = safe_to_s(self_class.name || 'UnknownClass')
708
- method_suffix = method_name && !method_name.empty? ? "##{method_name}" : ""
709
- "#{object_class_name}#{method_suffix}"
723
+ # Instance method call
724
+ klass_name = safe_to_s(tp.self.class.name || 'UnknownClass')
725
+ method_suffix = method_name.to_s.empty? ? '' : "##{method_name}"
726
+ "#{klass_name}#{method_suffix}"
710
727
  end
711
728
  rescue
712
729
  '[ErrorGettingName]'
@@ -798,10 +815,42 @@ class EnhancedErrors
798
815
  apply_skip_list(binding_info)
799
816
  end
800
817
 
818
+ # By default, we have filtering for safety, but past that, we capture everything by default
819
+ # at the moment.
801
820
  def default_eligible_for_capture(exception)
802
- ignored = ignored_exception?(exception)
803
- rspec = exception.class.name.start_with?('RSpec::Matchers')
804
- !ignored && !rspec
821
+ true
822
+ end
823
+
824
+ def exception_is_handleable?(exception)
825
+ case exception
826
+ when SystemExit, SignalException, SystemStackError, NoMemoryError
827
+ # Non-actionable: Ignore these exceptions
828
+ false
829
+ when SyntaxError, LoadError, ScriptError
830
+ # Non-actionable: Structural issues so there's no useful runtime context
831
+ false
832
+ else
833
+ # Ignore internal fatal errors
834
+ exception.class.to_s != 'fatal'
835
+ end
836
+ end
837
+
838
+ # This prevents loading it for say, production, if you don't want to,
839
+ # and keeps things cleaner. It allows a path to put this behind a feature-flag
840
+ # or env variable, and dynamically enable some capture instrumentation only
841
+ # when a Heisenbug is being hunted.
842
+ def ensure_extensions_are_required
843
+ mutex.synchronize do
844
+ return if @loaded_required_extensions
845
+ require_relative 'enhanced/colors'
846
+ require_relative 'enhanced/exception'
847
+ @loaded_required_extensions = true
848
+ end
805
849
  end
850
+
806
851
  end
807
852
  end
853
+
854
+ module Enhanced
855
+
856
+ 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: 3.0.3
4
+ version: 3.0.4
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-18 00:00:00.000000000 Z
11
+ date: 2024-12-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: awesome_print
@@ -74,19 +74,18 @@ executables: []
74
74
  extensions: []
75
75
  extra_rdoc_files: []
76
76
  files:
77
- - ".yardoc/checksums"
78
- - ".yardoc/complete"
79
- - ".yardoc/object_types"
80
- - ".yardoc/objects/root.dat"
81
- - ".yardoc/proxy_types"
82
77
  - LICENSE
83
78
  - README.md
84
79
  - benchmark/benchmark.rb
85
80
  - benchmark/memory_bench.rb
81
+ - benchmark/result.txt
86
82
  - benchmark/stackprofile.rb
87
83
  - doc/Context.html
88
84
  - doc/Enhanced.html
89
85
  - doc/Enhanced/Colors.html
86
+ - doc/Enhanced/Context.html
87
+ - doc/Enhanced/ExceptionBindingInfos.html
88
+ - doc/Enhanced/ExceptionContext.html
90
89
  - doc/Enhanced/Integrations.html
91
90
  - doc/Enhanced/Integrations/RSpecErrorFailureMessage.html
92
91
  - doc/EnhancedErrors.html
@@ -117,8 +116,8 @@ files:
117
116
  - examples/demo_rspec.rb
118
117
  - lib/enhanced/colors.rb
119
118
  - lib/enhanced/context.rb
120
- - lib/enhanced/enhanced_exception_context.rb
121
119
  - lib/enhanced/exception.rb
120
+ - lib/enhanced/exception_context.rb
122
121
  - lib/enhanced/minitest_patch.rb
123
122
  - lib/enhanced_errors.rb
124
123
  homepage: https://github.com/ericbeland/enhanced_errors
@@ -141,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
140
  - !ruby/object:Gem::Version
142
141
  version: '0'
143
142
  requirements: []
144
- rubygems_version: 3.5.22
143
+ rubygems_version: 3.3.26
145
144
  signing_key:
146
145
  specification_version: 4
147
146
  summary: Automatically enhance your errors with messages containing variable values
data/.yardoc/checksums DELETED
@@ -1,6 +0,0 @@
1
- lib/enhanced/colors.rb ed3b11d00ff9ceed089d4a65f0be5b3fca64bbe6
2
- lib/enhanced_errors.rb f79331fea888262a0447d2fff4e5067fdf1418a9
3
- lib/enhanced/context.rb 24ca2d1f4ee2ff48dd83c913ad1f1e7c1aa367c4
4
- lib/enhanced/exception.rb 5572411e9e32bbe9ed01b98787e1a53a4ab61408
5
- lib/enhanced/minitest_patch.rb 3e7fb88ddc37a1f966877735a43ae206ee396bbc
6
- lib/enhanced/enhanced_exception_context.rb 23423dbdb33b7961a0b8a297e052ebb2fbe1c6ac
data/.yardoc/complete DELETED
File without changes