Module: Moult::Formatters::HealthTable

Defined in:
lib/moult/formatters/health_table.rb

Overview

Human-readable health summary: a headline composite, the per-component breakdown (including the skipped/errored ones), and the least-healthy files. Renders from the same HealthReport as the JSON formatter so the two cannot disagree; ordering already happened in Health.

The heading is deliberate: this is a graded signal, never a verdict.

Constant Summary collapse

DEFAULT_FILE_LIMIT =
20
DASH =
""

Class Method Summary collapse

Class Method Details

.component_note(component) ⇒ Object



52
53
54
55
# File 'lib/moult/formatters/health_table.rb', line 52

def component_note(component)
  return component.diagnostic.to_s unless component.present
  component.reasons.first&.detail.to_s
end

.component_row(component) ⇒ Object



43
44
45
46
47
48
49
50
# File 'lib/moult/formatters/health_table.rb', line 43

def component_row(component)
  [
    component.name,
    component.present ? format("%.2f", component.score) : DASH,
    format("%.2f", component.weight),
    component_note(component)
  ]
end

.components_section(report) ⇒ Object



36
37
38
39
40
41
# File 'lib/moult/formatters/health_table.rb', line 36

def components_section(report)
  headers = %w[COMPONENT SCORE WEIGHT NOTE]
  rows = report.components.map { |c| component_row(c) }
  right = [1, 2] # SCORE, WEIGHT
  ["Components:", TextTable.render(headers, rows, right_aligned: right)].join("\n")
end

.file_row(file) ⇒ Object



70
71
72
73
74
75
76
77
# File 'lib/moult/formatters/health_table.rb', line 70

def file_row(file)
  [
    format("%.2f", file.score),
    file.grade,
    file.path,
    file.components.keys.join(",")
  ]
end

.files_section(report, file_limit) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/moult/formatters/health_table.rb', line 57

def files_section(report, file_limit)
  files = report.files
  return "Files: none with a health signal." if files.empty?

  shown = file_limit ? files.first(file_limit) : files
  headers = %w[SCORE GRADE FILE COMPONENTS]
  rows = shown.map { |f| file_row(f) }
  extra = files.size - shown.size
  suffix = extra.positive? ? " (top #{shown.size} of #{files.size})" : ""
  title = "Least-healthy files#{suffix}:"
  [title, TextTable.render(headers, rows, right_aligned: [0])].join("\n")
end

.heading(report) ⇒ Object



25
26
27
28
29
30
31
32
33
34
# File 'lib/moult/formatters/health_table.rb', line 25

def heading(report)
  if report.score.nil?
    "Codebase health: n/a — no analysis produced a signal"
  else
    present = report.components.count(&:present)
    total = report.components.size
    "Codebase health: #{report.grade} (#{format("%.2f", report.score)}) " \
      "— a graded signal, not a verdict  [#{present}/#{total} components]"
  end
end

.render(report, file_limit: DEFAULT_FILE_LIMIT) ⇒ String

Parameters:

  • report (HealthReport)
  • file_limit (Integer, nil) (defaults to: DEFAULT_FILE_LIMIT)

    how many worst files to show (nil = all)

Returns:

  • (String)


20
21
22
23
# File 'lib/moult/formatters/health_table.rb', line 20

def render(report, file_limit: DEFAULT_FILE_LIMIT)
  [heading(report), "", components_section(report), "", files_section(report, file_limit)]
    .join("\n").rstrip
end