Skip to content

Add simplecov:disable / simplecov:enable directive comments#1179

Merged
sferik merged 1 commit intomainfrom
add-disable-enable-directives
May 5, 2026
Merged

Add simplecov:disable / simplecov:enable directive comments#1179
sferik merged 1 commit intomainfrom
add-disable-enable-directives

Conversation

@sferik
Copy link
Copy Markdown
Collaborator

@sferik sferik commented May 4, 2026

Alternative to #1068 implementing the directive shape proposed at #1068 (comment):

# simplecov:disable line
# simplecov:disable method, branch
# simplecov:disable                                        <- shorthand for all three categories
# simplecov:disable line legacy adapter, scheduled to die  <- trailing text is a free-form reason
# simplecov:enable
raise "absurd" # simplecov:disable                         <- inline, single line, no enable needed

Categories are tracked independently. # simplecov:disable line skips those lines from line coverage but still reports any branches and methods that overlap them. # simplecov:disable method flags the method directly without depending on its lines being skipped, which is why Method gains a skipped! setter and an overlaps_with? helper alongside the existing inferred-from-lines skipped?.

Anything trailing the directive is treated as a free-form reason and discarded. The trade-off is that an unrecognised category name silently falls into the reason bucket and the bare form takes effect, so # simplecov:disable cyclomatic ends up over-disabling instead of being rejected. That's a deliberate fail-mode: over-disabling shows up loud in the report (a whole file with no covered lines), whereas silently disabling nothing wouldn't, so typos are easier to catch.

Comment extraction goes through Ripper.lex. That keeps the parser honest about Ruby syntax: a directive marker sitting inside a double-quoted string, a single-quoted string, an interpolated string, or a heredoc body is not a directive, and we no longer pretend otherwise. The # prefix # simplecov:disable line case (whole line is one comment, but the directive isn't at the start of it) is treated as inline, since the directive's column doesn't sit at the start of the comment text.

The new directives subsume what # :nocov: did, so it's deprecated (as is the the configurable SimpleCov.nocov_token). The toggle continues to work but each file that uses it now emits a one-time deprecation warning to stderr at load time pointing the user at the # simplecov:disable / # simplecov:enable replacement. The plan is to remove :nocov: entirely in a future release.

The shape of the implementation:

  • SimpleCov::Directive exposes Directive.disabled_ranges(src_lines) which walks the source via Ripper.lex, parses each comment token against a single regex, and returns { line: [Range, ...], branch: [...], method: [...] }. The Directive value object itself is mostly an internal accumulator for disabled_ranges; users of the class don't need to reach for it.
  • LinesClassifier#classify consults the line ranges so that SimulateCoverage (used for tracked-but-unloaded files) marks disabled lines as NOT_RELEVANT, matching the behaviour :nocov: already had for that path. Both this file and SourceFile require_relative "directive" directly so that requiring either one in isolation doesn't blow up.
  • SourceFile lazily memoises per-category ranges and consumes them in the three process_skipped_* methods. Branches and methods both use overlap-with-range checks, so a directive that sits inside a method body or a branch body still skips the enclosing construct. process_skipped_branches also consults branch.report_line so an inline directive on the condition line of a multi-line if (where the arm body's source range starts on a different line) still skips the arm.
  • SourceFile#warn_no_cov_deprecation is the deprecation hook. It dedupes per-filename via a class-level Set (SimpleCov::SourceFile.nocov_warned) so noisy projects only see one line per file rather than one per occurrence.

@sferik sferik force-pushed the add-disable-enable-directives branch from f0888f5 to 3463d22 Compare May 5, 2026 02:45
@sferik sferik requested a review from Copilot May 5, 2026 02:46

This comment was marked as resolved.

@sferik sferik force-pushed the add-disable-enable-directives branch 7 times, most recently from ed2b2c1 to 389df23 Compare May 5, 2026 16:05
Mirror RuboCop's directive style for selectively skipping coverage of
specific lines, branches, or methods:

  # simplecov:disable line             (block; closes at matching :enable)
  # simplecov:disable method, branch
  # simplecov:disable                  (no args = all three categories)
  # simplecov:disable line some reason (any trailing text becomes a reason)
  # simplecov:enable
  raise "absurd" # simplecov:disable   (inline; just this line)

Block directives sit on their own line (possibly indented) and open a
region until the matching `# simplecov:enable` for the same category;
unclosed disables run to end of file. Inline directives trail real code
and only affect that one line.

Categories are independently tracked: `# simplecov:disable line` skips
those lines from line coverage but leaves any branches and methods on
those lines reported normally. The bare form is a shorthand for all
three.

Trailing text after the directive is treated as a free-form reason and
discarded — no `--` separator or other marker is required. As a
consequence, an unrecognised category name silently falls into the
reason bucket and the bare form takes effect (a deliberate over-disable
so typos surface in the report rather than silently disabling nothing).

Comment extraction goes through `Ripper.lex`, so directive markers that
appear inside string literals or heredocs are correctly ignored.

SourceFile collects the per-category disabled ranges from Directive,
then applies them in process_skipped_lines, process_skipped_branches,
and a new process_skipped_methods. Method gains a direct skipped! flag
and overlaps_with? helper paralleling Branch's API.

Deprecate `# :nocov:` (and the configurable `SimpleCov.nocov_token`) in
favor of the new directives. Each file that still uses `# :nocov:`
emits a one-time deprecation warning to stderr at load time pointing
at the recommended `# simplecov:disable` / `# simplecov:enable`
replacement. The toggle continues to work; it will be removed in a
future release.
@sferik sferik force-pushed the add-disable-enable-directives branch from 389df23 to bb060d0 Compare May 5, 2026 16:24
@sferik sferik merged commit bfa6142 into main May 5, 2026
24 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants