Skip to content

Commit

Permalink
Merge pull request #48957 from cmaruz/48326
Browse files Browse the repository at this point in the history
Better handle SyntaxError in Action View
  • Loading branch information
byroot committed Dec 5, 2023
2 parents c4733f3 + df6d2fb commit b979afe
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 3 deletions.
Expand Up @@ -242,7 +242,7 @@ def initialize(location, template)
end

def spot(exc)
if RubyVM::AbstractSyntaxTree.respond_to?(:node_id_for_backtrace_location)
if RubyVM::AbstractSyntaxTree.respond_to?(:node_id_for_backtrace_location) && __getobj__.is_a?(Thread::Backtrace::Location)
location = @template.spot(__getobj__)
else
location = super
Expand All @@ -267,7 +267,12 @@ def build_backtrace

(@exception.backtrace_locations || []).map do |loc|
if built_methods.key?(loc.label.to_s)
SourceMapLocation.new(loc, built_methods[loc.label.to_s])
thread_backtrace_location = if loc.respond_to?(:__getobj__)
loc.__getobj__
else
loc
end
SourceMapLocation.new(thread_backtrace_location, built_methods[loc.label.to_s])
else
loc
end
Expand Down
14 changes: 14 additions & 0 deletions actionpack/test/dispatch/exception_wrapper_test.rb
Expand Up @@ -69,6 +69,20 @@ def backtrace
end
end

class_eval "def throw_syntax_error; eval %(
'abc' + pluralize 'def'
); end", "lib/file.rb", 42

test "#source_extracts works with eval syntax error" do
exception = begin throw_syntax_error; rescue SyntaxError => ex; ex; end

wrapper = ExceptionWrapper.new(nil, TopErrorProxy.new(exception, 1))

assert_called_with(wrapper, :source_fragment, ["lib/file.rb", 42], returns: "foo") do
assert_equal [ code: "foo", line_number: 42 ], wrapper.source_extracts
end
end

if defined?(ErrorHighlight) && Gem::Version.new(ErrorHighlight::VERSION) >= Gem::Version.new("0.4.0")
test "#source_extracts works with error_highlight" do
lineno = __LINE__
Expand Down
21 changes: 20 additions & 1 deletion activesupport/lib/active_support/syntax_error_proxy.rb
Expand Up @@ -43,7 +43,26 @@ def backtrace_locations

private
def parse_message_for_trace
__getobj__.to_s.split("\n")
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

0 comments on commit b979afe

Please sign in to comment.