144 lines
2.7 KiB
Ruby
144 lines
2.7 KiB
Ruby
module Mutant
|
|
class Reporter
|
|
# Reporter that reports in human readable format
|
|
class CLI < self
|
|
include Concord.new(:output)
|
|
|
|
NL = "\n".freeze
|
|
CLEAR_PREV_LINE = "\e[1A\e[2K".freeze
|
|
|
|
# Output abstraction to decouple tty? from buffer
|
|
class Output
|
|
include Concord.new(:tty, :buffer)
|
|
|
|
# Test if output is a tty
|
|
#
|
|
# @return [Boolean]
|
|
#
|
|
# @api private
|
|
#
|
|
def tty?
|
|
@tty
|
|
end
|
|
|
|
[:puts, :write].each do |name|
|
|
define_method(name) do |*args, &block|
|
|
buffer.public_send(name, *args, &block)
|
|
end
|
|
end
|
|
|
|
end # Output
|
|
|
|
# Rate per second progress report fires
|
|
OUTPUT_RATE = 1.0 / 20
|
|
|
|
# Initialize object
|
|
#
|
|
# @return [undefined]
|
|
#
|
|
# @api private
|
|
#
|
|
def initialize(*)
|
|
super
|
|
@last_frame = nil
|
|
@last_length = 0
|
|
@tty = output.respond_to?(:tty?) && output.tty?
|
|
end
|
|
|
|
# Report progress object
|
|
#
|
|
# @param [Runner::Collector] collector
|
|
#
|
|
# @return [self]
|
|
#
|
|
# @api private
|
|
#
|
|
def progress(collector)
|
|
throttle do
|
|
swap(frame(Printer::Collector, collector))
|
|
end
|
|
|
|
self
|
|
end
|
|
|
|
# Report warning
|
|
#
|
|
# @param [String] message
|
|
#
|
|
# @return [self]
|
|
#
|
|
# @api private
|
|
#
|
|
def warn(message)
|
|
output.puts(message)
|
|
self
|
|
end
|
|
|
|
# Report env
|
|
#
|
|
# @param [Result::Env] env
|
|
#
|
|
# @return [self]
|
|
#
|
|
# @api private
|
|
#
|
|
def report(env)
|
|
swap(frame(Printer::EnvResult, env))
|
|
self
|
|
end
|
|
|
|
private
|
|
|
|
# Compute progress frame
|
|
#
|
|
# @return [String]
|
|
#
|
|
# @api private
|
|
#
|
|
def frame(reporter, object)
|
|
buffer = StringIO.new
|
|
buffer.write(clear_command) if @tty
|
|
reporter.run(Output.new(@tty, buffer), object)
|
|
buffer.rewind
|
|
buffer.read
|
|
end
|
|
|
|
# Swap output frame
|
|
#
|
|
# @param [String] frame
|
|
#
|
|
# @return [undefined]
|
|
#
|
|
# @api private
|
|
#
|
|
def swap(frame)
|
|
output.write(frame)
|
|
@last_length = frame.split(NL).length
|
|
end
|
|
|
|
# Call block throttled
|
|
#
|
|
# @return [undefined]
|
|
#
|
|
# @api private
|
|
#
|
|
def throttle
|
|
now = Time.now
|
|
return if @last_frame && (now - @last_frame) < OUTPUT_RATE
|
|
yield
|
|
@last_frame = now
|
|
end
|
|
|
|
# Return clear command for last frame length
|
|
#
|
|
# @return [String]
|
|
#
|
|
# @api private
|
|
#
|
|
def clear_command
|
|
CLEAR_PREV_LINE * @last_length
|
|
end
|
|
|
|
end # CLI
|
|
end # Reporter
|
|
end # Mutant
|