Class: SpecGuard::RSpec::Linter
- Inherits:
-
Object
- Object
- SpecGuard::RSpec::Linter
- Defined in:
- lib/specguard/rspec/linter.rb
Overview
Applies the schema to the Findings discovery produced, and says which ones the run must fail on.
This is the join between the two halves of the linter: discovery decides what an annotation is, the schema decides whether it is valid, and Result is the single shape the reporter and the exit code are both derived from — so "what was printed" and "what we exited with" cannot drift apart.
What counts as a failure
Three things reach the same verdict from different directions:
* the payload could not be captured off the line at all
(`Finding::KIND_EXTRACTION`) — a typo'd annotation;
* it was captured but is not JSON even after normalization
(`Finding::KIND_PARSE`);
* it parsed but violates the schema.
All three are "an annotation is malformed", which the contract fixes at
exit 1. A missing annotation is not among them — "lint, don't
require" (SPGD-12 §1): a file with no @intent: at all is clean.
The one case that is arguably not an annotation problem
Finding::KIND_READ — a spec file that could not be opened or is not
valid UTF-8 — is also reported as a failure, and therefore also exits 1.
That is a deliberate choice, not an oversight: validate-intent
classifies it separately (its own read kind) and still reports it as
FAIL with exit 1.
The CLASSIFICATION and the EXIT CODE are what match, and both are asserted rather than described, in spec/specguard/rspec/validator_backend_spec.rb — which runs this linter and the binary's recorded report over the same inputs and compares them. Each read-failure shape below has its own two-sided block there, so the shared half and the surviving difference are both pinned: converging either one fails that file.
The MESSAGE TEXT does not match on any of the three read-failure shapes,
and an earlier version of this comment claimed it did — it quoted a
FAIL bad_spec.rb — could not read file: ... line as if the two tools
emitted the same bytes. They do not:
* a file that is not valid UTF-8 — the binary says `input is not
well-formed UTF-8 (PROTOCOL.md §1.1 requires it)`;
`Scanner.scan_text` says `invalid UTF-8 byte sequence`. Both name the
condition rather than an offset, and both refuse the file, which is
what PROTOCOL.md §1.1 requires; neither wording is specified.
* a file that does not exist — the binary reports it on *stderr* as
`error: no file(s) match '<path>'` (its arguments are glob patterns);
`Scanner.scan_file` reports it on stdout as a read failure of that
path (its arguments are paths).
* a path that exists and is not a regular file — the binary's glob
filters it away, so it answers exactly as it does for a name matching
nothing: a `no-match` finding under `--json`. `no file at this path`
is not the binary's wording but this gem's, minted in
`ValidatorBackend#no_match_result`, because Go's "no file(s) match
<pattern>" is a statement about a glob pattern this CLI does not
have. `Scanner.scan_file` opened it and has an errno, so it reports
`Is a directory @ io_fread - <path>`. The distinction between a
missing path and a non-regular one is Ruby's alone; the binary does
not draw it and the backend cannot recover it.
The line the contract actually draws is the linter is broken (2) versus the input it was pointed at is bad (1). An unopenable file named on the command line is the second. The kind is carried through rather than flattened into prose so this stays a visible decision that a later ticket can reverse in one place.
Defined Under Namespace
Classes: Result
Instance Method Summary collapse
-
#check(findings) ⇒ Array<Result>
In the order the findings were discovered.
- #check_one(finding) ⇒ Result
-
#initialize(schema) ⇒ Linter
constructor
A new instance of Linter.
Constructor Details
#initialize(schema) ⇒ Linter
Returns a new instance of Linter.
115 116 117 |
# File 'lib/specguard/rspec/linter.rb', line 115 def initialize(schema) @schema = schema end |
Instance Method Details
#check(findings) ⇒ Array<Result>
Returns in the order the findings were discovered.
121 122 123 |
# File 'lib/specguard/rspec/linter.rb', line 121 def check(findings) findings.map { |finding| check_one(finding) } end |
#check_one(finding) ⇒ Result
127 128 129 130 131 132 133 134 135 136 |
# File 'lib/specguard/rspec/linter.rb', line 127 def check_one(finding) unless finding.extracted? return Result.new(file: finding.file, line: finding.line, kind: finding.kind, problem: finding.problem) end reasons = @schema.violations(finding.intent) Result.new(file: finding.file, line: finding.line, reasons: reasons, kind: reasons.empty? ? nil : Finding::KIND_SCHEMA) end |