power_trace 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e0d694b8c7925be5e04c1f5f3ea4a5da6b35c877b21889b4087932431cbafb5b
4
- data.tar.gz: 36e4678c7647402010216e5312f42f4675eaafcd8d46f32c8564b0ccc97cd161
3
+ metadata.gz: 489aca17c7b57c040a81bcb25149149c616f3c822c23f65b20f94fc630178eaa
4
+ data.tar.gz: 0bcc29315b7c6c5399b840340ecec4f8e628b463e90e2288515c020d849deb26
5
5
  SHA512:
6
- metadata.gz: 66bde570863c5e24f4c8a853fa68e40f810f5a5278e2296a52ca8b4fa6cc1e0ad47394453e7814b8b61355576075a3a9dbd8534bb63a7404d7e15a093bed102b
7
- data.tar.gz: 5a24fd2fd709ad654b12adf15e1a321425316839e400d33d75a336b78565ee3c6520daad0cf881f32c13d5ec0d5e09df492631f8c554b0d66843a4b68d9fc8dd
6
+ metadata.gz: 91826f382a2687ca209f52498789410eb712fa371ba2f5205b20fb6c1831e75637874c593e8b98520368deed3ad19c6a047389921066bb7686b69b9f2ec666b8
7
+ data.tar.gz: d62169e40fbdb3fe21b209ce788eab7cfa8426bc776b0d336da9544389ac0590b98b93fc7f8ce260521bfccb237c6312ed79c1f885667296737e015fb514a1a0
@@ -1,10 +1,9 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- power_trace (0.1.0)
4
+ power_trace (0.2.0)
5
5
  activesupport
6
- pry
7
- pry-stack_explorer
6
+ binding_of_caller (~> 0.8.0)
8
7
 
9
8
  GEM
10
9
  remote: https://rubygems.org/
@@ -28,9 +27,6 @@ GEM
28
27
  pry (0.13.1)
29
28
  coderay (~> 1.1)
30
29
  method_source (~> 1.0)
31
- pry-stack_explorer (0.5.1)
32
- binding_of_caller (~> 0.7)
33
- pry (~> 0.13)
34
30
  rake (12.3.3)
35
31
  rspec (3.9.0)
36
32
  rspec-core (~> 3.9.0)
@@ -55,6 +51,7 @@ PLATFORMS
55
51
 
56
52
  DEPENDENCIES
57
53
  power_trace!
54
+ pry
58
55
  rake (~> 12.0)
59
56
  rspec (~> 3.0)
60
57
 
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # power_trace
2
2
 
3
- ![Ruby](https://github.com/st0012/power_trace/workflows/Ruby/badge.svg)
3
+ ![Ruby](https://github.com/st0012/power_trace/workflows/Ruby/badge.svg) [![Gem Version](https://badge.fury.io/rb/power_trace.svg)](https://badge.fury.io/rb/power_trace)
4
4
 
5
5
  Backtrace (Stack traces) are essential information for debugging our applications. However, they only tell us what the program did, but don't tell us what it had (the arguments, local variables...etc.). So it's very often that we'd need to visit each call site, rerun the program, and try to print out the variables. To me, It's like the Google map's navigation only tells us the name of the roads, but not showing us the map along with them.
6
6
 
@@ -82,10 +82,34 @@ I don't recommend using it like this for other purposes, though. Because by defa
82
82
 
83
83
  - `colorize` - to decide whether to colorize each entry in their string format. Default is `true`.
84
84
  - `line_limit` - `power_trace` truncates every argument/local variable's value to avoid creating too much noise. Default is `100`
85
+ - `extra_info_indent` -
85
86
 
86
- ### Get `power_trace` From An Exception (Experimental)
87
+ By default, extra info sections (locals/arguments) are indented with `4` spaces. Like:
87
88
 
88
- You can also access an exception object's enhanced backtrace with the `power_trace` method:
89
+ ```
90
+ /Users/st0012/projects/power_trace/spec/fixtures.rb:23:in `forth_call'
91
+ (Arguments)
92
+ num1: 20
93
+ num2: 10
94
+ ```
95
+
96
+ You can change this indentation with the `extra_info_indent: Int` option. It's useful when you need to adjust the output from some formatting tools (like `RSpec` formatters).
97
+
98
+ ### Use It With StandardError (Experimental)
99
+
100
+ If you set
101
+
102
+ ```ruby
103
+ PowerTrace.replace_backtrace = true
104
+ ```
105
+
106
+ it will replace every `StandardError` exception's backtrace with the `power_trace.to_backtrace`. So most of the error traces you see will also contain the colorized environment information!
107
+
108
+ This is still an experimental feature for now, as it has a very wide impact on all the libraries and your own code. **Don't try this on production!!!!**
109
+
110
+ #### Get `power_trace` Manually From A StandardError Exception
111
+
112
+ If you think the above feature is too aggressive. You can access an exception object's enhanced backtrace manually with the `power_trace` method:
89
113
 
90
114
  ```ruby
91
115
  begin
@@ -95,7 +119,24 @@ rescue => e
95
119
  end
96
120
  ```
97
121
 
98
- And use it as you get it from the call site.
122
+ This feature doesn't require any flag to enable, as the information is added as an extra field and doesn't override anything.
123
+
124
+ ### Use It With RSpec
125
+
126
+ You can also prettify RSpec's error messages with `power_trace`, just use the below config:
127
+
128
+ ```ruby
129
+ PowerTrace.power_rspec_trace = true
130
+ ```
131
+
132
+ Result:
133
+
134
+ **Before**
135
+ ![normal rspec error message](https://github.com/st0012/power_trace/blob/master/images/normal_rspec_error.png)
136
+
137
+ **After**
138
+ ![rspec error message with config set to true](https://github.com/st0012/power_trace/blob/master/images/power_trace_rspec_error.png)
139
+
99
140
 
100
141
  ## Inspirations & Helpful Tools
101
142
 
@@ -111,7 +152,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
111
152
 
112
153
  ## Contributing
113
154
 
114
- Bug reports and pull requests are welcome on GitHub at [https://github.com/[USERNAME]/power_trace](https://github.com/%5BUSERNAME%5D/power_trace). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/%5BUSERNAME%5D/power_trace/blob/master/CODE_OF_CONDUCT.md).
155
+ Bug reports and pull requests are welcome on GitHub at [https://github.com/st0012/power_trace](https://github.com/st0012/power_trace). This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/%5BUSERNAME%5D/power_trace/blob/master/CODE_OF_CONDUCT.md).
115
156
 
116
157
  ## License
117
158
 
@@ -2,6 +2,15 @@ require "power_trace/version"
2
2
  require "power_trace/stack"
3
3
 
4
4
  module PowerTrace
5
+ cattr_accessor :colorize_backtrace, instance_accessor: false
6
+ self.colorize_backtrace = true
7
+
8
+ cattr_accessor :replace_backtrace, instance_accessor: false
9
+ self.replace_backtrace = false
10
+
11
+ cattr_accessor :power_rspec_trace, instance_accessor: false
12
+ self.power_rspec_trace = false
13
+
5
14
  def power_trace(options = {})
6
15
  PowerTrace::Stack.new(options)
7
16
  end
@@ -10,3 +19,9 @@ end
10
19
  include PowerTrace
11
20
 
12
21
  require "power_trace/exception_patch"
22
+
23
+ require "rspec" rescue LoadError
24
+
25
+ if defined?(RSpec)
26
+ require "power_trace/rspec_patch"
27
+ end
@@ -1,7 +1,4 @@
1
1
  module PowerTrace
2
2
  class BlockEntry < Entry
3
- def method_parameters
4
- []
5
- end
6
3
  end
7
4
  end
@@ -2,10 +2,20 @@ module PowerTrace
2
2
  class MethodEntry < Entry
3
3
  def method
4
4
  @method ||= Object.instance_method(:method).bind(@receiver).call(name)
5
+ rescue NameError
6
+ # if any part of the program uses Refinement to extend its methods
7
+ # we might still get NoMethodError when trying to get that method outside the scope
8
+ nil
5
9
  end
6
10
 
11
+ private
12
+
7
13
  def method_parameters
8
- method.parameters.map { |parameter| parameter[1] }
14
+ if method
15
+ method.parameters.map { |parameter| parameter[1] }
16
+ else
17
+ []
18
+ end
9
19
  end
10
20
 
11
21
  def defined_class
@@ -6,8 +6,6 @@ module PowerTrace
6
6
  include ColorizeHelper
7
7
  UNDEFINED = "[undefined]"
8
8
 
9
- INDENT = "\s" * 4
10
-
11
9
  attr_reader :frame, :filepath, :line_number, :receiver, :locals, :arguments
12
10
 
13
11
  def initialize(frame)
@@ -27,11 +25,17 @@ module PowerTrace
27
25
  end
28
26
 
29
27
  def arguments_string(options = {})
30
- hash_to_string(arguments, false, options[:line_limit])
28
+ <<~STR.chomp
29
+ #{options[:indentation]}(Arguments)
30
+ #{hash_to_string(arguments, false, options)}
31
+ STR
31
32
  end
32
33
 
33
34
  def locals_string(options = {})
34
- hash_to_string(locals, false, options[:line_limit])
35
+ <<~STR.chomp
36
+ #{options[:indentation]}(Locals)
37
+ #{hash_to_string(locals, false, options)}
38
+ STR
35
39
  end
36
40
 
37
41
  def call_trace(options = {})
@@ -39,10 +43,10 @@ module PowerTrace
39
43
  end
40
44
 
41
45
  ATTRIBUTE_COLORS = {
42
- name: COLORS[:blue],
43
- location: COLORS[:green],
44
- arguments_string: COLORS[:orange],
45
- locals_string: COLORS[:megenta]
46
+ name: :blue,
47
+ location: :green,
48
+ arguments_string: :orange,
49
+ locals_string: :megenta
46
50
  }
47
51
 
48
52
  ATTRIBUTE_COLORS.each do |attribute, color|
@@ -53,7 +57,7 @@ module PowerTrace
53
57
  call_result = send("original_#{attribute}", options)
54
58
 
55
59
  if options[:colorize]
56
- "#{color}#{call_result}#{COLORS[:reset]}"
60
+ send("#{color}_color", call_result)
57
61
  else
58
62
  call_result
59
63
  end
@@ -61,37 +65,43 @@ module PowerTrace
61
65
  end
62
66
 
63
67
  def to_s(options = {})
64
- assemble_string(options)
68
+ # this is to prevent entries from polluting each other's options
69
+ # of course, that'd only happen if I did something stupid ;)
70
+ assemble_string(options.dup)
65
71
  end
66
72
 
67
73
  private
68
74
 
75
+ def method_parameters
76
+ []
77
+ end
78
+
69
79
  def assemble_string(options)
70
80
  strings = [call_trace(options)]
71
81
 
82
+ indentation = "\s" * options[:extra_info_indent]
83
+ options[:indentation] = indentation
84
+
72
85
  if arguments.present?
73
- strings << <<~STR.chomp
74
- (Arguments)
75
- #{arguments_string(options)}
76
- STR
86
+ strings << arguments_string(options)
77
87
  end
78
88
 
79
89
  if locals.present?
80
- strings << <<~STR.chomp
81
- (Locals)
82
- #{locals_string(options)}
83
- STR
90
+ strings << locals_string(options)
84
91
  end
85
92
 
86
93
  strings.join("\n")
87
94
  end
88
95
 
89
- def hash_to_string(hash, inspect, truncation)
96
+ def hash_to_string(hash, inspect, options)
97
+ truncation = options[:line_limit]
98
+ indentation = options[:indentation] + "\s" * 2
99
+
90
100
  elements_string = hash.map do |key, value|
91
101
  value_string = value_to_string(value, truncation)
92
102
  "#{key.to_s}: #{value_string}"
93
- end.join("\n#{INDENT}")
94
- "#{INDENT}#{elements_string}"
103
+ end.join("\n#{indentation}")
104
+ "#{indentation}#{elements_string}"
95
105
  end
96
106
 
97
107
  def value_to_string(value, truncation)
@@ -1,14 +1,41 @@
1
- class Exception
2
- attr_accessor :power_trace
1
+ class StandardError
2
+ attr_accessor :stored_power_trace
3
3
  end
4
4
 
5
+ # the purposes of this section are:
6
+ # 1. capture and store a power_trace when the exception is firstly raised (will skip re-raising conditions)
7
+ # 2. if `replace_backtrace` is set to `true, it'll use the captured power_trace to replace the exception's original backtrace
5
8
  TracePoint.trace(:raise) do |tp|
6
9
  begin
7
10
  e = tp.raised_exception
8
- e.power_trace = power_trace(exception: true)
11
+
12
+ # it's too risky to deal with non-StandardError exceptions
13
+ next unless e.is_a?(StandardError)
14
+
15
+ # ignore re-raised exceptions
16
+ next if e.stored_power_trace
17
+
18
+ # these errors are commonly used as flow control so working with them can be error-prone and slow
19
+ # we can revisit them once the gem gets more stable
20
+ next if e.is_a?(LoadError)
21
+ next if e.is_a?(NameError)
22
+ next if e.is_a?(SystemCallError)
23
+
24
+ if defined?(Bootsnap)
25
+ next if e.is_a?(Bootsnap::LoadPathCache::FallbackScan)
26
+ next if e.is_a?(Bootsnap::LoadPathCache::ReturnFalse)
27
+ end
28
+
29
+ e.stored_power_trace = power_trace(exception: true)
30
+
31
+ if PowerTrace.replace_backtrace
32
+ e.set_backtrace(
33
+ e.stored_power_trace.to_backtrace(colorize: PowerTrace.colorize_backtrace)
34
+ )
35
+ end
9
36
  rescue => e
10
- puts e
11
- puts e.backtrace
12
- fail "power_trace BUG"
37
+ puts(e)
38
+ puts(e.backtrace)
39
+ puts("power_trace's BUG")
13
40
  end
14
41
  end
@@ -17,12 +17,5 @@ module PowerTrace
17
17
  "#{color_mark}#{str}#{RESET_MARK}"
18
18
  end
19
19
  end
20
-
21
- COLORS = COLOR_CODES.each_with_object({}) do |(name, code), hash|
22
- hash[name] = "\u001b[38;5;#{code}m"
23
- end.merge(
24
- reset: "\u001b[0m",
25
- nocolor: ""
26
- )
27
20
  end
28
21
  end
@@ -0,0 +1,17 @@
1
+ RSpec::Core::Formatters::ExceptionPresenter.class_eval do
2
+ alias :original_formatted_backtrace :formatted_backtrace
3
+
4
+ def formatted_backtrace(exception=@exception)
5
+ if PowerTrace.power_rspec_trace || PowerTrace.replace_backtrace
6
+ backtrace_formatter.format_backtrace(exception.stored_power_trace.to_backtrace(extra_info_indent: 8), example.metadata) +
7
+ formatted_cause(exception)
8
+ else
9
+ original_formatted_backtrace
10
+ end
11
+ rescue => e
12
+ puts(e)
13
+ puts(e.backtrace)
14
+ puts("there's a bug in power_trace, please open an issue at https://github.com/st0012/power_trace")
15
+ original_formatted_backtrace
16
+ end
17
+ end
@@ -1,5 +1,5 @@
1
1
  require "power_trace/entry"
2
- require "pry-stack_explorer"
2
+ require "binding_of_caller"
3
3
 
4
4
  module PowerTrace
5
5
  class Stack
@@ -9,7 +9,8 @@ module PowerTrace
9
9
 
10
10
  OUTPUT_OPTIONS_DEFAULT = {
11
11
  colorize: true,
12
- line_limit: 100
12
+ line_limit: 100,
13
+ extra_info_indent: 4
13
14
  }
14
15
 
15
16
  def initialize(options = {})
@@ -44,12 +45,8 @@ module PowerTrace
44
45
  end
45
46
  end
46
47
 
47
- def frame_manager
48
- PryStackExplorer.frame_manager(Pry.new)
49
- end
50
-
51
48
  def extract_entries
52
- frames = frame_manager.bindings
49
+ frames = binding.callers
53
50
  # when using pry console, the power_trace_index will be `nil` and breaks EVERYTHING
54
51
  # so we should fallback it to 0
55
52
  power_trace_index = (frames.index { |b| b.frame_description&.to_sym == :power_trace } || 0) + 1
@@ -61,6 +58,8 @@ module PowerTrace
61
58
  MethodEntry.new(b)
62
59
  when :block
63
60
  BlockEntry.new(b)
61
+ else
62
+ Entry.new(b)
64
63
  end
65
64
  end
66
65
  end
@@ -1,3 +1,3 @@
1
1
  module PowerTrace
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -29,6 +29,7 @@ So I hope to solve this problem by adding some additional runtime info to the ba
29
29
  spec.require_paths = ["lib"]
30
30
 
31
31
  spec.add_dependency "activesupport"
32
- spec.add_dependency "pry"
33
- spec.add_dependency "pry-stack_explorer"
32
+ spec.add_dependency "binding_of_caller", "~> 0.8.0"
33
+
34
+ spec.add_development_dependency "pry"
34
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: power_trace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - st0012
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-07-09 00:00:00.000000000 Z
11
+ date: 2020-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -25,27 +25,27 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: pry
28
+ name: binding_of_caller
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ">="
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: 0.8.0
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ">="
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: 0.8.0
41
41
  - !ruby/object:Gem::Dependency
42
- name: pry-stack_explorer
42
+ name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '0'
48
- type: :runtime
48
+ type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
@@ -78,7 +78,9 @@ files:
78
78
  - bin/setup
79
79
  - images/entries.png
80
80
  - images/normal_backtrace.png
81
+ - images/normal_rspec_error.png
81
82
  - images/power_trace_backtrace.png
83
+ - images/power_trace_rspec_error.png
82
84
  - images/print_directly.png
83
85
  - lib/power_trace.rb
84
86
  - lib/power_trace/entries/block_entry.rb
@@ -86,6 +88,7 @@ files:
86
88
  - lib/power_trace/entry.rb
87
89
  - lib/power_trace/exception_patch.rb
88
90
  - lib/power_trace/helpers/colorize_helper.rb
91
+ - lib/power_trace/rspec_patch.rb
89
92
  - lib/power_trace/stack.rb
90
93
  - lib/power_trace/version.rb
91
94
  - power_trace.gemspec