forked from rails/rails
-
Notifications
You must be signed in to change notification settings - Fork 0
/
syntax_error_proxy.rb
68 lines (59 loc) · 2.08 KB
/
syntax_error_proxy.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# frozen_string_literal: true
require "delegate"
module ActiveSupport
# This is a class for wrapping syntax errors. The purpose of this class
# is to enhance the backtraces on SyntaxError exceptions to include the
# source location of the syntax error. That way we can display the error
# source on error pages in development.
class SyntaxErrorProxy < DelegateClass(SyntaxError) # :nodoc:
def backtrace
parse_message_for_trace + super
end
class BacktraceLocation < Struct.new(:path, :lineno, :to_s) # :nodoc:
def spot(_)
end
def label
end
end
class BacktraceLocationProxy < DelegateClass(Thread::Backtrace::Location) # :nodoc:
def initialize(loc, ex)
super(loc)
@ex = ex
end
def spot(_)
super(@ex.__getobj__)
end
end
def backtrace_locations
parse_message_for_trace.map { |trace|
file, line = trace.match(/^(.+?):(\d+).*$/, &:captures) || trace
BacktraceLocation.new(file, line.to_i, trace)
# We have to wrap these backtrace locations because we need the
# spot information to come from the originating exception, not the
# proxy object that's generating these
} + super.map { |loc| BacktraceLocationProxy.new(loc, self) }
end
private
def parse_message_for_trace
if source_location_eval?
# If the exception is coming from a call to eval, we need to keep
# the path of the file in which eval was called to ensure we can
# return the right source fragment to show the location of the
# error
location = __getobj__.backtrace_locations[0]
["#{location.path}:#{location.lineno}: #{__getobj__}"]
else
__getobj__.to_s.split("\n")
end
end
if SyntaxError.method_defined?(:path) # Ruby 3.3+
def source_location_eval?
__getobj__.path.start_with?("(eval")
end
else # 3.2 and older versions of Ruby
def source_location_eval?
__getobj__.to_s.start_with?("(eval")
end
end
end
end