require 'facet/ormsupport' # This supports source code extraction from a full # backtrace from any exception and also exposes class # methods incase you wish to harness them from elsewhere. #-- # TODO: Cache source code? Memory vs Speed - Is it worth # it? # FIXME: Don't change the Exception class, use NitroException # or something. #++ class Exception # :nodoc: all # Radius of the source code to display arround the error line. SOURCE_RADIUS = 5 class << self # Extracts the filename and line from the given line (step) # of the backtrace. def file_and_line_no(step) file = no = nil if res = step.match(/^(.+):(\d+)$/) file = res[1] no = res[2] elsif res = step.match(/^(.+):(\d+):in `.+'$/) file = res[1] no = res[2] end if file and no [file,no.to_i] else nil end end # Extract the source arround the error line. def source_extract(step, indent = 0) begin file, no = file_and_line_no(step) source = File.read(file) if file =~ /\.xhtml$/ source = Compiler.new(Nitro::Controller).transform_template(:action, source) no -= 2 end source = source.split("\n") start = (no-1) - SOURCE_RADIUS finish = (no-1) + SOURCE_RADIUS start = 0 if start < 0 finish = source.size if finish > source.size number = start extract = source[start..finish].collect do |line| number += 1 line = line.gsub(/; @out #{Nitro::TemplateMixin::START_DELIM}/, ' ?>').gsub(/#{Nitro::TemplateMixin::END_DELIM}/, ' ex '' end end end # Identifies the 'hot' index in the backtrace, where the error # actually happened. def hot_trace_index index = 0 while backtrace[index] =~ /controller\.rb(.*)method_missing/ index += 1 end return index end # Returns the 'hot' backtrace line. def hot_trace_step backtrace[hot_trace_index] end # Returns the 'hot' backtrace file. def hot_file file_and_line_no(hot_trace_step).first end def file_and_line_no(step) self.class.file_and_line_no(step) end def source_extract(step = hot_trace_step, indent = 0) self.class.source_extract(step,indent) end # Extract source for backtrace. def source_for_backtrace(indent = 0) backtrace.inject([]) do |sources, step| sources << source_extract(step, indent) end end end