Class.new(parent_class) do
ESC = "\e["
NND = "#{ESC}0m"
PASS = '='
PASS_ARY = ['-', '_']
FAIL = '*'
ERROR = '!'
PENDING = '+'
include rspec_module
attr_reader :current, :example_results, :color_index, :pending_count,
:failure_count, :example_count
def tick(mark = PASS)
@example_results << mark
@current = (@current > @example_count) ? @example_count : @current + 1
dump_progress
end
def nyan_cat
if @failure_count.to_i > 0 || @pending_count.to_i > 0
ascii_cat('o')[@color_index%2].join("\n")
elsif (@current == @example_count)
ascii_cat('-')[@color_index%2].join("\n")
else
ascii_cat('^')[@color_index%2].join("\n")
end
end
def dump_progress
padding = @example_count.to_s.length * 2 + 2
line = nyan_trail.split("\n").each_with_index.inject([]) do |result, (trail, index)|
value = "#{scoreboard[index]}/#{@example_count}:"
result << format("%s %s", value, trail)
end.join("\n")
output.print line + eol
end
def eol
return "\n" if @current == @example_count
length = (nyan_cat.split("\n").length - 1)
length > 0 ? format("\e[1A" * length + "\r") : "\r"
end
def current_width
padding = @example_count.to_s.length * 2 + 6
cat_length = nyan_cat.split("\n").group_by(&:size).max.first
padding + @current + cat_length
end
def terminal_width
@terminal_width ||= `stty size`.split.map { |x| x.to_i }.reverse.first - 1
end
def scoreboard
@pending_examples ||= []
@failed_examples ||= []
padding = @example_count.to_s.length
[ @current.to_s.rjust(padding),
green((@current - @pending_examples.size - @failed_examples.size).to_s.rjust(padding)),
yellow(@pending_count.to_s.rjust(padding)),
red(@failure_count.to_s.rjust(padding)) ]
end
def nyan_trail
marks = @example_results.map{ |mark| highlight(mark) }
marks.shift(current_width - terminal_width) if current_width >= terminal_width
nyan_cat_lines = nyan_cat.split("\n").each_with_index.map do |line, index|
format("%s#{line}", marks.join)
end.join("\n")
end
def ascii_cat(o = '^')
[[ "_,------, ",
"_| /\\_/\\ ",
"~|_( #{o} .#{o}) ",
" \"\" \"\" "
],
[ "_,------, ",
"_| /\\_/\\",
"^|__( #{o} .#{o}) ",
" \"\" \"\" "
]]
end
def rainbowify(string)
c = colors[@color_index % colors.size]
@color_index += 1
"#{ESC}38;5;#{c}m#{string}#{NND}"
end
def colors
@colors ||= (0...(6 * 7)).map do |n|
pi_3 = Math::PI / 3
n *= 1.0 / 6
r = (3 * Math.sin(n ) + 3).to_i
g = (3 * Math.sin(n + 2 * pi_3) + 3).to_i
b = (3 * Math.sin(n + 4 * pi_3) + 3).to_i
36 * r + 6 * g + b + 16
end
end
def highlight(mark = PASS)
case mark
when PASS; rainbowify PASS_ARY[@color_index%2]
when FAIL; "\e[31m#{mark}\e[0m"
when ERROR; "\e[33m#{mark}\e[0m"
when PENDING; "\e[33m#{mark}\e[0m"
else mark
end
end
end