Created
May 31, 2015 17:42
-
-
Save georgyangelov/d7dbd5f1388e4f54ea7d to your computer and use it in GitHub Desktop.
RSpec nested formatter
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
RSpec::Support.require_rspec_core 'formatters/base_text_formatter' | |
class RspecFormatter < RSpec::Core::Formatters::BaseTextFormatter | |
RSpec::Core::Formatters.register self, :start, | |
:stop, | |
:example_group_started, | |
:example_group_finished, | |
:example_passed, | |
:example_failed, | |
:example_pending | |
def initialize(output) | |
super | |
@out = OutputManager.new(output) | |
@root = OutputGroup.new | |
@current = @root | |
@current_visible = @current | |
end | |
def start(_notification) | |
@out.new_line | |
@out.line 'Examples:' | |
@out.new_line | |
end | |
def stop(_notification) | |
@out.new_line | |
end | |
def example_group_started(notification) | |
new_group = @current.push_group(notification.group) | |
if @current.expanded | |
@out.indent | |
@out.new_line | |
@out.line new_group.heading | |
@current_visible = new_group | |
end | |
@current = new_group | |
end | |
def example_group_finished(_notification) | |
if @current == @current_visible | |
@out.line @current.heading(true) unless @current.expanded | |
@out.dedent | |
@current_visible = @current_visible.parent | |
end | |
@current = @current.parent | |
end | |
def example_passed(passed) | |
new_example = @current.push_example(passed.example, :success) | |
if @current.expanded | |
@out.indent | |
@out.new_line | |
@out.line new_example.heading | |
@out.dedent | |
else | |
@out.line @current_visible.heading | |
end | |
end | |
def example_failed(failed) | |
expand_current unless @current.expanded | |
new_example = @current.push_example(failed.example, :failure) | |
@out.indent | |
@out.new_line | |
@out.line new_example.heading | |
@out.dedent | |
end | |
def example_pending(pending) | |
expand_current unless @current.expanded | |
new_example = @current.push_example(pending.example, :pending) | |
@out.indent | |
@out.new_line | |
@out.line new_example.heading | |
@out.dedent | |
end | |
private | |
def expand_current | |
@current.expand_to_top | |
@current_visible.print @out, new_line: false | |
@current_visible = @current | |
@out.current_indent = @current_visible.indent | |
end | |
end | |
class OutputGroup | |
attr_reader :parent, :group, :children, :expanded | |
def initialize(parent = nil, group = nil) | |
@parent = parent | |
@group = group | |
@children = [] | |
@expanded = !parent | |
end | |
def expand | |
@expanded = true | |
parent.expand | |
end | |
def heading(done = false) | |
if !@expanded && done | |
counter = RSpec::Core::Formatters::ConsoleCodes.wrap("[#{example_count}]", :success) | |
elsif !@expanded | |
counter = "[#{example_count}]" | |
end | |
"#{@group.description} #{counter}" | |
end | |
def indent | |
return 0 unless @parent | |
1 + @parent.indent | |
end | |
def print(out, new_line: true) | |
out.new_line if new_line | |
out.line heading(true) | |
if @expanded | |
out.indent | |
children.each { |child| child.print(out) } | |
out.dedent | |
end | |
end | |
def example_count | |
@children.map(&:example_count).reduce(:+) || 0 | |
end | |
def push_group(group) | |
output_group = OutputGroup.new(self, group) | |
@children.push output_group | |
output_group | |
end | |
def push_example(example, status) | |
output_example = OutputExample.new(self, example, status) | |
@children.push output_example | |
output_example | |
end | |
def expand_to_top | |
@expanded = true | |
return self if @parent.expanded | |
@parent.expand_to_top | |
end | |
end | |
class OutputExample | |
attr_reader :parent, :example, :status | |
def initialize(parent, example, status) | |
@parent = parent | |
@example = example | |
@status = status | |
end | |
def heading | |
case @status | |
when :success then passed_output | |
when :pending then pending_output | |
when :failure then failure_output | |
end | |
end | |
def print(out) | |
out.new_line | |
out.line heading | |
end | |
def example_count | |
1 | |
end | |
private | |
def passed_output | |
RSpec::Core::Formatters::ConsoleCodes.wrap(@example.description.strip, :success) | |
end | |
def pending_output | |
RSpec::Core::Formatters::ConsoleCodes.wrap("#{@example.description.strip} [PENDING]", :pending) | |
end | |
def failure_output | |
RSpec::Core::Formatters::ConsoleCodes.wrap("#{@example.description.strip} [FAILED]", :failure) | |
end | |
end | |
class OutputManager | |
attr_accessor :current_indent | |
def initialize(output) | |
@output = output | |
@current_indent = 0 | |
end | |
def line(line) | |
@output.print "\r#{' ' * 70}\r#{indent_block(line)}" | |
flush | |
end | |
def append(string) | |
@output.print string | |
flush | |
end | |
def indent | |
@current_indent += 1 | |
end | |
def dedent | |
@current_indent -= 1 | |
end | |
def new_line(text = '') | |
@output.puts text | |
end | |
private | |
def flush | |
$stdout.flush | |
end | |
def indent_block(string) | |
string.lines.map { |line| "#{' ' * @current_indent}#{line}" }.join('') | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment