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.
- checksums.yaml +4 -4
 - data/README.md +4 -3
 - data/benchmark/benchmark.rb +31 -29
 - data/benchmark/memory_bench.rb +1 -1
 - data/benchmark/result.txt +13 -0
 - data/doc/Enhanced/Colors.html +2 -2
 - data/doc/Enhanced/Context.html +283 -0
 - data/doc/Enhanced/ExceptionBindingInfos.html +255 -0
 - data/doc/Enhanced/ExceptionContext.html +397 -0
 - data/doc/Enhanced.html +8 -4
 - data/doc/EnhancedErrors.html +385 -269
 - data/doc/EnhancedExceptionContext.html +15 -15
 - data/doc/Exception.html +5 -5
 - data/doc/ExceptionBindingInfos.html +2 -2
 - data/doc/Minitest.html +3 -3
 - data/doc/_index.html +12 -6
 - data/doc/class_list.html +1 -1
 - data/doc/file.README.html +9 -4
 - data/doc/index.html +9 -4
 - data/doc/method_list.html +34 -18
 - data/doc/top-level-namespace.html +18 -8
 - data/enhanced_errors.gemspec +1 -1
 - data/lib/enhanced/context.rb +7 -5
 - data/lib/enhanced/exception.rb +35 -36
 - data/lib/enhanced/exception_context.rb +49 -0
 - data/lib/enhanced/minitest_patch.rb +1 -1
 - data/lib/enhanced_errors.rb +147 -98
 - metadata +8 -9
 - data/.yardoc/checksums +0 -6
 - data/.yardoc/complete +0 -0
 - data/.yardoc/object_types +0 -0
 - data/.yardoc/objects/root.dat +0 -0
 - data/.yardoc/proxy_types +0 -0
 - data/lib/enhanced/enhanced_exception_context.rb +0 -47
 
    
        data/lib/enhanced/exception.rb
    CHANGED
    
    | 
         @@ -1,55 +1,54 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            # exception.rb
         
     | 
| 
       2 
     | 
    
         
            -
            require_relative ' 
     | 
| 
       3 
     | 
    
         
            -
             
     | 
| 
       4 
     | 
    
         
            -
            module  
     | 
| 
       5 
     | 
    
         
            -
               
     | 
| 
       6 
     | 
    
         
            -
                 
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
                  ctx 
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         
            -
                 
     | 
| 
      
 19 
     | 
    
         
            +
                rescue
         
     | 
| 
       19 
20 
     | 
    
         
             
                  ''
         
     | 
| 
       20 
21 
     | 
    
         
             
                end
         
     | 
| 
       21 
     | 
    
         
            -
              rescue
         
     | 
| 
       22 
     | 
    
         
            -
                ''
         
     | 
| 
       23 
     | 
    
         
            -
              end
         
     | 
| 
       24 
22 
     | 
    
         | 
| 
       25 
     | 
    
         
            -
             
     | 
| 
      
 23 
     | 
    
         
            +
                private
         
     | 
| 
       26 
24 
     | 
    
         | 
| 
       27 
     | 
    
         
            -
             
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
       30 
     | 
    
         
            -
             
     | 
| 
       31 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
      
 31 
     | 
    
         
            +
                  bindings_of_interest = []
         
     | 
| 
       34 
32 
     | 
    
         | 
| 
       35 
     | 
    
         
            -
             
     | 
| 
       36 
     | 
    
         
            -
             
     | 
| 
       37 
     | 
    
         
            -
             
     | 
| 
       38 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
      
 38 
     | 
    
         
            +
                  if bindings_of_interest.empty? && binding_infos.first
         
     | 
| 
      
 39 
     | 
    
         
            +
                    bindings_of_interest << binding_infos.first
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
       43 
41 
     | 
    
         | 
| 
       44 
     | 
    
         
            -
             
     | 
| 
       45 
     | 
    
         
            -
             
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         
            -
                     
     | 
| 
      
 12 
     | 
    
         
            +
                    Enhanced::ExceptionContext.clear_all
         
     | 
| 
       13 
13 
     | 
    
         
             
                  rescue => e
         
     | 
| 
       14 
14 
     | 
    
         
             
                    puts "Ignored error during error enhancement: #{e}"
         
     | 
| 
       15 
15 
     | 
    
         
             
                  end
         
     | 
    
        data/lib/enhanced_errors.rb
    CHANGED
    
    | 
         @@ -4,12 +4,12 @@ require 'set' 
     | 
|
| 
       4 
4 
     | 
    
         
             
            require 'json'
         
     | 
| 
       5 
5 
     | 
    
         
             
            require 'monitor'
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
            require_relative 'enhanced/exception'
         
     | 
| 
      
 7 
     | 
    
         
            +
            module Enhanced; end
         
     | 
| 
       9 
8 
     | 
    
         | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
       12 
     | 
    
         
            -
            RSpec::Matchers::BuiltIn::RaiseError 
     | 
| 
      
 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=( 
     | 
| 
      
 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. 
     | 
| 
      
 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 
     | 
| 
      
 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 
     | 
    
         
            -
                   
     | 
| 
      
 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 
     | 
| 
      
 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 
     | 
    
         
            -
                   
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
       283 
     | 
    
         
            -
             
     | 
| 
       284 
     | 
    
         
            -
             
     | 
| 
       285 
     | 
    
         
            -
             
     | 
| 
       286 
     | 
    
         
            -
                         
     | 
| 
       287 
     | 
    
         
            -
             
     | 
| 
       288 
     | 
    
         
            -
                         
     | 
| 
      
 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 
     | 
    
         
            -
             
     | 
| 
      
 288 
     | 
    
         
            +
                  end
         
     | 
| 
      
 289 
     | 
    
         
            +
                  @rspec_tracepoint&.enable
         
     | 
| 
       292 
290 
     | 
    
         
             
                end
         
     | 
| 
       293 
291 
     | 
    
         | 
| 
       294 
     | 
    
         
            -
                #  
     | 
| 
      
 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 
     | 
| 
      
 311 
     | 
    
         
            +
                    @rspec_binding_trap&.disable
         
     | 
| 
       306 
312 
     | 
    
         
             
                    @rspec_binding_trap = nil
         
     | 
| 
       307 
313 
     | 
    
         
             
                  end
         
     | 
| 
       308 
     | 
    
         
            -
                  @rspec_binding_trap 
     | 
| 
      
 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: ' 
     | 
| 
      
 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 
     | 
    
         
            -
                                        
     | 
| 
       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 
     | 
    
         
            -
                   
     | 
| 
       463 
     | 
    
         
            -
             
     | 
| 
       464 
     | 
    
         
            -
             
     | 
| 
       465 
     | 
    
         
            -
                    variables[: 
     | 
| 
       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 
     | 
    
         
            -
                   
     | 
| 
       475 
     | 
    
         
            -
             
     | 
| 
      
 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 
     | 
    
         
            -
                   
     | 
| 
       537 
     | 
    
         
            -
             
     | 
| 
       538 
     | 
    
         
            -
                   
     | 
| 
      
 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 
     | 
    
         
            -
                   
     | 
| 
       553 
     | 
    
         
            -
             
     | 
| 
       554 
     | 
    
         
            -
                  }.to_h
         
     | 
| 
      
 569 
     | 
    
         
            +
                  instances = {}
         
     | 
| 
      
 570 
     | 
    
         
            +
                  receiver = binding_context.receiver
         
     | 
| 
       555 
571 
     | 
    
         | 
| 
       556 
     | 
    
         
            -
                   
     | 
| 
       557 
     | 
    
         
            -
             
     | 
| 
       558 
     | 
    
         
            -
             
     | 
| 
       559 
     | 
    
         
            -
             
     | 
| 
      
 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). 
     | 
| 
       567 
     | 
    
         
            -
                        [var 
     | 
| 
       568 
     | 
    
         
            -
                       
     | 
| 
      
 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 =  
     | 
| 
      
 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:  
     | 
| 
      
 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  
     | 
| 
      
 613 
     | 
    
         
            +
                  if on_capture_hook
         
     | 
| 
       594 
614 
     | 
    
         
             
                    begin
         
     | 
| 
       595 
615 
     | 
    
         
             
                      Thread.current[:on_capture] = true
         
     | 
| 
       596 
     | 
    
         
            -
                      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 
     | 
    
         
            -
                   
     | 
| 
       605 
     | 
    
         
            -
             
     | 
| 
       606 
     | 
    
         
            -
                     
     | 
| 
       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 
     | 
    
         
            -
             
     | 
| 
       617 
     | 
    
         
            -
                   
     | 
| 
      
 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 =  
     | 
| 
      
 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 
     | 
    
         
            -
                     
     | 
| 
       700 
     | 
    
         
            -
                     
     | 
| 
       701 
     | 
    
         
            -
             
     | 
| 
       702 
     | 
    
         
            -
             
     | 
| 
       703 
     | 
    
         
            -
                       
     | 
| 
       704 
     | 
    
         
            -
                       
     | 
| 
       705 
     | 
    
         
            -
                       
     | 
| 
      
 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 
     | 
    
         
            -
                       
     | 
| 
       708 
     | 
    
         
            -
                       
     | 
| 
       709 
     | 
    
         
            -
                      " 
     | 
| 
      
 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 
     | 
    
         
            -
                   
     | 
| 
       803 
     | 
    
         
            -
             
     | 
| 
       804 
     | 
    
         
            -
             
     | 
| 
      
 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. 
     | 
| 
      
 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- 
     | 
| 
      
 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. 
     | 
| 
      
 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
         
     |