Updated README.rdoc again
[feedcatcher.git] / vendor / rails / actionpack / lib / action_view / template_error.rb
1 module ActionView
2 # The TemplateError exception is raised when the compilation of the template fails. This exception then gathers a
3 # bunch of intimate details and uses it to report a very precise exception message.
4 class TemplateError < ActionViewError #:nodoc:
5 SOURCE_CODE_RADIUS = 3
6
7 attr_reader :original_exception
8
9 def initialize(template, assigns, original_exception)
10 @template, @assigns, @original_exception = template, assigns.dup, original_exception
11 @backtrace = compute_backtrace
12 end
13
14 def file_name
15 @template.relative_path
16 end
17
18 def message
19 ActiveSupport::Deprecation.silence { original_exception.message }
20 end
21
22 def clean_backtrace
23 if defined?(Rails) && Rails.respond_to?(:backtrace_cleaner)
24 Rails.backtrace_cleaner.clean(original_exception.backtrace)
25 else
26 original_exception.backtrace
27 end
28 end
29
30 def sub_template_message
31 if @sub_templates
32 "Trace of template inclusion: " +
33 @sub_templates.collect { |template| template.relative_path }.join(", ")
34 else
35 ""
36 end
37 end
38
39 def source_extract(indentation = 0)
40 return unless num = line_number
41 num = num.to_i
42
43 source_code = @template.source.split("\n")
44
45 start_on_line = [ num - SOURCE_CODE_RADIUS - 1, 0 ].max
46 end_on_line = [ num + SOURCE_CODE_RADIUS - 1, source_code.length].min
47
48 indent = ' ' * indentation
49 line_counter = start_on_line
50 return unless source_code = source_code[start_on_line..end_on_line]
51
52 source_code.sum do |line|
53 line_counter += 1
54 "#{indent}#{line_counter}: #{line}\n"
55 end
56 end
57
58 def sub_template_of(template_path)
59 @sub_templates ||= []
60 @sub_templates << template_path
61 end
62
63 def line_number
64 @line_number ||=
65 if file_name
66 regexp = /#{Regexp.escape File.basename(file_name)}:(\d+)/
67
68 $1 if message =~ regexp or clean_backtrace.find { |line| line =~ regexp }
69 end
70 end
71
72 def to_s
73 "\n#{self.class} (#{message}) #{source_location}:\n" +
74 "#{source_extract}\n #{clean_backtrace.join("\n ")}\n\n"
75 end
76
77 # don't do anything nontrivial here. Any raised exception from here becomes fatal
78 # (and can't be rescued).
79 def backtrace
80 @backtrace
81 end
82
83 private
84 def compute_backtrace
85 [
86 "#{source_location.capitalize}\n\n#{source_extract(4)}\n " +
87 clean_backtrace.join("\n ")
88 ]
89 end
90
91 def source_location
92 if line_number
93 "on line ##{line_number} of "
94 else
95 'in '
96 end + file_name
97 end
98 end
99 end