lib/qed/reporter/abstract.rb in qed-2.5.1 vs lib/qed/reporter/abstract.rb in qed-2.6.0
- old
+ new
@@ -1,19 +1,28 @@
module QED
module Reporter
require 'facets/string'
- require 'ansi/code'
+ begin
+ require 'ansi/core'
+ rescue LoadError
+ require 'ansi/code'
+ end
+
# = Reporter Absract Base Class
#
# Serves as the base class for all other output formats.
class Abstract
+ attr :session
+
attr :io
+
attr :record
+ # TODO: pass session into initialize
def initialize(options={})
@io = options[:io] || STDOUT
@trace = options[:trace]
@record = {
@@ -108,10 +117,11 @@
end
# At the start of a session, before running any demonstrations.
def before_session(session)
+ @session = session
@start_time = Time.now
end
# Beginning of a demonstration.
def before_demo(demo) #demo(demo)
@@ -246,16 +256,28 @@
io.puts mask % vars
end
#
- def clean_backtrace(btrace)
- btrace.chomp(":in \`__binding__'")
+ INTERNALS = /(lib|bin)[\\\/](qed|ae)/
+
+ #
+ def sane_backtrace(exception)
+ if trace_count
+ clean_backtrace(*exception.backtrace[0, trace_count])
+ else
+ clean_backtrace(*exception.backtrace)
+ end
end
#
- INTERNALS = /(lib|bin)[\\\/](qed|ae)/
+ def clean_backtrace(*btrace)
+ stack = btrace.reject{ |bt| bt =~ INTERNALS } unless $DEBUG
+ stack.map do |bt|
+ bt.chomp(":in \`__binding__'")
+ end
+ end
=begin
# Clean the backtrace of any reference to ko/ paths and code.
def clean_backtrace(backtrace)
trace = backtrace.reject{ |bt| bt =~ INTERNALS }
@@ -267,47 +289,143 @@
end
end
end
=end
+ # Produce a pretty code snippet given an exception.
#
- def code_snippet(exception, bredth=3)
- backtrace = exception.backtrace.reject{ |bt| bt =~ INTERNALS }
- backtrace.first =~ /(.+?):(\d+(?=:|\z))/ or return ""
- source_file, source_line = $1, $2.to_i
+ # @param exception [Exception, String]
+ # An exception or backtrace.
+ #
+ # @param radius [Integer]
+ # The number of surrounding lines to show.
+ #
+ # @return [String] pretty code snippet
+ def code_snippet(exception, radius=2)
+ radius = radius.to_i
- source = source(source_file)
+ file, lineno = file_and_line(exception)
+
+ return nil if file.empty?
+
+ source = source(file)
- radius = bredth # number of surrounding lines to show
- region = [source_line - radius, 1].max ..
- [source_line + radius, source.length].min
+ region = [lineno - radius, 1].max ..
+ [lineno + radius, source.length].min
# ensure proper alignment by zero-padding line numbers
format = " %2s %0#{region.last.to_s.length}d %s"
pretty = region.map do |n|
- format % [('=>' if n == source_line), n, source[n-1].chomp]
+ format % [('=>' if n == lineno), n, source[n-1].chomp]
end #.unshift "[#{region.inspect}] in #{source_file}"
pretty
end
+ # Return a structure code snippet in an array of lineno=>line
+ # hash elements.
#
+ # @param exception [Exception, String]
+ # An exception or backtrace.
+ #
+ # @param radius [Integer]
+ # The number of surrounding lines to show.
+ #
+ # @return [Hash] structured code snippet
+ def structured_code_snippet(exception, radius=2)
+ radius = radius.to_i
+
+ file, lineno = file_and_line(exception)
+
+ return {} if file.empty?
+
+ source = source(file)
+
+ region = [lineno - radius, 1].max ..
+ [lineno + radius, source.length].min
+
+ region.map do |n|
+ {n => source[n-1].chomp}
+ end
+ end
+
+ # Cache the source code of a file.
+ #
+ # @param file [String] full pathname to file
+ #
+ # @return [String] source code
def source(file)
@source[file] ||= (
File.readlines(file)
)
end
+ # @param exception [Exception,Array,String]
+ # An exception or backtrace.
+ #
+ #--
# TODO: Show more of the file name than just the basename.
+ #++
def file_and_line(exception)
- line = exception.backtrace[0]
- return "" unless line
- i = line.rindex(':in')
- line = i ? line[0...i] : line
- File.basename(line)
+ backtrace = case exception
+ when Exception
+ exception.backtrace.reject{ |bt| bt =~ INTERNALS }.first
+ when Array
+ exception.first
+ else
+ exception
+ end
+
+ backtrace =~ /(.+?):(\d+(?=:|\z))/ or return ""
+
+ file, lineno = $1, $2.to_i
+
+ return file, lineno
+
+ #i = backtrace.rindex(':in')
+ #line = i ? line[0...i] : line
+ #relative_file(line)
end
+ # Same as file_and_line, exception return file path is relative.
+ def file_line(exception)
+ file, lineno = file_and_line(exception)
+ return relative_file(file), lineno
+ end
+
+ # Default trace count. This is the number of backtrace lines that
+ # will be provided on errors and failed assertions, unless otherwise
+ # overridden with ENV['trace'].
+ DEFAULT_TRACE_COUNT = 3
+
+ # Looks at ENV['trace'] to determine how much trace output to provide.
+ # If it is not set, or set to`false` or `off`, then the default trace count
+ # is used. If set to `0`, `true`, 'on' or 'all' then aa complete trace dump
+ # is provided. Otherwise the value is converted to an integer and that many
+ # line of trace is given.
+ #
+ # @return [Integer, nil] trace count
+ def trace_count
+ cnt = ENV['trace']
+ case cnt
+ when nil, 'false', 'off'
+ DEFAULT_TRACE_COUNT
+ when 0, 'all', 'true', 'on'
+ nil
+ else
+ Integer(cnt)
+ end
+ end
+
+ #
+ def relative_file(file)
+ pwd = Dir.pwd
+ idx = (0...pwd.size).find do |i|
+ file[i,1] != pwd[i,1]
+ end
+ file[(idx || 0)..-1]
+ end
end
end
end