Empty array instead of nil for source_extract

The source_extract method will return nil when it can't find the file name in
the backtrace, methods that consume this method expect an array and the nil ends
up causing type errors down the road like it happened here: #36341. This
patch refactors the source_extract method so that it returns an empty
array instead of nil when it can't find the source code.

Co-authored-by: Kasper Timm Hansen <kaspth@gmail.com>
This commit is contained in:
Guilherme Mansur 2019-06-21 15:04:28 -04:00
parent 727da1d8cd
commit 526a5eb10c
3 changed files with 29 additions and 12 deletions

@ -1,3 +1,8 @@
* annotated_source_code returns an empty array so TemplateErrors without a
template in the backtrace are surfaced properly by DebugExceptions.
*Guilherme Mansur*, *Kasper Timm Hansen*
* Add autoload for SyntaxErrorInTemplate so syntax errors are correctly raised by DebugExceptions.
*Guilherme Mansur*, *Gannon McGibbon*

@ -81,8 +81,8 @@ def sub_template_message
end
end
def source_extract(indentation = 0, output = :console)
return unless num = line_number
def source_extract(indentation = 0)
return [] unless num = line_number
num = num.to_i
source_code = @template.source.split("\n")
@ -91,9 +91,9 @@ def source_extract(indentation = 0, output = :console)
end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
indent = end_on_line.to_s.size + indentation
return unless source_code = source_code[start_on_line..end_on_line]
return [] unless source_code = source_code[start_on_line..end_on_line]
formatted_code_for(source_code, start_on_line, indent, output)
formatted_code_for(source_code, start_on_line, indent)
end
def sub_template_of(template_path)
@ -122,15 +122,11 @@ def source_location
end + file_name
end
def formatted_code_for(source_code, line_counter, indent, output)
start_value = (output == :html) ? {} : []
source_code.inject(start_value) do |result, line|
def formatted_code_for(source_code, line_counter, indent)
indent_template = "%#{indent}s: %s"
source_code.map do |line|
line_counter += 1
if output == :html
result.update(line_counter.to_s => "%#{indent}s %s\n" % ["", line])
else
result << "%#{indent}s: %s" % [line_counter, line]
end
indent_template % [line_counter, line]
end
end
end

@ -34,4 +34,20 @@ def test_provides_useful_inspect
assert_equal "#<ActionView::Template::Error: original>", error.inspect
end
def test_annotated_source_code_returns_empty_array_if_source_cant_be_found
template = Class.new do
def identifier
"something"
end
end.new
error = begin
raise
rescue
raise ActionView::Template::Error.new(template) rescue $!
end
assert_equal [], error.annotated_source_code
end
end