minitest-heat 0.0.8 → 0.0.12
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/.rubocop.yml +1 -0
- data/Gemfile.lock +6 -6
- data/README.md +1 -1
- data/lib/minitest/heat/backtrace/line_parser.rb +25 -0
- data/lib/minitest/heat/backtrace.rb +39 -43
- data/lib/minitest/heat/hit.rb +36 -19
- data/lib/minitest/heat/issue.rb +98 -79
- data/lib/minitest/heat/location.rb +115 -116
- data/lib/minitest/heat/locations.rb +105 -0
- data/lib/minitest/heat/map.rb +16 -4
- data/lib/minitest/heat/output/backtrace.rb +52 -44
- data/lib/minitest/heat/output/issue.rb +65 -62
- data/lib/minitest/heat/output/map.rb +99 -25
- data/lib/minitest/heat/output/marker.rb +5 -3
- data/lib/minitest/heat/output/results.rb +3 -2
- data/lib/minitest/heat/output/source_code.rb +1 -1
- data/lib/minitest/heat/output/token.rb +2 -1
- data/lib/minitest/heat/output.rb +66 -6
- data/lib/minitest/heat/results.rb +23 -3
- data/lib/minitest/heat/source.rb +1 -1
- data/lib/minitest/heat/version.rb +1 -1
- data/lib/minitest/heat.rb +3 -2
- data/lib/minitest/heat_plugin.rb +9 -17
- data/lib/minitest/heat_reporter.rb +24 -34
- metadata +5 -4
- data/lib/minitest/heat/line.rb +0 -74
@@ -2,179 +2,178 @@
|
|
2
2
|
|
3
3
|
module Minitest
|
4
4
|
module Heat
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
# - 'final' represents the final line of the backtrace regardless of where it is
|
9
|
-
# - 'test' represents the last line from the project's tests. It is further differentiated by
|
10
|
-
# the line where the test is defined and the actual line of code in the test that geneated
|
11
|
-
# the failure or exception
|
12
|
-
# - 'source_code' represents the last line from the project's source code
|
13
|
-
# - 'project' represents the last source line, but falls back to the last test line
|
14
|
-
# - 'most_relevant' represents the most specific file to investigate starting with the source
|
15
|
-
# code and then looking to the test code with final line of the backtrace as a fallback
|
5
|
+
# Consistent structure for extracting information about a given location. In addition to the
|
6
|
+
# pathname to the file and the line number in the file, it can also include information about
|
7
|
+
# the containing method or block and retrieve source code for the location.
|
16
8
|
class Location
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
@line_number = Integer(line_number)
|
21
|
-
super
|
22
|
-
end
|
23
|
-
end
|
9
|
+
UNRECOGNIZED = '(Unrecognized File)'
|
10
|
+
UNKNOWN_MODIFICATION_TIME = Time.at(0)
|
11
|
+
UNKNOWN_MODIFICATION_SECONDS = -1
|
24
12
|
|
25
|
-
|
13
|
+
attr_accessor :raw_pathname, :raw_line_number, :raw_container
|
26
14
|
|
27
|
-
|
28
|
-
|
29
|
-
|
15
|
+
# Initialize a new Location
|
16
|
+
#
|
17
|
+
# @param [Pathname, String] pathname: the pathname to the file
|
18
|
+
# @param [Integer] line_number: the line number of the location within the file
|
19
|
+
# @param [String] container: nil the containing method or block for the issue
|
20
|
+
#
|
21
|
+
# @return [self]
|
22
|
+
def initialize(pathname:, line_number:, container: nil)
|
23
|
+
@raw_pathname = pathname
|
24
|
+
@raw_line_number = line_number
|
25
|
+
@raw_container = container
|
30
26
|
end
|
31
27
|
|
32
|
-
#
|
33
|
-
# test failure
|
28
|
+
# Generates a formatted string describing the line of code similar to the original backtrace
|
34
29
|
#
|
35
|
-
# @return [String]
|
30
|
+
# @return [String] a consistently-formatted, human-readable string about the line of code
|
36
31
|
def to_s
|
37
|
-
"#{
|
38
|
-
end
|
39
|
-
|
40
|
-
def local?
|
41
|
-
broken_test? || proper_failure?
|
32
|
+
"#{absolute_path}#{filename}:#{line_number} in `#{container}`"
|
42
33
|
end
|
43
34
|
|
44
|
-
#
|
45
|
-
# test, and it raises an exception, then it's really a broken test rather than a proper
|
46
|
-
# faiure.
|
35
|
+
# Generates a simplified location array with the pathname and line number
|
47
36
|
#
|
48
|
-
# @return [
|
49
|
-
def
|
50
|
-
|
37
|
+
# @return [Array<Pathname, Integer>] a no-frills location pair
|
38
|
+
def to_a
|
39
|
+
[
|
40
|
+
pathname,
|
41
|
+
line_number
|
42
|
+
]
|
51
43
|
end
|
52
44
|
|
53
|
-
#
|
54
|
-
# an external piece of code like a gem.
|
45
|
+
# A short relative pathname and line number pair
|
55
46
|
#
|
56
|
-
# @return [
|
57
|
-
|
58
|
-
|
59
|
-
!source_code_file.nil? && !broken_test?
|
47
|
+
# @return [String] the short filename/line number combo. ex. `dir/file.rb:23`
|
48
|
+
def short
|
49
|
+
"#{relative_filename}:#{line_number}"
|
60
50
|
end
|
61
51
|
|
62
|
-
#
|
63
|
-
# backtrace files will be a gem or external library that's failing indirectly as a result
|
64
|
-
# of a problem with local source code (not always, but frequently). In that case, the best
|
65
|
-
# first place to focus is on the code you control.
|
52
|
+
# Determine if there is a file and text at the given line number
|
66
53
|
#
|
67
|
-
# @return [
|
68
|
-
def
|
69
|
-
|
54
|
+
# @return [Boolean] true if the file exists and has text at the given line number
|
55
|
+
def exists?
|
56
|
+
pathname.exist? && source_code.lines.any?
|
70
57
|
end
|
71
58
|
|
72
|
-
# The
|
59
|
+
# The pathanme for the location. Written to be safe and fallbackto the project directory if
|
60
|
+
# an exception is raised ocnverting the value to a pathname
|
73
61
|
#
|
74
|
-
# @return [
|
75
|
-
def
|
76
|
-
|
62
|
+
# @return [Pathname] a pathname instance for the relevant file
|
63
|
+
def pathname
|
64
|
+
Pathname(raw_pathname)
|
65
|
+
rescue ArgumentError
|
66
|
+
Pathname(Dir.pwd)
|
77
67
|
end
|
78
68
|
|
79
|
-
#
|
69
|
+
# A safe interface to getting a string representing the path portion of the file
|
80
70
|
#
|
81
|
-
# @return [String] the
|
82
|
-
|
83
|
-
|
71
|
+
# @return [String] either the path/directory portion of the file name or '(Unrecognized File)'
|
72
|
+
# if the offending file can't be found for some reason
|
73
|
+
def path
|
74
|
+
pathname.exist? ? pathname.dirname.to_s : UNRECOGNIZED
|
84
75
|
end
|
85
76
|
|
86
|
-
|
87
|
-
|
88
|
-
# @return [Integer] line number
|
89
|
-
def final_failure_line
|
90
|
-
final_location.line_number
|
77
|
+
def absolute_path
|
78
|
+
pathname.exist? ? "#{path}/" : UNRECOGNIZED
|
91
79
|
end
|
92
80
|
|
93
|
-
|
94
|
-
|
95
|
-
# @return [String] the relative path to the file from the project root
|
96
|
-
def project_file
|
97
|
-
broken_test? ? test_file : source_code_file
|
81
|
+
def relative_path
|
82
|
+
pathname.exist? ? absolute_path.delete_prefix("#{project_root_dir}/") : UNRECOGNIZED
|
98
83
|
end
|
99
84
|
|
100
|
-
#
|
85
|
+
# A safe interface for getting a string representing the filename portion of the file
|
101
86
|
#
|
102
|
-
# @return [
|
103
|
-
|
104
|
-
|
87
|
+
# @return [String] either the filename portion of the file or '(Unrecognized File)'
|
88
|
+
# if the offending file can't be found for some reason
|
89
|
+
def filename
|
90
|
+
pathname.exist? ? pathname.basename.to_s : UNRECOGNIZED
|
105
91
|
end
|
106
92
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
def source_code_file
|
111
|
-
return nil unless backtrace.source_code_entries.any?
|
93
|
+
def absolute_filename
|
94
|
+
pathname.exist? ? pathname.to_s : UNRECOGNIZED
|
95
|
+
end
|
112
96
|
|
113
|
-
|
97
|
+
def relative_filename
|
98
|
+
pathname.exist? ? pathname.to_s.delete_prefix("#{project_root_dir}/") : UNRECOGNIZED
|
114
99
|
end
|
115
100
|
|
116
|
-
#
|
101
|
+
# Line number identifying the specific line in the file
|
102
|
+
#
|
103
|
+
# @return [Integer] line number for the file
|
117
104
|
#
|
118
|
-
|
119
|
-
|
120
|
-
|
105
|
+
def line_number
|
106
|
+
Integer(raw_line_number)
|
107
|
+
rescue ArgumentError
|
108
|
+
1
|
109
|
+
end
|
121
110
|
|
122
|
-
|
111
|
+
# The containing method or block details for the location
|
112
|
+
#
|
113
|
+
# @return [String] the containing method of the line of code
|
114
|
+
def container
|
115
|
+
raw_container.nil? ? '(Unknown Container)' : String(raw_container)
|
123
116
|
end
|
124
117
|
|
125
|
-
#
|
118
|
+
# Looks up the source code for the location. Can return multiple lines of source code from
|
119
|
+
# the surrounding lines of code for the primary line
|
126
120
|
#
|
127
|
-
# @
|
128
|
-
|
129
|
-
|
121
|
+
# @param [Integer] max_line_count: 1 the maximum number of lines to return from the source
|
122
|
+
#
|
123
|
+
# @return [Source] an instance of Source for accessing lines and their line numbers
|
124
|
+
def source_code(max_line_count: 1)
|
125
|
+
Minitest::Heat::Source.new(
|
126
|
+
pathname.to_s,
|
127
|
+
line_number: line_number,
|
128
|
+
max_line_count: max_line_count
|
129
|
+
)
|
130
130
|
end
|
131
131
|
|
132
|
-
#
|
132
|
+
# Determines if a given file is from the project directory
|
133
133
|
#
|
134
|
-
# @return [
|
135
|
-
def
|
136
|
-
|
134
|
+
# @return [Boolean] true if the file is in the project (source code or test)
|
135
|
+
def project_file?
|
136
|
+
path.include?(project_root_dir)
|
137
137
|
end
|
138
138
|
|
139
|
-
#
|
139
|
+
# Determines if a given file follows the standard approaching to naming test files.
|
140
140
|
#
|
141
|
-
# @return [
|
142
|
-
def
|
143
|
-
|
141
|
+
# @return [Boolean] true if the file name starts with `test_` or ends with `_test.rb`
|
142
|
+
def test_file?
|
143
|
+
filename.to_s.start_with?('test_') || filename.to_s.end_with?('_test.rb')
|
144
144
|
end
|
145
145
|
|
146
|
-
#
|
146
|
+
# Determines if a given file is a non-test file from the project directory
|
147
147
|
#
|
148
|
-
# @return [
|
149
|
-
|
150
|
-
|
151
|
-
backtrace? ? backtrace.final_location : test_location
|
148
|
+
# @return [Boolean] true if the file is in the project but not a test file
|
149
|
+
def source_code_file?
|
150
|
+
project_file? && !test_file?
|
152
151
|
end
|
153
152
|
|
154
|
-
#
|
155
|
-
# backtrace files will be a gem or external library that's failing indirectly as a result
|
156
|
-
# of a problem with local source code (not always, but frequently). In that case, the best
|
157
|
-
# first place to focus is on the code you control.
|
153
|
+
# A safe interface to getting the last modified time for the file in question
|
158
154
|
#
|
159
|
-
# @return [
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
test_location,
|
164
|
-
final_location
|
165
|
-
].compact.first
|
155
|
+
# @return [Time] the timestamp for when the file in question was last modified or `Time.at(0)`
|
156
|
+
# if the offending file can't be found for some reason
|
157
|
+
def mtime
|
158
|
+
pathname.exist? ? pathname.mtime : UNKNOWN_MODIFICATION_TIME
|
166
159
|
end
|
167
160
|
|
168
|
-
|
169
|
-
|
161
|
+
# A safe interface to getting the number of seconds since the file was modified
|
162
|
+
#
|
163
|
+
# @return [Integer] the number of seconds since the file was modified or `-1` if the offending
|
164
|
+
# file can't be found for some reason
|
165
|
+
def age_in_seconds
|
166
|
+
pathname.exist? ? seconds_ago : UNKNOWN_MODIFICATION_SECONDS
|
170
167
|
end
|
171
168
|
|
172
|
-
|
173
|
-
|
169
|
+
private
|
170
|
+
|
171
|
+
def project_root_dir
|
172
|
+
Dir.pwd
|
174
173
|
end
|
175
174
|
|
176
|
-
def
|
177
|
-
|
175
|
+
def seconds_ago
|
176
|
+
(Time.now - mtime).to_i
|
178
177
|
end
|
179
178
|
end
|
180
179
|
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Minitest
|
4
|
+
module Heat
|
5
|
+
# Convenience methods for determining the file and line number where the problem occurred.
|
6
|
+
# There are several layers of specificity to help make it easy to communicate the relative
|
7
|
+
# location of the failure:
|
8
|
+
# - 'final' represents the final line of the backtrace regardless of where it is
|
9
|
+
# - 'test_definition' represents where the test is defined
|
10
|
+
# - 'test_failure' represents the last line from the project's tests. It is further differentiated by
|
11
|
+
# the line where the test is defined and the actual line of code in the test that geneated
|
12
|
+
# the failure or exception
|
13
|
+
# - 'source_code' represents the last line from the project's source code
|
14
|
+
# - 'project' represents the last source line, but falls back to the last test line
|
15
|
+
# - 'most_relevant' represents the most specific file to investigate starting with the source
|
16
|
+
# code and then looking to the test code with final line of the backtrace as a fallback
|
17
|
+
class Locations
|
18
|
+
attr_reader :test_definition, :backtrace
|
19
|
+
|
20
|
+
def initialize(test_definition_location, backtrace = [])
|
21
|
+
test_definition_pathname, test_definition_line_number = test_definition_location
|
22
|
+
@test_definition = ::Minitest::Heat::Location.new(pathname: test_definition_pathname, line_number: test_definition_line_number)
|
23
|
+
|
24
|
+
@backtrace = Backtrace.new(backtrace)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Prints the pathname and line number of the location most likely to be the source of the
|
28
|
+
# test failure
|
29
|
+
#
|
30
|
+
# @return [String] ex. 'path/to/file.rb:12'
|
31
|
+
def to_s
|
32
|
+
"#{most_relevant.absolute_filename}:#{most_relevant.line_number}"
|
33
|
+
end
|
34
|
+
|
35
|
+
# Knows if the failure is contained within the test. For example, if there's bad code in a
|
36
|
+
# test, and it raises an exception, then it's really a broken test rather than a proper
|
37
|
+
# faiure.
|
38
|
+
#
|
39
|
+
# @return [Boolean] true if final file in the backtrace is the same as the test location file
|
40
|
+
def broken_test?
|
41
|
+
!test_failure.nil? && test_failure == final
|
42
|
+
end
|
43
|
+
|
44
|
+
# Knows if the failure occurred in the actual project source code—as opposed to the test or
|
45
|
+
# an external piece of code like a gem.
|
46
|
+
#
|
47
|
+
# @return [Boolean] true if there's a non-test project file in the stacktrace but it's not
|
48
|
+
# a result of a broken test
|
49
|
+
def proper_failure?
|
50
|
+
!source_code.nil? && !broken_test?
|
51
|
+
end
|
52
|
+
|
53
|
+
# The file most likely to be the source of the underlying problem. Often, the most recent
|
54
|
+
# backtrace files will be a gem or external library that's failing indirectly as a result
|
55
|
+
# of a problem with local source code (not always, but frequently). In that case, the best
|
56
|
+
# first place to focus is on the code you control.
|
57
|
+
#
|
58
|
+
# @return [Array] file and line number of the most likely source of the problem
|
59
|
+
def most_relevant
|
60
|
+
[
|
61
|
+
source_code,
|
62
|
+
test_failure,
|
63
|
+
final
|
64
|
+
].compact.first
|
65
|
+
end
|
66
|
+
|
67
|
+
def freshest
|
68
|
+
backtrace.recently_modified_locations.first
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns the final test location based on the backtrace if present. Otherwise falls back to
|
72
|
+
# the test location which represents the test definition. The `test_definition` attribute
|
73
|
+
# provides the location of where the test is defined. `test_failure` represents the actual
|
74
|
+
# line from within the test where the problem occurred
|
75
|
+
#
|
76
|
+
# @return [Location] the final location from the test files
|
77
|
+
def test_failure
|
78
|
+
backtrace.test_locations.any? ? backtrace.test_locations.first : test_definition
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns the final source code location based on the backtrace
|
82
|
+
#
|
83
|
+
# @return [Location] the final location from the source code files
|
84
|
+
def source_code
|
85
|
+
backtrace.source_code_locations.first
|
86
|
+
end
|
87
|
+
|
88
|
+
# Returns the final project location based on the backtrace if present. Otherwise falls back
|
89
|
+
# to the test location which represents the test definition.
|
90
|
+
#
|
91
|
+
# @return [Location] the final location from the project files
|
92
|
+
def project
|
93
|
+
backtrace.project_locations.any? ? backtrace.project_locations.first : test_definition
|
94
|
+
end
|
95
|
+
|
96
|
+
# The line number from within the `test_file` test definition where the failure occurred
|
97
|
+
#
|
98
|
+
# @return [Location] the last location from the backtrace or the test location if a backtrace
|
99
|
+
# was not passed to the initializer
|
100
|
+
def final
|
101
|
+
backtrace.locations.any? ? backtrace.locations.first : test_definition
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
data/lib/minitest/heat/map.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module Minitest
|
4
4
|
module Heat
|
5
|
+
# Structured approach to collecting the locations of issues for generating a heat map
|
5
6
|
class Map
|
6
7
|
MAXIMUM_FILES_TO_SHOW = 5
|
7
8
|
|
@@ -11,18 +12,29 @@ module Minitest
|
|
11
12
|
@hits = {}
|
12
13
|
end
|
13
14
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
# Records a hit to the list of files and issue types
|
16
|
+
# @param filename [String] the unique path and file name for recordings hits
|
17
|
+
# @param line_number [Integer] the line number where the issue was encountered
|
18
|
+
# @param type [Symbol] the type of issue that was encountered (i.e. :failure, :error, etc.)
|
19
|
+
#
|
20
|
+
# @return [void]
|
21
|
+
def add(pathname, line_number, type, backtrace: [])
|
22
|
+
@hits[pathname.to_s] ||= Hit.new(pathname)
|
23
|
+
@hits[pathname.to_s].log(type.to_sym, line_number, backtrace: backtrace)
|
18
24
|
end
|
19
25
|
|
26
|
+
# Returns a subset of affected files to keep the list from being overwhelming
|
27
|
+
#
|
28
|
+
# @return [Array] the list of files and the line numbers for each encountered issue type
|
20
29
|
def file_hits
|
21
30
|
hot_files.take(MAXIMUM_FILES_TO_SHOW)
|
22
31
|
end
|
23
32
|
|
24
33
|
private
|
25
34
|
|
35
|
+
# Sorts the files by hit "weight" so that the most problematic files are at the beginning
|
36
|
+
#
|
37
|
+
# @return [Array] the collection of files that encountred issues
|
26
38
|
def hot_files
|
27
39
|
hits.values.sort_by(&:weight).reverse
|
28
40
|
end
|
@@ -5,14 +5,14 @@ module Minitest
|
|
5
5
|
class Output
|
6
6
|
# Builds the collection of tokens for a backtrace when an exception occurs
|
7
7
|
class Backtrace
|
8
|
-
DEFAULT_LINE_COUNT =
|
8
|
+
DEFAULT_LINE_COUNT = 10
|
9
9
|
DEFAULT_INDENTATION_SPACES = 2
|
10
10
|
|
11
|
-
attr_accessor :
|
11
|
+
attr_accessor :locations, :backtrace
|
12
12
|
|
13
|
-
def initialize(
|
14
|
-
@
|
15
|
-
@backtrace =
|
13
|
+
def initialize(locations)
|
14
|
+
@locations = locations
|
15
|
+
@backtrace = locations.backtrace
|
16
16
|
@tokens = []
|
17
17
|
end
|
18
18
|
|
@@ -21,18 +21,8 @@ module Minitest
|
|
21
21
|
# final backtrace line if it might be relevant/helpful?
|
22
22
|
|
23
23
|
# Iterate over the selected lines from the backtrace
|
24
|
-
|
25
|
-
|
26
|
-
parts = [
|
27
|
-
indentation_token,
|
28
|
-
path_token(backtrace_entry),
|
29
|
-
*file_and_line_number_tokens(backtrace_entry),
|
30
|
-
source_code_line_token(backtrace_entry.source_code)
|
31
|
-
]
|
32
|
-
|
33
|
-
parts << file_freshness(backtrace_entry) if most_recently_modified?(backtrace_entry)
|
34
|
-
|
35
|
-
@tokens << parts
|
24
|
+
backtrace_locations.each do |location|
|
25
|
+
@tokens << backtrace_location_tokens(location)
|
36
26
|
end
|
37
27
|
|
38
28
|
@tokens
|
@@ -51,56 +41,74 @@ module Minitest
|
|
51
41
|
# ...it could be influenced by a "compact" or "robust" reporter super-style?
|
52
42
|
# ...it's smart about exceptions that were raised outside of the project?
|
53
43
|
# ...it's smart about highlighting lines of code differently based on whether it's source code, test code, or external code?
|
54
|
-
def
|
55
|
-
|
44
|
+
def backtrace_locations
|
45
|
+
backtrace.locations.take(line_count)
|
56
46
|
end
|
57
47
|
|
58
48
|
private
|
59
49
|
|
60
|
-
def
|
61
|
-
|
50
|
+
def backtrace_location_tokens(location)
|
51
|
+
[
|
52
|
+
indentation_token,
|
53
|
+
path_token(location),
|
54
|
+
*file_and_line_number_tokens(location),
|
55
|
+
containining_element_token(location),
|
56
|
+
source_code_line_token(location),
|
57
|
+
most_recently_modified_token(location),
|
58
|
+
].compact
|
62
59
|
end
|
63
60
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
backtrace.project_entries.take(line_count)
|
70
|
-
end
|
71
|
-
|
72
|
-
def all_entries
|
73
|
-
backtrace.parsed_entries.take(line_count)
|
61
|
+
# Determines if all lines to be displayed are from within the project directory
|
62
|
+
#
|
63
|
+
# @return [Boolean] true if all lines of the backtrace being displayed are from the project
|
64
|
+
def all_backtrace_from_project?
|
65
|
+
backtrace_locations.all?(&:project_file?)
|
74
66
|
end
|
75
67
|
|
76
|
-
def most_recently_modified?(
|
68
|
+
def most_recently_modified?(location)
|
77
69
|
# If there's more than one line being displayed, and the current line is the freshest
|
78
|
-
|
70
|
+
backtrace_locations.size > 1 && location == locations.freshest
|
79
71
|
end
|
80
72
|
|
81
73
|
def indentation_token
|
82
74
|
[:default, ' ' * indentation]
|
83
75
|
end
|
84
76
|
|
85
|
-
def path_token(
|
86
|
-
|
77
|
+
def path_token(location)
|
78
|
+
# If the line is a project file, help it stand out from the backtrace noise
|
79
|
+
style = location.project_file? ? :default : :muted
|
87
80
|
|
88
|
-
# If all of the backtrace lines are from the project, no point in the added redundant
|
89
|
-
#
|
90
|
-
|
81
|
+
# If *all* of the backtrace lines are from the project, no point in the added redundant
|
82
|
+
# noise of showing the project root directory over and over again
|
83
|
+
path_format = all_backtrace_from_project? ? :relative_path : :absolute_path
|
91
84
|
|
92
|
-
[
|
85
|
+
[style, location.send(path_format)]
|
93
86
|
end
|
94
87
|
|
95
|
-
def file_and_line_number_tokens(
|
96
|
-
|
88
|
+
def file_and_line_number_tokens(location)
|
89
|
+
style = location.to_s.include?(Dir.pwd) ? :bold : :muted
|
90
|
+
[
|
91
|
+
[style, location.filename],
|
92
|
+
[:muted, ':'],
|
93
|
+
[style, location.line_number]
|
94
|
+
]
|
97
95
|
end
|
98
96
|
|
99
|
-
def source_code_line_token(
|
100
|
-
|
97
|
+
def source_code_line_token(location)
|
98
|
+
return nil unless location.project_file?
|
99
|
+
|
100
|
+
[:muted, " #{Output::SYMBOLS[:arrow]} `#{location.source_code.line.strip}`"]
|
101
101
|
end
|
102
102
|
|
103
|
-
def
|
103
|
+
def containining_element_token(location)
|
104
|
+
return nil if !location.project_file? || location.container.nil? || location.container.empty?
|
105
|
+
|
106
|
+
[:muted, " in #{location.container}"]
|
107
|
+
end
|
108
|
+
|
109
|
+
def most_recently_modified_token(location)
|
110
|
+
return nil unless most_recently_modified?(location)
|
111
|
+
|
104
112
|
[:default, " #{Output::SYMBOLS[:middot]} Most Recently Modified File"]
|
105
113
|
end
|
106
114
|
|