enhanced_errors 2.0.4 → 2.0.6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a8930564c886592e2009e80692afc91e246a3568c5aa3014cc8c75cc9707ab79
4
- data.tar.gz: 50f4106e4f94eaaadde9a0e1a1ef3f6783863edfbba7a40a95453c3fb82b6f9d
3
+ metadata.gz: 9e6ed241407a54376e0c64f2c1adc087e3dae4980ac5b7e84c947d92ff787392
4
+ data.tar.gz: 4f949a5145869e73e7f795a9c009800433956162a6d25695c2a9e8ba3a39da05
5
5
  SHA512:
6
- metadata.gz: c1e15a12dc7fe9823160a57d989fc281dd53bdbdfac17dc249be8f6e821c44cf2c089c1c7414b42245dc9be2c63ff98efb723ef26cb63550d019f8d48e7457d0
7
- data.tar.gz: cda1322bd0d6371ed9f12a7faf165dfd4f838387b98c1d34c22c03c89534e5b2de4570894d941ef22c7019278cad0ee569984e6abc6632403e563051044acbcb
6
+ metadata.gz: 02312f5287c4214c59b4b4a53e723d53d4dff511f24c335a7f7a84f049bb06638f77ea22f488cba5682fba66f581116b2bb1a4b3a79d8b6a5a290f5f822f1ea8
7
+ data.tar.gz: 13d06fa670a3f34bb67624ec40bc9a87810536aace8c2867e64620092c13d8e48d25675241491d821491cb2f3a893c1d8faa2ede7ff2f22c45b50fb506fbbd74
data/.yardoc/checksums CHANGED
@@ -1,4 +1,4 @@
1
- lib/enhanced/colors.rb 4fdbc5803b62201392c6a2ee46c5012a6f79685e
2
- lib/enhanced_errors.rb 9572612271c977a4063fab6a9c9bee75198e9166
3
- lib/enhanced/exception.rb 72c62e85ce9cea875bc3e835240059bbf1b00f0b
4
- lib/enhanced/integrations/rspec_error_failure_message.rb 3404247ebb2c7cf6b7dc9abb215c59c46a041cee
1
+ lib/colors.rb a4314ef9531d4713907c3fea22955c943fdb8cf3
2
+ lib/binding.rb fdd7d5a2dd2edde22e3b10773510738dcdce4aeb
3
+ lib/enhanced_errors.rb d12ce0629f2565e5179ae5076be8a495e19ecda2
4
+ lib/error_enhancements.rb a97d0f139d35f6e1b5bf49386271b1f4cf71761c
data/.yardoc/object_types CHANGED
Binary file
Binary file
data/README.md CHANGED
@@ -79,33 +79,19 @@ exceptions except those that pass by during the RSpec run.
79
79
  ```ruby
80
80
 
81
81
  RSpec.configure do |config|
82
-
83
- # add these config changes to your RSpec config to get variable messages
84
- config.before(:suite) do
85
- RSpec::Core::Example.prepend(Enhanced::Integrations::RSpecErrorFailureMessage)
86
- end
87
-
88
82
  config.before(:example) do |_example|
89
83
  EnhancedErrors.start_rspec_binding_capture
90
84
  end
91
85
 
92
86
  config.after(:example) do |example|
93
87
  example.metadata[:expect_binding] = EnhancedErrors.stop_rspec_binding_capture
88
+ EnhancedErrors.override_exception_message(example.exception, example.metadata[:expect_binding])
94
89
  end
95
-
96
90
  end
97
-
98
91
  ```
99
92
 
100
- ## Minitest
101
-
102
- Untested as of yet, but enhance_exceptions!(override_messages: true) is likely to work.
93
+ ## TODO: Minitest
103
94
 
104
- If anyone wants to look into an integration implementation like RSpec, it would
105
- be welcomed. With a more targeted approach like the RSpec one, exceptions could be captured and
106
- modified only during test time, like the RSpec approach. This would be advantageous as
107
- it wouldn't modify the exception message itself, but still makes the variable output available in
108
- test messages.
109
95
 
110
96
  ## Enhancing .message
111
97
 
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "enhanced_errors"
3
- spec.version = "2.0.4"
3
+ spec.version = "2.0.6"
4
4
  spec.authors = ["Eric Beland"]
5
5
 
6
6
  spec.summary = "Automatically enhance your errors with messages containing variable values from the moment they were raised."
@@ -1,6 +1,7 @@
1
1
  module Enhanced
2
2
  class Colors
3
- COLORS = { red: 31, green: 32, yellow: 33, blue: 34, purple: 35, cyan: 36, white: 0 }
3
+ COLORS = { red: 31, green: 32, yellow: 33, blue: 34, purple: 35, cyan: 36, white: 0 }.freeze
4
+ RESET_CODE = "\e[0m".freeze
4
5
 
5
6
  class << self
6
7
  def enabled?
@@ -12,11 +13,12 @@ module Enhanced
12
13
  end
13
14
 
14
15
  def color(num, string)
15
- @enabled ? "#{code(num)}#{string}#{code(0)}" : string
16
+ return string unless @enabled
17
+ "#{code(num)}#{string}#{RESET_CODE}"
16
18
  end
17
19
 
18
20
  def code(num)
19
- "\e[#{num}m"
21
+ "\e[#{num}m".freeze
20
22
  end
21
23
 
22
24
  COLORS.each do |color, code|
@@ -3,15 +3,13 @@
3
3
  require 'set'
4
4
  require 'json'
5
5
 
6
- require_relative 'enhanced/integrations/rspec_error_failure_message'
7
6
  require_relative 'enhanced/colors'
8
7
 
9
8
  IGNORED_EXCEPTIONS = %w[SystemExit NoMemoryError SignalException Interrupt
10
- ScriptError LoadError NotImplementedError SyntaxError
11
- RSpec::Expectations::ExpectationNotMetError
12
- RSpec::Matchers::BuiltIn::RaiseError
13
- SystemStackError Psych::BadAlias]
14
-
9
+ ScriptError LoadError NotImplementedError SyntaxError
10
+ RSpec::Expectations::ExpectationNotMetError
11
+ RSpec::Matchers::BuiltIn::RaiseError
12
+ SystemStackError Psych::BadAlias]
15
13
 
16
14
  class EnhancedErrors
17
15
  extend ::Enhanced
@@ -22,17 +20,19 @@ class EnhancedErrors
22
20
  :override_messages
23
21
 
24
22
  GEMS_REGEX = %r{[\/\\]gems[\/\\]}
25
- DEFAULT_MAX_LENGTH = 3000
23
+ RSPEC_EXAMPLE_REGEXP = /RSpec::ExampleGroups::[A-Z0-9]+.*/
24
+ DEFAULT_MAX_LENGTH = 2000
26
25
 
27
26
  # Maximum binding infos we will track per-exception instance. This is intended as an extra
28
27
  # safety rail, not a normal scenario.
29
- MAX_BINDING_INFOS = 10
28
+ MAX_BINDING_INFOS = 3
30
29
 
31
30
  # Add @__memoized and @__inspect_output to the skip list so they don't appear in output
32
31
  RSPEC_SKIP_LIST = Set.new([
33
32
  :@assertions,
34
33
  :@integration_session,
35
34
  :@example,
35
+ :@assertion_delegator,
36
36
  :@fixture_cache,
37
37
  :@fixture_cache_key,
38
38
  :@fixture_connections,
@@ -45,7 +45,7 @@ class EnhancedErrors
45
45
  :@matcher_definitions,
46
46
  :@__memoized,
47
47
  :@__inspect_output
48
- ])
48
+ ]).freeze
49
49
 
50
50
  RAILS_SKIP_LIST = Set.new([
51
51
  :@new_record,
@@ -53,8 +53,11 @@ class EnhancedErrors
53
53
  :@association_cache,
54
54
  :@readonly,
55
55
  :@previously_new_record,
56
- :@routes, # usually just shows #<ActionDispatch::Routing::RouteSet:0x000000016087d708>
56
+ :@_routes, # usually just shows #<ActionDispatch::Routing::RouteSet:0x000000016087d708>
57
+ :@routes,
58
+ :@app,
57
59
  :@destroyed,
60
+ :@response, #usually big, gets truncated anyway
58
61
  :@marked_for_destruction,
59
62
  :@destroyed_by_association,
60
63
  :@primary_key,
@@ -63,13 +66,16 @@ class EnhancedErrors
63
66
  :@strict_loading_mode,
64
67
  :@mutations_before_last_save,
65
68
  :@mutations_from_database,
69
+ :@integration_session,
66
70
  :@relation_delegate_cache,
67
71
  :@predicate_builder,
68
72
  :@generated_relation_method,
69
73
  :@find_by_statement_cache,
70
74
  :@arel_table,
71
75
  :@response_klass,
72
- ])
76
+ ]).freeze
77
+
78
+ DEFAULT_SKIP_LIST = (RAILS_SKIP_LIST + RSPEC_SKIP_LIST).freeze
73
79
 
74
80
  @enabled = false
75
81
 
@@ -92,18 +98,15 @@ class EnhancedErrors
92
98
  end
93
99
 
94
100
  def skip_list
95
- @skip_list ||= default_skip_list
96
- end
97
-
98
- def default_skip_list
99
- Set.new(RAILS_SKIP_LIST).merge(RSPEC_SKIP_LIST)
101
+ @skip_list ||= DEFAULT_SKIP_LIST.dup
100
102
  end
101
103
 
102
104
  # takes an exception and bindings, calculates the variables message
103
105
  # and modifies the exceptions .message to display the variables
104
106
  def override_exception_message(exception, binding_or_bindings)
105
107
  # Ensure binding_or_bindings is always an array for compatibility
106
- return exception if binding_or_bindings.nil? || binding_or_bindings.empty? || exception.respond_to?(:unaltered_message)
108
+ return exception if binding_or_bindings.nil? || binding_or_bindings.empty?
109
+ return exception if exception.respond_to?(:unaltered_message)
107
110
  variable_str = EnhancedErrors.format(binding_or_bindings)
108
111
  message_str = exception.message
109
112
  exception.define_singleton_method(:unaltered_message) { message_str }
@@ -125,21 +128,19 @@ class EnhancedErrors
125
128
  @original_global_variables = nil
126
129
  @override_messages = override_messages
127
130
 
128
- if enabled == false
131
+ if !enabled
129
132
  @original_global_variables = nil
130
133
  @enabled = false
131
134
  @trace&.disable
132
- @trace = nil
133
135
  else
134
136
  # if there's an old one, disable it before replacing it
135
137
  # this seems to actually matter, although it seems like it
136
138
  # shouldn't
137
139
  @trace&.disable
138
- @trace = nil
139
140
 
140
141
  @enabled = true
141
142
  @debug = debug
142
- @original_global_variables = global_variables
143
+ @original_global_variables = global_variables if @debug
143
144
 
144
145
  options.each do |key, value|
145
146
  setter_method = "#{key}="
@@ -177,36 +178,44 @@ class EnhancedErrors
177
178
 
178
179
  def safely_prepend_rspec_custom_failure_message
179
180
  return if @rspec_failure_message_loaded
180
- if defined?(RSpec::Core::Example)
181
+ if defined?(RSpec::Core::Example) && !RSpec::Core::Example < Enhanced::Integrations::RSpecErrorFailureMessage
181
182
  RSpec::Core::Example.prepend(Enhanced::Integrations::RSpecErrorFailureMessage)
182
183
  @rspec_failure_message_loaded = true
183
- else
184
-
185
184
  end
186
185
  rescue => e
187
- puts "Failed "
186
+ puts "Failed to prepend RSpec custom failure message: #{e.message}"
188
187
  end
189
188
 
190
189
  def start_rspec_binding_capture
191
190
  @rspec_example_binding = nil
191
+ @capture_next_binding = false
192
192
 
193
193
  # In the Exception binding infos, I observed that re-setting
194
194
  # the tracepoint without disabling it seemed to accumulate traces
195
195
  # in the test suite where things are disabled and re-enabled often.
196
196
  @rspec_tracepoint&.disable
197
- @rspec_tracepoint = nil
198
197
 
199
- @rspec_tracepoint = TracePoint.new(:b_return) do |tp|
198
+ @rspec_tracepoint = TracePoint.new(:raise, :b_return) do |tp|
200
199
  # This is super-kluge-y and should be replaced with... something TBD
201
-
202
- # early easy checks to nope out of the object name and other checks
203
- if tp.method_id.nil? && !(tp.path.to_s =~ /rspec/) && tp.path.to_s =~ /_spec\.rb$/
204
- # fixes cases where class and name are screwed up or overridden
205
- if determine_object_name(tp) =~ /RSpec::ExampleGroups::[A-Z0-9]+.*/ &&
206
- @rspec_example_binding = tp.binding
200
+ # only look at block returns once we have seen an ExpectationNotMetError
201
+
202
+ case tp.event
203
+ when :b_return
204
+ # only active if we are capturing the next binding
205
+ next unless @capture_next_binding && @rspec_example_binding.nil?
206
+ # early easy checks to nope out of the object name and other checks
207
+ if @capture_next_binding && tp.method_id.nil? && !(tp.path.include?('rspec')) && tp.path.end_with?('_spec.rb')
208
+ # fixes cases where class and name are screwed up or overridden
209
+ if determine_object_name(tp) =~ RSPEC_EXAMPLE_REGEXP
210
+ @rspec_example_binding = tp.binding
211
+ end
212
+ end
213
+ when :raise
214
+ # turn on capture of next binding
215
+ if tp.raised_exception.class.name == 'RSpec::Expectations::ExpectationNotMetError'
216
+ @capture_next_binding ||= true
207
217
  end
208
218
  end
209
-
210
219
  end
211
220
 
212
221
  @rspec_tracepoint.enable
@@ -214,8 +223,8 @@ class EnhancedErrors
214
223
 
215
224
  def stop_rspec_binding_capture
216
225
  @rspec_tracepoint&.disable
217
- @rspec_tracepoint = nil
218
226
  binding_info = convert_binding_to_binding_info(@rspec_example_binding) if @rspec_example_binding
227
+ @capture_next_binding = false
219
228
  @rspec_example_binding = nil
220
229
  binding_info
221
230
  end
@@ -261,8 +270,7 @@ class EnhancedErrors
261
270
 
262
271
  # Apply skip list to remove @__memoized and @__inspect_output from output
263
272
  # but only after extracting let variables.
264
- binding_info = default_on_capture(binding_info)
265
- binding_info
273
+ default_on_capture(binding_info)
266
274
  end
267
275
 
268
276
  def eligible_for_capture(&block)
@@ -358,12 +366,11 @@ class EnhancedErrors
358
366
  end
359
367
 
360
368
  def apply_skip_list(binding_info)
361
- unless @debug
362
- variables = binding_info[:variables]
363
- variables[:instances]&.reject! { |var, _| skip_list.include?(var) || (var.to_s.start_with?('@_') && !@debug) }
364
- variables[:locals]&.reject! { |var, _| skip_list.include?(var) }
365
- variables[:globals]&.reject! { |var, _| skip_list.include?(var) }
366
- end
369
+ variables = binding_info[:variables]
370
+ variables[:instances]&.reject! { |var, _| skip_list.include?(var) || (var.to_s.start_with?('@_') && !@debug) }
371
+ variables[:locals]&.reject! { |var, _| skip_list.include?(var) }
372
+ return binding_info unless @debug
373
+ variables[:globals]&.reject! { |var, _| skip_list.include?(var) }
367
374
  binding_info
368
375
  end
369
376
 
@@ -394,7 +401,7 @@ class EnhancedErrors
394
401
 
395
402
  instance_vars_to_display = variables[:instances] || {}
396
403
 
397
- if instance_vars_to_display && !instance_vars_to_display.empty?
404
+ unless instance_vars_to_display.empty?
398
405
  result += "\n#{Colors.green('Instances:')}\n#{variable_description(instance_vars_to_display)}"
399
406
  end
400
407
 
@@ -520,11 +527,12 @@ class EnhancedErrors
520
527
  end
521
528
 
522
529
  def default_capture_events
530
+ return @default_capture_events if @default_capture_events
523
531
  events = [:raise]
524
532
  if capture_rescue && Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.3.0')
525
533
  events << :rescue
526
534
  end
527
- Set.new(events)
535
+ @default_capture_events = events
528
536
  end
529
537
 
530
538
  def validate_and_set_capture_events(capture_events)
@@ -624,7 +632,7 @@ class EnhancedErrors
624
632
 
625
633
  def variable_description(vars_hash)
626
634
  vars_hash.map do |name, value|
627
- " #{Colors.purple(name)}: #{format_variable(value)}\n"
635
+ " #{Colors.purple(name)}: #{format_variable(value)}\n"
628
636
  end.join
629
637
  rescue
630
638
  ''
@@ -647,15 +655,20 @@ class EnhancedErrors
647
655
  end
648
656
 
649
657
  def safe_inspect(variable)
650
- variable.inspect
658
+ str = variable.inspect
659
+ if str.length > 1200
660
+ str[0...1200] + '...'
661
+ else
662
+ str
663
+ end
651
664
  rescue
652
665
  safe_to_s(variable)
653
666
  end
654
667
 
655
668
  def safe_to_s(variable)
656
669
  str = variable.to_s
657
- if str.length > 140
658
- str[0...140] + '...'
670
+ if str.length > 120
671
+ str[0...120] + '...'
659
672
  else
660
673
  str
661
674
  end
@@ -689,4 +702,4 @@ class EnhancedErrors
689
702
  !ignored && !rspec
690
703
  end
691
704
  end
692
- end
705
+ 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: 2.0.4
4
+ version: 2.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Beland
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-12-10 00:00:00.000000000 Z
11
+ date: 2024-12-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: awesome_print
@@ -96,7 +96,6 @@ files:
96
96
  - examples/example_spec.rb
97
97
  - lib/enhanced/colors.rb
98
98
  - lib/enhanced/exception.rb
99
- - lib/enhanced/integrations/rspec_error_failure_message.rb
100
99
  - lib/enhanced_errors.rb
101
100
  homepage: https://github.com/ericbeland/enhanced_errors
102
101
  licenses: []
@@ -1,13 +0,0 @@
1
- module Enhanced
2
- module Integrations
3
- module RSpecErrorFailureMessage
4
- def execution_result
5
- result = super
6
- if result.exception
7
- EnhancedErrors.override_exception_message(result.exception, self.metadata[:expect_binding])
8
- end
9
- result
10
- end
11
- end
12
- end
13
- end