rubocop-rspec-unused-let
A RuboCop extension that detects
unreferenced RSpec let definitions.
It adds a single cop, RSpec/UnusedLet, which flags let (and optionally
let!) definitions whose name is never referenced within their scope. The cop
is deliberately conservative around shared_examples so that it avoids false
positives that a naive implementation would produce.
Installation
Add the gem to your Gemfile:
gem "rubocop-rspec-unused-let", require: false
This gem builds on rubocop-rspec, so make sure that is available too.
Usage
Enable both plugins in your .rubocop.yml:
plugins:
- rubocop-rspec
- rubocop-rspec-unused-let
What it detects
# bad
RSpec.describe Foo do
let(:used) { 1 }
let(:unused) { 2 } # never referenced
it { expect(used).to eq(1) }
end
# good
RSpec.describe Foo do
let(:used) { 1 }
it { expect(used).to eq(1) }
end
A let is considered used when its name appears as a bare method call
anywhere in its scope — inside examples, hooks (before/after/around),
subject, other let blocks, and nested example groups. Dynamic references
such as send(:name) / public_send("name") are also treated as usages.
How it handles shared_examples
Because RuboCop analyzes one file at a time, a let can be consumed by a shared
example block defined in another file. To avoid false positives, the cop stays
silent whenever it cannot see every possible reference:
letdefinitions inside ashared_examples/shared_contextblock are ignored (their consumers are the including groups, which may be external).- When an example group's subtree contains a shared example inclusion
(
it_behaves_like,include_examples,include_context, ...), theletdefinitions visible at that inclusion point are ignored. Sibling subtrees that do not include shared examples are still checked.
RSpec.describe Foo do
let(:a) { 1 } # skipped: visible at the inclusion below
context "with shared" do
let(:b) { 2 } # skipped: same
it_behaves_like "something"
end
context "other" do
let(:c) { 3 } # checked: the shared block cannot see `c`
it { expect(c).to eq(3) }
end
end
Configuration
RSpec/UnusedLet:
# Whether to also check `let!`. On by default. Since `let!` is sometimes used
# purely for its side effects (e.g. `let!(:user) { create(:user) }`), set this
# to `false` to opt out.
CheckLetBang: true
Known limitations
- Analysis is limited to a single file; references reachable only across files (e.g. through external shared examples) are intentionally not flagged.
letdefinitions in an override chain (redefined in a nested group, or overriding an outer definition) are skipped, since the outer one may be reached throughsuper.
Development
After checking out the repo, run bin/setup to install dependencies. Then run
rake spec to run the tests and rake rubocop to lint the gem. rake runs
both.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/tk0miya/rubocop-rspec-unused-let.
License
The gem is available as open source under the terms of the MIT License.