RSpec Let Analyzer
A Ruby gem that analyzes RSpec test files to identify opportunities for refactoring let
and let!
declarations to use test-prof's let_it_be
helper for improved test performance.
Background
The let_it_be
helper from the test-prof gem creates test data once per example group instead of once per example, which can significantly speed up test suites. This tool helps you identify which let
declarations are good candidates for conversion to let_it_be
.
Installation
Add this line to your application's Gemfile:
gem 'rspec-let-analyzer'
And then execute:
bundle install
Or install it yourself as:
gem install rspec-let-analyzer
Usage
Run the analyzer on your RSpec test suite:
# Analyze specs in current directory
rspec-let-analyzer
# Analyze specs in a different directory
rspec-let-analyzer /path/to/project
rspec-let-analyzer --directory /path/to/project
This will scan all files matching spec/**/*_spec.rb
in the specified directory (or current directory if not specified) and display a table showing:
- Total: Combined score of all metrics (Root + it blocks + Nest columns + Redef + Before Creates)
-
Root: Number of
let
/let!
declarations at the root level of each describe block - it blocks: Number of test examples in each file
-
Nest 1, Nest 2, etc.: Number of
let
declarations at different nesting depths -
Redef: Number of
let
redefinitions (where a nested context redefines alet
from a parent scope) -
Bef Cr: Number of
create
calls inbefore
blocks
Command Line Options
# Show top 20 files instead of default 10
rspec-let-analyzer -n 20
# Output in different formats
rspec-let-analyzer --format ascii # Default: ASCII table
rspec-let-analyzer --format json # JSON for further processing
rspec-let-analyzer --format html # HTML report with Bootstrap styling
rspec-let-analyzer --format llm # LLM-friendly JSON for AI-assisted refactoring
# Disable progress indicator
rspec-let-analyzer --no-progress
# Track nesting depth up to 5 levels (default: 3)
rspec-let-analyzer --nesting 5
# Disable nesting tracking entirely
rspec-let-analyzer --no-nesting
# Sort by different fields
rspec-let-analyzer --sort total # Sort by total score (default)
rspec-let-analyzer --sort root # Sort by root lets
rspec-let-analyzer --sort it # Sort by number of it blocks
rspec-let-analyzer --sort redef # Sort by number of redefinitions
rspec-let-analyzer --sort before # Sort by before creates
# Track FactoryBot usage statistics
rspec-let-analyzer --factories
# Analyze a different directory
rspec-let-analyzer --directory /path/to/project
rspec-let-analyzer /path/to/project # Positional argument also works
# Display runtime performance metrics
rspec-let-analyzer --runtime-metrics
# Use a different adapter (default: prism)
rspec-let-analyzer --adapter parser # Requires 'gem install parser'
# Generate reports and save to file
rspec-let-analyzer --format html --output report.html
rspec-let-analyzer --format llm --output refactor-guide.json
# Show help
rspec-let-analyzer --help
LLM-Assisted Refactoring
The --format llm
option generates AI-friendly output designed for use with Large Language Models (like Claude, ChatGPT, etc.) to assist with refactoring:
# Generate refactoring guide
rspec-let-analyzer --format llm --output refactor-guide.json -n 10
# Then provide this to your AI assistant with a prompt like:
# "Review the top 5 files in this report and suggest let_it_be refactorings"
The LLM format includes:
- Prioritized list of refactoring candidates with scores
- Step-by-step refactoring workflow
- Decision criteria (when to keep/ask/revert changes)
- Guidelines for safe conversions and common fixes
- Context about factory usage patterns
Understanding the Output
High Total score indicates files with the most opportunities for optimization, combining all metrics for a comprehensive view of complexity.
High numbers in the Root column indicate files with many let
declarations at the top level. These are prime candidates for let_it_be
if:
- The data doesn't change between tests
- The tests don't modify the created objects
High numbers in Redef column indicate files where let
declarations are frequently overridden in nested contexts. These may be more complex to refactor since the redefinitions might be intentional for test isolation.
High numbers in Bef Cr column indicate files with many create
calls in before
blocks, which can be converted to let_it_be
or before(:all)
blocks.
Factory tracking shows which FactoryBot factories are used most frequently across your test suite, helping identify optimization opportunities.
Example Output
+------------------------------------------------------------+----------+----------+----------+----------+----------+----------+----------+----------+
| File | Total | Root | it blocks| Nest 1 | Nest 2 | Nest 3+| Redef | Bef Cr |
+------------------------------------------------------------+----------+----------+----------+----------+----------+----------+----------+----------+
| spec/models/user_spec.rb | 50 | 12 | 25 | 8 | 3 | 0 | 2 | 0 |
| spec/controllers/posts_controller_spec.rb | 38 | 10 | 18 | 6 | 2 | 1 | 1 | 0 |
+------------------------------------------------------------+----------+----------+----------+----------+----------+----------+----------+----------+
| TOTAL (all 50 files) | 600 | 150 | 300 | | | | 15 | 0 |
+------------------------------------------------------------+----------+----------+----------+----------+----------+----------+----------+----------+
Development
After checking out the repo, run:
bundle install
To run the test suite:
bundle exec rspec
To install this gem onto your local machine:
bundle exec rake install
How It Works
The gem uses Ruby's Prism parser to analyze RSpec files and identify:
-
let
andlet!
declarations at various nesting levels - Context nesting depth for each declaration
- Cases where
let
declarations are redefined in nested scopes - FactoryBot usage patterns (when enabled)
This information helps you prioritize which test files to refactor for better performance using let_it_be
.
Contributing
Bug reports and pull requests are welcome on GitHub.
License
The gem is available as open source under the terms of the MIT License.