enhanced_errors 3.0.3 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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