A static analysis tool that scores Ruby classes and modules against SOLID principles using AST analysis.
- SOLID Principles Analysis: Scores each class/module on all five SOLID principles (SRP, OCP, LSP, ISP, DIP)
- Multiple Output Formats: Text (table), JSON, and HTML report output
- Git Diff Mode: Analyze only changed files to prevent score regression
- Configurable Thresholds: Set minimum scores for CI quality gates
- Customizable Weights: Adjust the importance of each principle in the total score
- RuboCop Integration: Use as RuboCop cops for seamless linting workflow
Add this line to your application's Gemfile:
gem 'solid_score'And then execute:
bundle installOr install it yourself as:
gem install solid_score# Analyze current directory
solid-score .
# Analyze specific directory
solid-score app/models
# Output as JSON
solid-score app/ --format json
# Generate HTML report
solid-score app/ --format html > report.html
# Analyze only changed files (git diff)
solid-score . --diff origin/main
# Use configuration file
solid-score . --config .solid-score.ymlUsage: solid-score [path] [options]
Options:
--format FORMAT Output format: text (default), json, html
--config FILE Path to configuration file
--min-score SCORE Minimum total score (exit 1 if below)
--min-srp SCORE Minimum SRP score
--min-ocp SCORE Minimum OCP score
--min-lsp SCORE Minimum LSP score
--min-isp SCORE Minimum ISP score
--min-dip SCORE Minimum DIP score
--diff REF Analyze only files changed since REF (git ref)
--max-decrease SCORE Maximum allowed score decrease per class
--exclude PATTERN Exclude patterns (comma-separated)
--version Show version
-h, --help Show help
solid-score v0.1.0
Analyzed 5 class(es)
Class SRP OCP LSP ISP DIP Total
-------------------------------------------------------------------------------
OrderService 100.0 100.0 100.0 100.0 100.0 100.0
UserRepository 80.0 90.0 100.0 95.0 85.0 88.0
PaymentProcessor 60.0 70.0 100.0 80.0 50.0 68.5
ShapeCalculator 60.0 35.0 100.0 100.0 100.0 78.2
GodClass 30.0 100.0 100.0 65.0 100.0 72.0
-------------------------------------------------------------------------------
Average 66.0 79.0 100.0 88.0 87.0 81.3
{
"version": "0.1.0",
"classes": [
{
"class_name": "OrderService",
"file_path": "app/services/order_service.rb",
"srp": 100,
"ocp": 100.0,
"lsp": 100,
"isp": 100,
"dip": 100.0,
"total": 100.0,
"confidence": {
"srp": "high",
"ocp": "low",
"lsp": "low_medium",
"isp": "medium_high",
"dip": "high"
}
}
],
"summary": {
"total_classes": 1,
"average_score": 100.0
}
}Create a .solid-score.yml file in your project root:
# Target paths to analyze
paths:
- app/models
- app/services
- lib
# Patterns to exclude (glob format)
exclude:
- spec/**
- test/**
- tmp/**
- vendor/**
# Preset (loads predefined configuration)
# preset: rails
# Output format
format: text # or json or html
# Score thresholds (CI will fail if below)
thresholds:
total: 70
srp: 60
ocp: 50
lsp: 50
isp: 50
dip: 60
# Weight of each principle in total score (must sum to 1.0)
weights:
srp: 0.30 # 30%
ocp: 0.15 # 15%
lsp: 0.10 # 10%
isp: 0.20 # 20%
dip: 0.25 # 25%
# Git diff analysis settings
diff:
max_decrease: 5 # Max allowed score decrease per class
new_class_min: 70 # Minimum score for new classesMetric: LCOM4 (Lack of Cohesion of Methods 4)
Measures class cohesion using graph connectivity analysis. A class with high cohesion (methods working with shared instance variables) scores higher.
- Score 100: All methods are connected (single responsibility)
- Score 0: Methods are completely disconnected (multiple responsibilities)
- Confidence: High
Metric: Conditional complexity + type checking patterns
Detects patterns that suggest a class needs modification for extension:
-
if/elsechains with type checking (is_a?,kind_of?,instance_of?) -
case/whenstatements with multiple branches -
Conditional density in methods
-
Confidence: Low-Medium (heuristic-based)
Metric: Inheritance contract compliance
Detects potential violations:
-
Method signature changes (different parameters than parent)
-
Missing
supercalls in overridden methods -
Return type inconsistencies
-
Confidence: Low-Medium (requires runtime analysis for full accuracy)
Metric: Interface bloat detection
Measures:
-
Number of public methods
-
Method parameter count
-
Unused method dependencies
-
Confidence: Medium-High
Metric: Concrete dependency ratio
Calculates the ratio of concrete class instantiations to total dependencies:
-
Direct
ClassName.newcalls penalize the score -
Standard library classes (Array, Hash, String, etc.) are whitelisted
-
Dependency injection patterns score higher
-
Confidence: High
For Rails projects, use the built-in preset to get sensible defaults:
# .solid-score.yml
preset: rails
thresholds:
total: 60The Rails preset configures:
- Paths:
app/models,app/controllers,app/services,app/jobs,app/mailers,lib, etc. - Excludes:
spec/**,test/**,vendor/**,db/**,tmp/** - Weights: DIP weighted higher (0.30), SRP slightly lower (0.25)
- DIP Whitelist: Rails, Logger, Net::HTTP, ActionMailer, ActiveJob, etc.
Explicit YAML values override the preset.
name: SOLID Score Check
on:
pull_request:
branches: [main]
jobs:
solid-score:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: harakeishi/solid-score@main
with:
min-score: "70"
pr-comment: "true"The action supports these inputs:
| Input | Default | Description |
|---|---|---|
ruby-version |
3.2 |
Ruby version |
min-score |
0 |
Minimum total score threshold |
format |
text |
Output format (text/json/html) |
paths |
. |
Paths to analyze |
config |
.solid-score.yml |
Config file path |
pr-comment |
false |
Post score report as PR comment |
diff-ref |
origin/main |
Base ref for diff comparison |
Outputs: score-json, passing, average-score.
jobs:
solid-score:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: ruby/setup-ruby@v1
with:
ruby-version: '3.3'
bundler-cache: true
- name: Install solid-score
run: gem install solid_score
- name: Check SOLID scores
run: solid-score app/ lib/ --min-score 70
- name: Check score regression (diff mode)
run: solid-score . --diff origin/main --max-decrease 5Add rubocop-solid_score to your .rubocop.yml to run SOLID score checks as part of your existing RuboCop workflow:
# .rubocop.yml
require:
- rubocop-solid_score| Cop | Default | Description |
|---|---|---|
SolidScore/TotalScore |
Enabled (70) | Checks weighted total score |
SolidScore/SingleResponsibility |
Disabled (60) | Checks SRP score |
SolidScore/OpenClosed |
Disabled (50) | Checks OCP score |
SolidScore/LiskovSubstitution |
Disabled (60) | Checks LSP score |
SolidScore/InterfaceSegregation |
Disabled (70) | Checks ISP score |
SolidScore/DependencyInversion |
Disabled (65) | Checks DIP score |
# .rubocop.yml
SolidScore/TotalScore:
Enabled: true
MinScore: 70
Weights:
srp: 0.30
ocp: 0.15
lsp: 0.10
isp: 0.20
dip: 0.25
DipWhitelist:
- Rails
- Logger
# Enable individual principle checks
SolidScore/SingleResponsibility:
Enabled: true
MinScore: 60
SolidScore/DependencyInversion:
Enabled: true
MinScore: 65| Code | Description |
|---|---|
| 0 | All checks passed |
| 1 | Score below threshold or regression detected |
| 2 | Invalid arguments or configuration error |
After checking out the repo, run:
# Install dependencies
bundle install
# Run tests
bundle exec rspec
# Run tests with coverage
COVERAGE=true bundle exec rspec
# Run linter
bundle exec rubocop
# Run the tool locally
bundle exec solid-score spec/fixtures- Static Analysis Only: Cannot detect runtime behavior or duck typing patterns
- OCP/LSP Accuracy: These principles are difficult to measure statically; scores are heuristic-based
- Module Support: Module analysis is less accurate than class analysis
- Metaprogramming: Heavy use of
define_method,method_missing, etc. may affect accuracy
- Ruby >= 3.2.0
Bug reports and pull requests are welcome on GitHub at https://github.com/harakeishi/solid-score.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
The gem is available as open source under the terms of the MIT License.
- SOLID Principles - Wikipedia
- LCOM4 Metric - Lack of Cohesion of Methods
- Robert C. Martin - Clean Architecture