error_highlight 0.1.0 → 0.4.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: f6edc97e3eca88e8281056e7a3d9bceb448c0ac614b742e4ed38908a40e51e01
4
- data.tar.gz: 255b537c7d07f8dfd01b747719472e57d24e91703b8df678d655a3fc3f71897d
3
+ metadata.gz: a9ae1f66c6b1151cf65329869a64d4ea9ce7732344a6318aa99dc8a16aabeeff
4
+ data.tar.gz: d2e52f94f74c6569cea530e8a843d99030c0a2860f38b8591952faedba759419
5
5
  SHA512:
6
- metadata.gz: a63da67176a0dabd493fdafa1de60155a26696d22ba633d17765b29a359b0e4ffcc30d4806236bf416c828427d32171aca4210bdb1e018e0347e4cefef3e953a
7
- data.tar.gz: '08febd90564658489923f2ef0d2aab82a3796e52c7aa2a11ddcd6cc0d1f65abacd9b757b61bbb36bb59d7cf0e0c1eea820bce6d3b0bad3f771ead27714bc70ee'
6
+ metadata.gz: b6610f3e482792ae7f2eb8a2e8ada6c13f588b8d9fdbf2bac0948d99efb5046d92b9b5c83294661ecc91ffb1239b446b759d206db60da7dedaab5af48c7e3d4c
7
+ data.tar.gz: 481f0da516eff4f75662bb709f56aeb11b380336f3fbd82465af16c24e48bbaa20d4590e5bdad5373c283f7d8eaba90c458bd807a6f1c1b809aef4710cb5a302
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: 'github-actions'
4
+ directory: '/'
5
+ schedule:
6
+ interval: 'weekly'
@@ -13,9 +13,9 @@ jobs:
13
13
  runs-on: ubuntu-latest
14
14
  strategy:
15
15
  matrix:
16
- ruby: [ 'ruby-head' ]
16
+ ruby: [ 'ruby-head', '3.1' ]
17
17
  steps:
18
- - uses: actions/checkout@v2
18
+ - uses: actions/checkout@v3
19
19
  - uses: ruby/setup-ruby@v1
20
20
  with:
21
21
  ruby-version: ${{ matrix.ruby }}
@@ -24,4 +24,4 @@ jobs:
24
24
  bundle install
25
25
  - name: Run the test suite
26
26
  run: |
27
- bundle exec rake TESTOPT=-v
27
+ RUBYOPT=--disable-error_highlight bundle exec rake TESTOPT=-v
data/README.md CHANGED
@@ -29,7 +29,7 @@ def extract_value(data)
29
29
  end
30
30
  ```
31
31
 
32
- When `data` is `{ :results => [] }`, the following error messsage is shown:
32
+ When `data` is `{ :results => [] }`, the following error message is shown:
33
33
 
34
34
  ```
35
35
  $ ruby test.rb
@@ -51,13 +51,63 @@ test.rb:2:in `extract_value': undefined method `[]' for nil:NilClass (NoMethodEr
51
51
  from test.rb:5:in `<main>'
52
52
  ```
53
53
 
54
+ ## Using the `ErrorHighlight.spot`
55
+
56
+ *Note: This API is experimental, may change in future.*
57
+
58
+ You can use the `ErrorHighlight.spot` method to get the snippet data.
59
+ Note that the argument must be a RubyVM::AbstractSyntaxTree::Node object that is created with `keep_script_lines: true` option (which is available since Ruby 3.1).
60
+
61
+ ```ruby
62
+ class Dummy
63
+ def test(_dummy_arg)
64
+ node = RubyVM::AbstractSyntaxTree.of(caller_locations.first, keep_script_lines: true)
65
+ ErrorHighlight.spot(node)
66
+ end
67
+ end
68
+
69
+ pp Dummy.new.test(42) # <- Line 8
70
+ # ^^^^^ <- Column 12--17
71
+
72
+ #=> {:first_lineno=>8,
73
+ # :first_column=>12,
74
+ # :last_lineno=>8,
75
+ # :last_column=>17,
76
+ # :snippet=>"pp Dummy.new.test(42) # <- Line 8\n"}
77
+ ```
78
+
79
+ ## Custom Formatter
80
+
81
+ If you want to customize the message format for code snippet, use `ErrorHighlight.formatter=` to set your custom object that responds to `message_for` method.
82
+
83
+ ```ruby
84
+ formatter = Object.new
85
+ def formatter.message_for(spot)
86
+ marker = " " * spot[:first_column] + "^" + "~" * (spot[:last_column] - spot[:first_column] - 1)
87
+
88
+ "\n\n#{ spot[:snippet] }#{ marker }"
89
+ end
90
+
91
+ ErrorHighlight.formatter = formatter
92
+
93
+ 1.time {}
94
+
95
+ #=>
96
+ #
97
+ # test.rb:10:in `<main>': undefined method `time' for 1:Integer (NoMethodError)
98
+ #
99
+ # 1.time {}
100
+ # ^~~~~
101
+ # Did you mean? times
102
+ ```
103
+
54
104
  ## Disabling `error_highlight`
55
105
 
56
106
  Occasionally, you may want to disable the `error_highlight` gem for e.g. debugging issues in the error object itself. You
57
107
  can disable it entirely by specifying `--disable-error_highlight` option to the `ruby` command:
58
108
 
59
109
  ```bash
60
- $ uby --disable-error_highlight -e '1.time {}'
110
+ $ ruby --disable-error_highlight -e '1.time {}'
61
111
  -e:1:in `<main>': undefined method `time' for 1:Integer (NoMethodError)
62
112
  Did you mean? times
63
113
  ```
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.homepage = "https://github.com/ruby/error_highlight"
19
19
 
20
20
  spec.license = "MIT"
21
- spec.required_ruby_version = Gem::Requirement.new(">= 3.1.0")
21
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.1.0.dev")
22
22
 
23
23
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
24
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
@@ -1,13 +1,17 @@
1
1
  require_relative "version"
2
2
 
3
3
  module ErrorHighlight
4
- # Identify the code fragment that seems associated with a given error
4
+ # Identify the code fragment at that a given exception occurred.
5
5
  #
6
- # Arguments:
7
- # node: RubyVM::AbstractSyntaxTree::Node
8
- # point: :name | :args
9
- # name: The name associated with the NameError/NoMethodError
10
- # fetch: A block to fetch a specified code line (or lines)
6
+ # Options:
7
+ #
8
+ # point_type: :name | :args
9
+ # :name (default) points the method/variable name that the exception occurred.
10
+ # :args points the arguments of the method call that the exception occurred.
11
+ #
12
+ # backtrace_location: Thread::Backtrace::Location
13
+ # It locates the code fragment of the given backtrace_location.
14
+ # By default, it uses the first frame of backtrace_locations of the given exception.
11
15
  #
12
16
  # Returns:
13
17
  # {
@@ -15,23 +19,76 @@ module ErrorHighlight
15
19
  # first_column: Integer,
16
20
  # last_lineno: Integer,
17
21
  # last_column: Integer,
18
- # line: String,
22
+ # snippet: String,
23
+ # script_lines: [String],
19
24
  # } | nil
20
- def self.spot(...)
21
- Spotter.new(...).spot
25
+ def self.spot(obj, **opts)
26
+ case obj
27
+ when Exception
28
+ exc = obj
29
+ loc = opts[:backtrace_location]
30
+ opts = { point_type: opts.fetch(:point_type, :name) }
31
+
32
+ unless loc
33
+ case exc
34
+ when TypeError, ArgumentError
35
+ opts[:point_type] = :args
36
+ end
37
+
38
+ locs = exc.backtrace_locations
39
+ return nil unless locs
40
+
41
+ loc = locs.first
42
+ return nil unless loc
43
+
44
+ opts[:name] = exc.name if NameError === obj
45
+ end
46
+
47
+ return nil unless Thread::Backtrace::Location === loc
48
+
49
+ node = RubyVM::AbstractSyntaxTree.of(loc, keep_script_lines: true)
50
+
51
+ Spotter.new(node, **opts).spot
52
+
53
+ when RubyVM::AbstractSyntaxTree::Node
54
+ # Just for compatibility
55
+ Spotter.new(node, **opts).spot
56
+
57
+ else
58
+ raise TypeError, "Exception is expected"
59
+ end
60
+
61
+ rescue SyntaxError,
62
+ SystemCallError, # file not found or something
63
+ ArgumentError # eval'ed code
64
+
65
+ return nil
22
66
  end
23
67
 
24
68
  class Spotter
25
- def initialize(node, point, name: nil, &fetch)
69
+ class NonAscii < Exception; end
70
+ private_constant :NonAscii
71
+
72
+ def initialize(node, point_type: :name, name: nil)
26
73
  @node = node
27
- @point = point
74
+ @point_type = point_type
28
75
  @name = name
29
76
 
30
77
  # Not-implemented-yet options
31
78
  @arg = nil # Specify the index or keyword at which argument caused the TypeError/ArgumentError
32
79
  @multiline = false # Allow multiline spot
33
80
 
34
- @fetch = fetch
81
+ @fetch = -> (lineno, last_lineno = lineno) do
82
+ snippet = @node.script_lines[lineno - 1 .. last_lineno - 1].join("")
83
+ snippet += "\n" unless snippet.end_with?("\n")
84
+
85
+ # It require some work to support Unicode (or multibyte) characters.
86
+ # Tentatively, we stop highlighting if the code snippet has non-ascii characters.
87
+ # See https://github.com/ruby/error_highlight/issues/4
88
+ raise NonAscii unless snippet.ascii_only?
89
+
90
+ snippet
91
+ end
35
92
  end
36
93
 
37
94
  def spot
@@ -40,7 +97,7 @@ module ErrorHighlight
40
97
  case @node.type
41
98
 
42
99
  when :CALL, :QCALL
43
- case @point
100
+ case @point_type
44
101
  when :name
45
102
  spot_call_for_name
46
103
  when :args
@@ -48,7 +105,7 @@ module ErrorHighlight
48
105
  end
49
106
 
50
107
  when :ATTRASGN
51
- case @point
108
+ case @point_type
52
109
  when :name
53
110
  spot_attrasgn_for_name
54
111
  when :args
@@ -56,7 +113,7 @@ module ErrorHighlight
56
113
  end
57
114
 
58
115
  when :OPCALL
59
- case @point
116
+ case @point_type
60
117
  when :name
61
118
  spot_opcall_for_name
62
119
  when :args
@@ -64,7 +121,7 @@ module ErrorHighlight
64
121
  end
65
122
 
66
123
  when :FCALL
67
- case @point
124
+ case @point_type
68
125
  when :name
69
126
  spot_fcall_for_name
70
127
  when :args
@@ -75,7 +132,7 @@ module ErrorHighlight
75
132
  spot_vcall
76
133
 
77
134
  when :OP_ASGN1
78
- case @point
135
+ case @point_type
79
136
  when :name
80
137
  spot_op_asgn1_for_name
81
138
  when :args
@@ -83,7 +140,7 @@ module ErrorHighlight
83
140
  end
84
141
 
85
142
  when :OP_ASGN2
86
- case @point
143
+ case @point_type
87
144
  when :name
88
145
  spot_op_asgn2_for_name
89
146
  when :args
@@ -103,17 +160,21 @@ module ErrorHighlight
103
160
  spot_op_cdecl
104
161
  end
105
162
 
106
- if @line && @beg_column && @end_column && @beg_column < @end_column
163
+ if @snippet && @beg_column && @end_column && @beg_column < @end_column
107
164
  return {
108
165
  first_lineno: @beg_lineno,
109
166
  first_column: @beg_column,
110
167
  last_lineno: @end_lineno,
111
168
  last_column: @end_column,
112
- line: @line,
169
+ snippet: @snippet,
170
+ script_lines: @node.script_lines,
113
171
  }
114
172
  else
115
173
  return nil
116
174
  end
175
+
176
+ rescue NonAscii
177
+ nil
117
178
  end
118
179
 
119
180
  private
@@ -133,34 +194,34 @@ module ErrorHighlight
133
194
  nd_recv, mid, nd_args = @node.children
134
195
  lineno = nd_recv.last_lineno
135
196
  lines = @fetch[lineno, @node.last_lineno]
136
- if mid == :[] && lines.match(/\G\s*(\[(?:\s*\])?)/, nd_recv.last_column)
197
+ if mid == :[] && lines.match(/\G[\s)]*(\[(?:\s*\])?)/, nd_recv.last_column)
137
198
  @beg_column = $~.begin(1)
138
- @line = lines[/.*\n/]
199
+ @snippet = lines[/.*\n/]
139
200
  @beg_lineno = @end_lineno = lineno
140
201
  if nd_args
141
- if nd_recv.last_lineno == nd_args.last_lineno && @line.match(/\s*\]/, nd_args.last_column)
202
+ if nd_recv.last_lineno == nd_args.last_lineno && @snippet.match(/\s*\]/, nd_args.last_column)
142
203
  @end_column = $~.end(0)
143
204
  end
144
205
  else
145
- if lines.match(/\G\s*?\[\s*\]/, nd_recv.last_column)
206
+ if lines.match(/\G[\s)]*?\[\s*\]/, nd_recv.last_column)
146
207
  @end_column = $~.end(0)
147
208
  end
148
209
  end
149
- elsif lines.match(/\G\s*?(\&?\.)(\s*?)(#{ Regexp.quote(mid) }).*\n/, nd_recv.last_column)
210
+ elsif lines.match(/\G[\s)]*?(\&?\.)(\s*?)(#{ Regexp.quote(mid) }).*\n/, nd_recv.last_column)
150
211
  lines = $` + $&
151
212
  @beg_column = $~.begin($2.include?("\n") ? 3 : 1)
152
213
  @end_column = $~.end(3)
153
214
  if i = lines[..@beg_column].rindex("\n")
154
215
  @beg_lineno = @end_lineno = lineno + lines[..@beg_column].count("\n")
155
- @line = lines[i + 1..]
216
+ @snippet = lines[i + 1..]
156
217
  @beg_column -= i + 1
157
218
  @end_column -= i + 1
158
219
  else
159
- @line = lines
220
+ @snippet = lines
160
221
  @beg_lineno = @end_lineno = lineno
161
222
  end
162
223
  elsif mid.to_s =~ /\A\W+\z/ && lines.match(/\G\s*(#{ Regexp.quote(mid) })=.*\n/, nd_recv.last_column)
163
- @line = $` + $&
224
+ @snippet = $` + $&
164
225
  @beg_column = $~.begin(1)
165
226
  @end_column = $~.end(1)
166
227
  end
@@ -192,16 +253,16 @@ module ErrorHighlight
192
253
  nd_recv, mid, nd_args = @node.children
193
254
  *nd_args, _nd_last_arg, _nil = nd_args.children
194
255
  fetch_line(nd_recv.last_lineno)
195
- if mid == :[]= && @line.match(/\G\s*(\[)/, nd_recv.last_column)
256
+ if mid == :[]= && @snippet.match(/\G[\s)]*(\[)/, nd_recv.last_column)
196
257
  @beg_column = $~.begin(1)
197
258
  args_last_column = $~.end(0)
198
259
  if nd_args.last && nd_recv.last_lineno == nd_args.last.last_lineno
199
260
  args_last_column = nd_args.last.last_column
200
261
  end
201
- if @line.match(/\s*\]\s*=/, args_last_column)
262
+ if @snippet.match(/[\s)]*\]\s*=/, args_last_column)
202
263
  @end_column = $~.end(0)
203
264
  end
204
- elsif @line.match(/\G\s*(\.\s*#{ Regexp.quote(mid.to_s.sub(/=\z/, "")) }\s*=)/, nd_recv.last_column)
265
+ elsif @snippet.match(/\G[\s)]*(\.\s*#{ Regexp.quote(mid.to_s.sub(/=\z/, "")) }\s*=)/, nd_recv.last_column)
205
266
  @beg_column = $~.begin(1)
206
267
  @end_column = $~.end(1)
207
268
  end
@@ -217,7 +278,7 @@ module ErrorHighlight
217
278
  def spot_attrasgn_for_args
218
279
  nd_recv, mid, nd_args = @node.children
219
280
  fetch_line(nd_recv.last_lineno)
220
- if mid == :[]= && @line.match(/\G\s*\[/, nd_recv.last_column)
281
+ if mid == :[]= && @snippet.match(/\G[\s)]*\[/, nd_recv.last_column)
221
282
  @beg_column = $~.end(0)
222
283
  if nd_recv.last_lineno == nd_args.last_lineno
223
284
  @end_column = nd_args.last_column
@@ -239,13 +300,13 @@ module ErrorHighlight
239
300
  fetch_line(nd_recv.last_lineno)
240
301
  if nd_arg
241
302
  # binary operator
242
- if @line.match(/\G\s*(#{ Regexp.quote(op) })/, nd_recv.last_column)
303
+ if @snippet.match(/\G[\s)]*(#{ Regexp.quote(op) })/, nd_recv.last_column)
243
304
  @beg_column = $~.begin(1)
244
305
  @end_column = $~.end(1)
245
306
  end
246
307
  else
247
308
  # unary operator
248
- if @line[...nd_recv.first_column].match(/(#{ Regexp.quote(op.to_s.sub(/@\z/, "")) })\s*\(?\s*\z/)
309
+ if @snippet[...nd_recv.first_column].match(/(#{ Regexp.quote(op.to_s.sub(/@\z/, "")) })\s*\(?\s*\z/)
249
310
  @beg_column = $~.begin(1)
250
311
  @end_column = $~.end(1)
251
312
  end
@@ -273,7 +334,7 @@ module ErrorHighlight
273
334
  def spot_fcall_for_name
274
335
  mid, _nd_args = @node.children
275
336
  fetch_line(@node.first_lineno)
276
- if @line.match(/(#{ Regexp.quote(mid) })/, @node.first_column)
337
+ if @snippet.match(/(#{ Regexp.quote(mid) })/, @node.first_column)
277
338
  @beg_column = $~.begin(1)
278
339
  @end_column = $~.end(1)
279
340
  end
@@ -315,13 +376,13 @@ module ErrorHighlight
315
376
  def spot_op_asgn1_for_name
316
377
  nd_recv, op, nd_args, _nd_rhs = @node.children
317
378
  fetch_line(nd_recv.last_lineno)
318
- if @line.match(/\G\s*(\[)/, nd_recv.last_column)
379
+ if @snippet.match(/\G[\s)]*(\[)/, nd_recv.last_column)
319
380
  bracket_beg_column = $~.begin(1)
320
381
  args_last_column = $~.end(0)
321
382
  if nd_args && nd_recv.last_lineno == nd_args.last_lineno
322
383
  args_last_column = nd_args.last_column
323
384
  end
324
- if @line.match(/\s*\](\s*)(#{ Regexp.quote(op) })=()/, args_last_column)
385
+ if @snippet.match(/\s*\](\s*)(#{ Regexp.quote(op) })=()/, args_last_column)
325
386
  case @name
326
387
  when :[], :[]=
327
388
  @beg_column = bracket_beg_column
@@ -340,7 +401,7 @@ module ErrorHighlight
340
401
  def spot_op_asgn1_for_args
341
402
  nd_recv, mid, nd_args, nd_rhs = @node.children
342
403
  fetch_line(nd_recv.last_lineno)
343
- if mid == :[]= && @line.match(/\G\s*\[/, nd_recv.last_column)
404
+ if mid == :[]= && @snippet.match(/\G\s*\[/, nd_recv.last_column)
344
405
  @beg_column = $~.end(0)
345
406
  if nd_recv.last_lineno == nd_rhs.last_lineno
346
407
  @end_column = nd_rhs.last_column
@@ -362,7 +423,7 @@ module ErrorHighlight
362
423
  def spot_op_asgn2_for_name
363
424
  nd_recv, _qcall, attr, op, _nd_rhs = @node.children
364
425
  fetch_line(nd_recv.last_lineno)
365
- if @line.match(/\G\s*(\.)\s*#{ Regexp.quote(attr) }()\s*(#{ Regexp.quote(op) })(=)/, nd_recv.last_column)
426
+ if @snippet.match(/\G[\s)]*(\.)\s*#{ Regexp.quote(attr) }()\s*(#{ Regexp.quote(op) })(=)/, nd_recv.last_column)
366
427
  case @name
367
428
  when attr
368
429
  @beg_column = $~.begin(1)
@@ -399,8 +460,8 @@ module ErrorHighlight
399
460
  @beg_column = nd_parent.last_column
400
461
  @end_column = @node.last_column
401
462
  else
402
- @line = @fetch[@node.last_lineno]
403
- if @line[...@node.last_column].match(/#{ Regexp.quote(const) }\z/)
463
+ @snippet = @fetch[@node.last_lineno]
464
+ if @snippet[...@node.last_column].match(/#{ Regexp.quote(const) }\z/)
404
465
  @beg_column = $~.begin(0)
405
466
  @end_column = $~.end(0)
406
467
  end
@@ -414,8 +475,8 @@ module ErrorHighlight
414
475
  nd_lhs, op, _nd_rhs = @node.children
415
476
  *nd_parent_lhs, _const = nd_lhs.children
416
477
  if @name == op
417
- @line = @fetch[nd_lhs.last_lineno]
418
- if @line.match(/\G\s*(#{ Regexp.quote(op) })=/, nd_lhs.last_column)
478
+ @snippet = @fetch[nd_lhs.last_lineno]
479
+ if @snippet.match(/\G\s*(#{ Regexp.quote(op) })=/, nd_lhs.last_column)
419
480
  @beg_column = $~.begin(1)
420
481
  @end_column = $~.end(1)
421
482
  end
@@ -424,12 +485,12 @@ module ErrorHighlight
424
485
  @end_column = nd_lhs.last_column
425
486
  if nd_parent_lhs.empty? # example: ::C += 1
426
487
  if nd_lhs.first_lineno == nd_lhs.last_lineno
427
- @line = @fetch[nd_lhs.last_lineno]
488
+ @snippet = @fetch[nd_lhs.last_lineno]
428
489
  @beg_column = nd_lhs.first_column
429
490
  end
430
491
  else # example: Foo::Bar::C += 1
431
492
  if nd_parent_lhs.last.last_lineno == nd_lhs.last_lineno
432
- @line = @fetch[nd_lhs.last_lineno]
493
+ @snippet = @fetch[nd_lhs.last_lineno]
433
494
  @beg_column = nd_parent_lhs.last.last_column
434
495
  end
435
496
  end
@@ -438,7 +499,7 @@ module ErrorHighlight
438
499
 
439
500
  def fetch_line(lineno)
440
501
  @beg_lineno = @end_lineno = lineno
441
- @line = @fetch[lineno]
502
+ @snippet = @fetch[lineno]
442
503
  end
443
504
  end
444
505
 
@@ -1,48 +1,45 @@
1
+ require_relative "formatter"
2
+
1
3
  module ErrorHighlight
2
4
  module CoreExt
3
- SKIP_TO_S_FOR_SUPER_LOOKUP = true
4
- private_constant :SKIP_TO_S_FOR_SUPER_LOOKUP
5
-
6
- def to_s
7
- msg = super.dup
8
-
9
- locs = backtrace_locations
10
- return msg unless locs
11
-
12
- loc = locs.first
13
- begin
14
- node = RubyVM::AbstractSyntaxTree.of(loc, save_script_lines: true)
15
- opts = {}
16
-
17
- case self
18
- when NoMethodError, NameError
19
- point = :name
20
- opts[:name] = name
21
- when TypeError, ArgumentError
22
- point = :args
23
- end
5
+ private def generate_snippet
6
+ spot = ErrorHighlight.spot(self)
7
+ return "" unless spot
8
+ return ErrorHighlight.formatter.message_for(spot)
9
+ end
24
10
 
25
- spot = ErrorHighlight.spot(node, point, **opts) do |lineno, last_lineno|
26
- last_lineno ||= lineno
27
- node.script_lines[lineno - 1 .. last_lineno - 1].join("")
11
+ if Exception.method_defined?(:detailed_message)
12
+ def detailed_message(highlight: false, error_highlight: true, **)
13
+ return super unless error_highlight
14
+ snippet = generate_snippet
15
+ if highlight
16
+ snippet = snippet.gsub(/.+/) { "\e[1m" + $& + "\e[m" }
28
17
  end
29
-
30
- rescue Errno::ENOENT
18
+ super + snippet
31
19
  end
32
-
33
- if spot
34
- marker = " " * spot[:first_column] + "^" * (spot[:last_column] - spot[:first_column])
35
- points = "\n\n#{ spot[:line] }#{ marker }"
36
- msg << points if !msg.include?(points)
20
+ else
21
+ # This is a marker to let `DidYouMean::Correctable#original_message` skip
22
+ # the following method definition of `to_s`.
23
+ # See https://github.com/ruby/did_you_mean/pull/152
24
+ SKIP_TO_S_FOR_SUPER_LOOKUP = true
25
+ private_constant :SKIP_TO_S_FOR_SUPER_LOOKUP
26
+
27
+ def to_s
28
+ msg = super
29
+ snippet = generate_snippet
30
+ if snippet != "" && !msg.include?(snippet)
31
+ msg + snippet
32
+ else
33
+ msg
34
+ end
37
35
  end
38
-
39
- msg
40
36
  end
41
37
  end
42
38
 
43
39
  NameError.prepend(CoreExt)
44
40
 
45
- # temporarily disabled
41
+ # The extension for TypeError/ArgumentError is temporarily disabled due to many test failures
42
+
46
43
  #TypeError.prepend(CoreExt)
47
44
  #ArgumentError.prepend(CoreExt)
48
45
  end
@@ -0,0 +1,23 @@
1
+ module ErrorHighlight
2
+ class DefaultFormatter
3
+ def self.message_for(spot)
4
+ # currently only a one-line code snippet is supported
5
+ if spot[:first_lineno] == spot[:last_lineno]
6
+ indent = spot[:snippet][0...spot[:first_column]].gsub(/[^\t]/, " ")
7
+ marker = indent + "^" * (spot[:last_column] - spot[:first_column])
8
+
9
+ "\n\n#{ spot[:snippet] }#{ marker }"
10
+ else
11
+ ""
12
+ end
13
+ end
14
+ end
15
+
16
+ def self.formatter
17
+ Ractor.current[:__error_highlight_formatter__] || DefaultFormatter
18
+ end
19
+
20
+ def self.formatter=(formatter)
21
+ Ractor.current[:__error_highlight_formatter__] = formatter
22
+ end
23
+ end
@@ -1,3 +1,3 @@
1
1
  module ErrorHighlight
2
- VERSION = "0.1.0"
2
+ VERSION = "0.4.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: error_highlight
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yusuke Endoh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-29 00:00:00.000000000 Z
11
+ date: 2022-08-10 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: The gem enhances Exception#message by adding a short explanation where
14
14
  the exception is raised
@@ -18,6 +18,7 @@ executables: []
18
18
  extensions: []
19
19
  extra_rdoc_files: []
20
20
  files:
21
+ - ".github/dependabot.yml"
21
22
  - ".github/workflows/ruby.yml"
22
23
  - ".gitignore"
23
24
  - Gemfile
@@ -28,6 +29,7 @@ files:
28
29
  - lib/error_highlight.rb
29
30
  - lib/error_highlight/base.rb
30
31
  - lib/error_highlight/core_ext.rb
32
+ - lib/error_highlight/formatter.rb
31
33
  - lib/error_highlight/version.rb
32
34
  homepage: https://github.com/ruby/error_highlight
33
35
  licenses:
@@ -41,14 +43,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
41
43
  requirements:
42
44
  - - ">="
43
45
  - !ruby/object:Gem::Version
44
- version: 3.1.0
46
+ version: 3.1.0.dev
45
47
  required_rubygems_version: !ruby/object:Gem::Requirement
46
48
  requirements:
47
49
  - - ">="
48
50
  - !ruby/object:Gem::Version
49
51
  version: '0'
50
52
  requirements: []
51
- rubygems_version: 3.3.0.dev
53
+ rubygems_version: 3.3.7
52
54
  signing_key:
53
55
  specification_version: 4
54
56
  summary: Shows a one-line code snippet with an underline in the error backtrace