Module: Moult::Coverage::Resolver

Defined in:
lib/moult/coverage/resolver.rb

Overview

The line->symbol resolver: turns line-keyed coverage into a per-symbol runtime classification. This is the one genuinely novel component, so its rules are precise and fixture-pinned — drift is a bug, exactly like the ABC metric.

For a method definition spanning span.start_line..span.end_line in a tracked file, it inspects the body lines and returns:

  • :hot — at least one executable body line was executed
  • :cold — the file is tracked, body has executable lines, none ran
  • :untracked — no usable signal (see below)

The defining rule is that the def signature line is EXCLUDED: stdlib Coverage counts it at definition (load) time, not per call, so counting it would mark every loaded method hot. Only the body reflects real calls.

Class Method Summary collapse

Class Method Details

.body_values(lines, span) ⇒ Array<Integer>

Coverage values for the executable (non-nil) body lines, excluding the def signature line at span.start_line. The end line and blanks are nil and so fall out naturally.

Returns:

  • (Array<Integer>)


48
49
50
51
52
53
# File 'lib/moult/coverage/resolver.rb', line 48

def body_values(lines, span)
  first = span.start_line + 1
  last = span.end_line
  return [] if first > last
  (first..last).filter_map { |line| lines[line - 1] }
end

.classify(dataset, path:, span:, kind:) ⇒ Symbol

Returns :hot, :cold, or :untracked.

Parameters:

  • dataset (Dataset)
  • path (String)

    root-relative path (a symbol_id component)

  • span (Span)

    1-based definition span

  • kind (Symbol)

    :method or :constant

Returns:

  • (Symbol)

    :hot, :cold, or :untracked



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/moult/coverage/resolver.rb', line 28

def classify(dataset, path:, span:, kind:)
  # A constant's only line is its assignment, executed at load regardless
  # of whether the constant is ever read — so it carries no runtime signal.
  return :untracked unless kind == :method
  lines = dataset.entries[path]
  return :untracked unless lines

  executable = body_values(lines, span)
  # No executable body line to judge: one-line methods (def f = x), empty
  # methods, abstract stubs. Their only line is the def line (load-time
  # coverage), so they are genuinely unclassifiable in :lines mode.
  return :untracked if executable.empty?

  executable.any?(&:positive?) ? :hot : :cold
end