Class: RSpecTurbo::Display
- Inherits:
-
Object
- Object
- RSpecTurbo::Display
- Defined in:
- lib/rspec_turbo/display.rb
Overview
Owns every line printed to the terminal: the live per-worker spinner (TTY), the plain CI worker roster, and the final report — failures plus the slowest folders/files (fed by slow_profile.rb in each worker log).
Class Method Summary collapse
- .folder_for(unit) ⇒ Object
-
.folder_labels(batch_units, with_counts: false, max_len: nil) ⇒ Object
Folder label string for a batch’s units, e.g.
Instance Method Summary collapse
-
#initialize(planner) ⇒ Display
constructor
A new instance of Display.
- #print_plan ⇒ Object
- #print_report(results, wall_total, n_workers) ⇒ Object
-
#print_worker_summary(results) ⇒ Object
Consolidated, sorted PASS/FAIL roster — printed once after every worker finishes (CI path) so the per-worker results form one clean block.
- #spinner_line(state, frame) ⇒ Object
Constructor Details
#initialize(planner) ⇒ Display
Returns a new instance of Display.
8 9 10 |
# File 'lib/rspec_turbo/display.rb', line 8 def initialize(planner) @planner = planner end |
Class Method Details
.folder_for(unit) ⇒ Object
23 24 25 26 27 28 29 30 |
# File 'lib/rspec_turbo/display.rb', line 23 def self.folder_for(unit) path = unit.is_a?(Array) ? unit.first.split("[").first.delete_prefix("./spec/") : unit parts = path.split("/") return parts[0] if parts.size <= 1 || parts[1].end_with?("_spec.rb") "#{parts[0]}/#{parts[1]}" end |
.folder_labels(batch_units, with_counts: false, max_len: nil) ⇒ Object
Folder label string for a batch’s units, e.g. “models · requests”.
13 14 15 16 17 18 19 20 21 |
# File 'lib/rspec_turbo/display.rb', line 13 def self.folder_labels(batch_units, with_counts: false, max_len: nil) counts = Hash.new(0) batch_units.each { |unit| counts[folder_for(unit)] += 1 } label = counts.map { |folder, n| with_counts ? "#{folder}(#{n})" : folder }.join(" · ") return label unless max_len label.slice(0, max_len).then { |slice| (slice.length < label.length) ? "#{slice}…" : slice } end |
Instance Method Details
#print_plan ⇒ Object
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/rspec_turbo/display.rb', line 32 def print_plan total = @planner.counts.values.sum puts puts " Found #{@planner.batches.flatten.size} spec files (#{total} examples) → #{@planner.batches.size} batches" puts @planner.batches.each_with_index do |batch, i| label = format("worker/%02d", i + 1) folders = Display.folder_labels(batch) puts format(" %-10s %3d files ~%-4d ex %s", label, batch.size, @planner.example_count(batch), folders) end puts end |
#print_report(results, wall_total, n_workers) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/rspec_turbo/display.rb', line 49 def print_report(results, wall_total, n_workers) sum_total = results.sum { |r| r[:duration] } speedup = sum_total.positive? ? (sum_total.to_f / wall_total).round(2) : 0 total_ex = results.sum { |r| @planner.example_count(r[:units]) } file_data = parse_profiler_data(results.map { |r| Config.log_path(r[:label]) }) failed = results.select { |r| r[:status] == "FAIL" } puts puts Terminal::SEP_THICK puts " RSpec Turbo Report" puts Terminal::SEP_THICK # On a TTY you watch failures scroll by live, so show them first. In CI # the log is read top-to-bottom afterwards, so push failures to the very # end where they sit right above the one-line summary — easy to find. if Config::TTY print_failures(failed) print_slowest(file_data) else print_slowest(file_data) print_failures(failed) end print_summary(failed, total_ex, wall_total, sum_total, speedup, n_workers) end |
#print_worker_summary(results) ⇒ Object
Consolidated, sorted PASS/FAIL roster — printed once after every worker finishes (CI path) so the per-worker results form one clean block.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/rspec_turbo/display.rb', line 77 def print_worker_summary(results) return if results.empty? puts puts Terminal::SEP_THICK puts " Workers" puts Terminal::SEP_THICK puts results.sort_by { |r| r[:label] }.each do |r| icon = (r[:status] == "PASS") ? "✓" : "✗" code = (r[:status] == "PASS") ? "32" : "31" line = format("#{icon} %-10s %-7s %-6s %s", r[:label], Terminal.fmt_duration(r[:duration]), r[:status], Display.folder_labels(r[:units])) puts Terminal.c(code, line) end end |
#spinner_line(state, frame) ⇒ Object
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/rspec_turbo/display.rb', line 96 def spinner_line(state, frame) folders = Display.folder_labels(state[:units], max_len: 55) case state[:status] when :pending " \e[90m○ #{state[:label]}\e[0m" when :running elapsed = state[:started] ? (Process.clock_gettime(Process::CLOCK_MONOTONIC) - state[:started]).round : 0 spin = Terminal::SPINNER_FRAMES[frame % Terminal::SPINNER_FRAMES.size] total = @planner.example_count(state[:units]) " \e[36m#{spin} #{state[:label]}\e[0m ~#{total} ex #{Terminal.fmt_duration(elapsed)} #{folders}" when :done color = (state[:result] == "PASS") ? "\e[32m" : "\e[31m" icon = (state[:result] == "PASS") ? "✓" : "✗" " #{color}#{icon} #{state[:label]} #{Terminal.fmt_duration(state[:duration])} #{state[:result]} #{folders}\e[0m" end end |