rails_code_health 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +30 -0
- data/LICENSE.txt +21 -0
- data/README.md +237 -0
- data/bin/rails-health +5 -0
- data/config/tresholds.json +80 -0
- data/lib/rails_code_health/cli.rb +164 -0
- data/lib/rails_code_health/configuration.rb +89 -0
- data/lib/rails_code_health/file_analyzer.rb +117 -0
- data/lib/rails_code_health/health_calculator.rb +370 -0
- data/lib/rails_code_health/project_detector.rb +74 -0
- data/lib/rails_code_health/rails_analyzer.rb +391 -0
- data/lib/rails_code_health/report_generator.rb +335 -0
- data/lib/rails_code_health/ruby_analyzer.rb +319 -0
- data/lib/rails_code_health/version.rb +3 -0
- data/lib/rails_code_health.rb +46 -0
- metadata +186 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1fcf270392e52c8b6ab9783a9ed2ffaa133825210ff18c0c4ec124ce8b8d2b7f
|
4
|
+
data.tar.gz: 6ddc72d1451b604e7df94e655e22b225647842dcbd0a00baec0618d4e3b1c823
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 416a30e4fd42da4f2f8fe100e349c611c009d5468710974c59d945036145ce1c0df543ca1a8f51f3bf53868cd6ce9472e4be3457dcdaca3d5de12258ef16ed77
|
7
|
+
data.tar.gz: 44e261b45a963e81c5d3ace4be6b360ff8c052ba39dd4b0e3fa56789c145673e3b51d5359ebed08a2f7eb50214044031f0f6185760e3ac06072531be25659769
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [0.1.0] - 2025-06-17
|
11
|
+
|
12
|
+
### Added
|
13
|
+
- Initial release of Rails Code Health analyzer
|
14
|
+
- Ruby code complexity analysis (cyclomatic complexity, method length, class length)
|
15
|
+
- Rails-specific pattern detection for controllers, models, views, helpers, and migrations
|
16
|
+
- Health scoring system (1-10 scale) based on CodeScene research
|
17
|
+
- Command-line interface with console and JSON output options
|
18
|
+
- Configurable thresholds and scoring weights
|
19
|
+
- Actionable recommendations for code improvements
|
20
|
+
- Support for Ruby 3.0+ and Rails 7.0+
|
21
|
+
|
22
|
+
### Features
|
23
|
+
- **Ruby Analysis**: Method/class length, cyclomatic complexity, nesting depth, parameter count
|
24
|
+
- **Rails Analysis**: Controller actions, model validations, view logic detection, migration complexity
|
25
|
+
- **Code Smells**: God classes/methods, long parameter lists, nested conditionals, missing validations
|
26
|
+
- **Reporting**: Detailed console output with health categories and JSON export
|
27
|
+
- **CLI**: `rails-health` command with options for format, output file, and custom configuration
|
28
|
+
|
29
|
+
[Unreleased]: https://github.com/yourusername/rails_code_health/compare/v0.1.0...HEAD
|
30
|
+
[0.1.0]: https://github.com/yourusername/rails_code_health/releases/tag/v0.1.0
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 George Kosmopoulos
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
# Rails Code Health
|
2
|
+
|
3
|
+
A Ruby gem that evaluates the code health of Ruby on Rails applications, inspired by CodeScene's research on technical debt and maintainability.
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
Rails Code Health analyzes your Rails codebase and provides:
|
8
|
+
- **Health scores** (1-10 scale) for each file based on complexity, maintainability, and Rails conventions
|
9
|
+
- **Categorization** of files into Healthy (🟢), Warning (🟡), Alert (🔴), and Critical (⚫) categories
|
10
|
+
- **Actionable recommendations** for improving code quality
|
11
|
+
- **Rails-specific analysis** for controllers, models, views, helpers, and migrations
|
12
|
+
|
13
|
+
## Installation
|
14
|
+
|
15
|
+
Add this gem to your Rails application's Gemfile:
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
gem 'rails_code_health', group: :development
|
19
|
+
```
|
20
|
+
|
21
|
+
Or install it globally:
|
22
|
+
|
23
|
+
```bash
|
24
|
+
gem install rails_code_health
|
25
|
+
```
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
### Command Line Interface
|
30
|
+
|
31
|
+
Run analysis on your current Rails project:
|
32
|
+
|
33
|
+
```bash
|
34
|
+
rails-health
|
35
|
+
```
|
36
|
+
|
37
|
+
Analyze a specific Rails project:
|
38
|
+
|
39
|
+
```bash
|
40
|
+
rails-health /path/to/rails/project
|
41
|
+
```
|
42
|
+
|
43
|
+
Generate JSON output:
|
44
|
+
|
45
|
+
```bash
|
46
|
+
rails-health --format json --output report.json
|
47
|
+
```
|
48
|
+
|
49
|
+
Use custom configuration:
|
50
|
+
|
51
|
+
```bash
|
52
|
+
rails-health --config custom_thresholds.json
|
53
|
+
```
|
54
|
+
|
55
|
+
### Programmatic Usage
|
56
|
+
|
57
|
+
```ruby
|
58
|
+
require 'rails_code_health'
|
59
|
+
|
60
|
+
# Analyze current directory
|
61
|
+
report = RailsCodeHealth.analyze('.')
|
62
|
+
|
63
|
+
# Analyze specific path
|
64
|
+
report = RailsCodeHealth.analyze('/path/to/rails/project')
|
65
|
+
|
66
|
+
# Configure custom thresholds
|
67
|
+
RailsCodeHealth.configure do |config|
|
68
|
+
config.load_thresholds_from_file('custom_config.json')
|
69
|
+
end
|
70
|
+
```
|
71
|
+
|
72
|
+
## What It Analyzes
|
73
|
+
|
74
|
+
### Ruby Code Metrics
|
75
|
+
- **Method length** - Long methods are harder to understand and maintain
|
76
|
+
- **Class length** - Large classes often violate single responsibility principle
|
77
|
+
- **Cyclomatic complexity** - High complexity increases defect risk
|
78
|
+
- **Nesting depth** - Deep nesting reduces readability
|
79
|
+
- **Parameter count** - Too many parameters suggest poor design
|
80
|
+
- **ABC complexity** - Assignments, branches, and conditions complexity
|
81
|
+
|
82
|
+
### Rails-Specific Analysis
|
83
|
+
|
84
|
+
#### Controllers
|
85
|
+
- Action count per controller
|
86
|
+
- Strong parameters usage
|
87
|
+
- Direct model access detection
|
88
|
+
- Response format analysis
|
89
|
+
|
90
|
+
#### Models
|
91
|
+
- Association count
|
92
|
+
- Validation presence
|
93
|
+
- Callback complexity
|
94
|
+
- Fat model detection
|
95
|
+
|
96
|
+
#### Views
|
97
|
+
- Logic in views detection
|
98
|
+
- Inline styles/JavaScript
|
99
|
+
- Template length analysis
|
100
|
+
|
101
|
+
#### Helpers & Migrations
|
102
|
+
- Helper method count
|
103
|
+
- Migration complexity
|
104
|
+
- Data changes in migrations
|
105
|
+
|
106
|
+
### Code Smells Detection
|
107
|
+
- **God Class/Method** - Classes or methods doing too much
|
108
|
+
- **Long Parameter List** - Methods with too many parameters
|
109
|
+
- **Nested Conditionals** - Deep if/else nesting
|
110
|
+
- **Missing Validations** - Models without proper validation
|
111
|
+
- **Logic in Views** - Business logic in presentation layer
|
112
|
+
|
113
|
+
## Health Score Calculation
|
114
|
+
|
115
|
+
Health scores range from 1.0 (critical) to 10.0 (excellent) based on:
|
116
|
+
|
117
|
+
- **File type multipliers** - Different standards for different file types
|
118
|
+
- **Weighted penalties** - More important issues have higher impact
|
119
|
+
- **Rails conventions** - Adherence to Rails best practices
|
120
|
+
- **Code complexity** - Multiple complexity metrics combined
|
121
|
+
|
122
|
+
### Score Categories
|
123
|
+
|
124
|
+
- **🟢 Healthy (8.0-10.0)**: Well-structured, maintainable code
|
125
|
+
- **🟡 Warning (4.0-7.9)**: Some issues, but generally acceptable
|
126
|
+
- **🔴 Alert (1.0-3.9)**: Significant problems requiring attention
|
127
|
+
- **⚫ Critical (<1.0)**: Severe issues, immediate action needed
|
128
|
+
|
129
|
+
## Configuration
|
130
|
+
|
131
|
+
Create a custom `thresholds.json` file:
|
132
|
+
|
133
|
+
```json
|
134
|
+
{
|
135
|
+
"ruby_thresholds": {
|
136
|
+
"method_length": {
|
137
|
+
"green": 15,
|
138
|
+
"yellow": 25,
|
139
|
+
"red": 40
|
140
|
+
},
|
141
|
+
"cyclomatic_complexity": {
|
142
|
+
"green": 6,
|
143
|
+
"yellow": 10,
|
144
|
+
"red": 15
|
145
|
+
}
|
146
|
+
},
|
147
|
+
"rails_specific": {
|
148
|
+
"controller_actions": {
|
149
|
+
"green": 5,
|
150
|
+
"yellow": 10,
|
151
|
+
"red": 20
|
152
|
+
}
|
153
|
+
},
|
154
|
+
"scoring_weights": {
|
155
|
+
"method_length": 0.15,
|
156
|
+
"cyclomatic_complexity": 0.20,
|
157
|
+
"rails_conventions": 0.15
|
158
|
+
}
|
159
|
+
}
|
160
|
+
```
|
161
|
+
|
162
|
+
## Sample Output
|
163
|
+
|
164
|
+
```
|
165
|
+
Rails Code Health Report
|
166
|
+
==================================================
|
167
|
+
|
168
|
+
📊 Overall Health Summary:
|
169
|
+
Total files analyzed: 45
|
170
|
+
🟢 Healthy files (8.0-10.0): 32 (71.1%)
|
171
|
+
🟡 Warning files (4.0-7.9): 10 (22.2%)
|
172
|
+
🔴 Alert files (1.0-3.9): 3 (6.7%)
|
173
|
+
|
174
|
+
📈 Average Health Score: 7.8/10.0
|
175
|
+
|
176
|
+
📂 Breakdown by File Type:
|
177
|
+
Controller: 8 files, avg score: 7.2, 5 healthy
|
178
|
+
Model: 12 files, avg score: 8.4, 10 healthy
|
179
|
+
View: 15 files, avg score: 8.1, 12 healthy
|
180
|
+
|
181
|
+
🚨 Files Needing Most Attention:
|
182
|
+
1. 🔴 app/controllers/admin/reports_controller.rb
|
183
|
+
Score: 3.2/10.0 | Type: controller | Size: 15.2 KB
|
184
|
+
Top issues:
|
185
|
+
• Break down the generate_report method (156 lines) into smaller methods
|
186
|
+
• Consider splitting this controller - it has 18 actions
|
187
|
+
|
188
|
+
💡 Key Recommendations:
|
189
|
+
1. Reduce method and class lengths
|
190
|
+
2. Lower cyclomatic complexity
|
191
|
+
3. Follow Rails conventions
|
192
|
+
4. Extract business logic from controllers
|
193
|
+
```
|
194
|
+
|
195
|
+
## Research Foundation
|
196
|
+
|
197
|
+
This gem is inspired by the peer-reviewed research paper ["Code Red: The Business Impact of Code Quality"](https://arxiv.org/pdf/2203.04374) by Adam Tornhill and Markus Borg, which found that:
|
198
|
+
|
199
|
+
- Low quality code contains **15x more defects** than high quality code
|
200
|
+
- Resolving issues in low quality code takes **124% more time**
|
201
|
+
- Issue resolutions involve **9x longer maximum cycle times**
|
202
|
+
|
203
|
+
## Development
|
204
|
+
|
205
|
+
After checking out the repo, run:
|
206
|
+
|
207
|
+
```bash
|
208
|
+
bundle install
|
209
|
+
```
|
210
|
+
|
211
|
+
Run tests:
|
212
|
+
|
213
|
+
```bash
|
214
|
+
bundle exec rspec
|
215
|
+
```
|
216
|
+
|
217
|
+
Run the gem locally:
|
218
|
+
|
219
|
+
```bash
|
220
|
+
bundle exec bin/rails-health /path/to/rails/project
|
221
|
+
```
|
222
|
+
|
223
|
+
## Contributing
|
224
|
+
|
225
|
+
1. Fork it
|
226
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
227
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
228
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
229
|
+
5. Create a new Pull Request
|
230
|
+
|
231
|
+
## License
|
232
|
+
|
233
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
234
|
+
|
235
|
+
## Credits
|
236
|
+
|
237
|
+
Inspired by [CodeScene](https://codescene.com/) and the research on technical debt's business impact. This gem implements similar concepts specifically for Ruby on Rails applications.
|
data/bin/rails-health
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
{
|
2
|
+
"ruby_thresholds": {
|
3
|
+
"method_length": {
|
4
|
+
"green": 15,
|
5
|
+
"yellow": 25,
|
6
|
+
"red": 40
|
7
|
+
},
|
8
|
+
"class_length": {
|
9
|
+
"green": 100,
|
10
|
+
"yellow": 200,
|
11
|
+
"red": 400
|
12
|
+
},
|
13
|
+
"cyclomatic_complexity": {
|
14
|
+
"green": 6,
|
15
|
+
"yellow": 10,
|
16
|
+
"red": 15
|
17
|
+
},
|
18
|
+
"abc_complexity": {
|
19
|
+
"green": 15,
|
20
|
+
"yellow": 25,
|
21
|
+
"red": 40
|
22
|
+
},
|
23
|
+
"nesting_depth": {
|
24
|
+
"green": 3,
|
25
|
+
"yellow": 5,
|
26
|
+
"red": 8
|
27
|
+
},
|
28
|
+
"parameter_count": {
|
29
|
+
"green": 3,
|
30
|
+
"yellow": 5,
|
31
|
+
"red": 8
|
32
|
+
}
|
33
|
+
},
|
34
|
+
"rails_specific": {
|
35
|
+
"controller_actions": {
|
36
|
+
"green": 5,
|
37
|
+
"yellow": 10,
|
38
|
+
"red": 20
|
39
|
+
},
|
40
|
+
"controller_length": {
|
41
|
+
"green": 50,
|
42
|
+
"yellow": 100,
|
43
|
+
"red": 200
|
44
|
+
},
|
45
|
+
"model_public_methods": {
|
46
|
+
"green": 7,
|
47
|
+
"yellow": 12,
|
48
|
+
"red": 20
|
49
|
+
},
|
50
|
+
"view_length": {
|
51
|
+
"green": 30,
|
52
|
+
"yellow": 50,
|
53
|
+
"red": 100
|
54
|
+
},
|
55
|
+
"migration_complexity": {
|
56
|
+
"green": 10,
|
57
|
+
"yellow": 20,
|
58
|
+
"red": 40
|
59
|
+
}
|
60
|
+
},
|
61
|
+
"file_type_multipliers": {
|
62
|
+
"controllers": 1.2,
|
63
|
+
"models": 1.0,
|
64
|
+
"views": 0.8,
|
65
|
+
"helpers": 0.9,
|
66
|
+
"lib": 1.1,
|
67
|
+
"specs": 0.7,
|
68
|
+
"migrations": 0.6
|
69
|
+
},
|
70
|
+
"scoring_weights": {
|
71
|
+
"method_length": 0.15,
|
72
|
+
"class_length": 0.12,
|
73
|
+
"cyclomatic_complexity": 0.20,
|
74
|
+
"nesting_depth": 0.18,
|
75
|
+
"parameter_count": 0.10,
|
76
|
+
"duplication": 0.25,
|
77
|
+
"rails_conventions": 0.15,
|
78
|
+
"code_smells": 0.25
|
79
|
+
}
|
80
|
+
}
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module RailsCodeHealth
|
4
|
+
class CLI
|
5
|
+
def self.start(args)
|
6
|
+
new(args).run
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(args)
|
10
|
+
@args = args
|
11
|
+
@options = {
|
12
|
+
path: '.',
|
13
|
+
format: :console,
|
14
|
+
output: nil,
|
15
|
+
config: nil,
|
16
|
+
verbose: false
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
parse_options
|
22
|
+
|
23
|
+
begin
|
24
|
+
# Load custom config if provided
|
25
|
+
if @options[:config]
|
26
|
+
RailsCodeHealth.configuration.load_thresholds_from_file(@options[:config])
|
27
|
+
end
|
28
|
+
|
29
|
+
# Set output format
|
30
|
+
RailsCodeHealth.configuration.output_format = @options[:format]
|
31
|
+
|
32
|
+
puts "🔍 Analyzing Rails project at: #{@options[:path]}" if @options[:verbose]
|
33
|
+
puts "📊 Using format: #{@options[:format]}" if @options[:verbose]
|
34
|
+
|
35
|
+
# Run the analysis
|
36
|
+
report = analyze_project
|
37
|
+
|
38
|
+
# Output the report
|
39
|
+
output_report(report)
|
40
|
+
|
41
|
+
puts "\n✅ Analysis complete!" if @options[:verbose]
|
42
|
+
|
43
|
+
rescue RailsCodeHealth::Error => e
|
44
|
+
puts "❌ Error: #{e.message}"
|
45
|
+
exit 1
|
46
|
+
rescue => e
|
47
|
+
puts "💥 Unexpected error: #{e.message}"
|
48
|
+
puts e.backtrace.join("\n") if @options[:verbose]
|
49
|
+
exit 1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def parse_options
|
56
|
+
OptionParser.new do |opts|
|
57
|
+
opts.banner = "Usage: rails-health [options] [path]"
|
58
|
+
opts.separator ""
|
59
|
+
opts.separator "Analyze the code health of a Ruby on Rails application"
|
60
|
+
opts.separator ""
|
61
|
+
opts.separator "Options:"
|
62
|
+
|
63
|
+
opts.on("-f", "--format FORMAT", [:console, :json],
|
64
|
+
"Output format (console, json)") do |format|
|
65
|
+
@options[:format] = format
|
66
|
+
end
|
67
|
+
|
68
|
+
opts.on("-o", "--output FILE",
|
69
|
+
"Output file (default: stdout)") do |file|
|
70
|
+
@options[:output] = file
|
71
|
+
end
|
72
|
+
|
73
|
+
opts.on("-c", "--config FILE",
|
74
|
+
"Custom configuration file") do |file|
|
75
|
+
@options[:config] = file
|
76
|
+
end
|
77
|
+
|
78
|
+
opts.on("-v", "--verbose",
|
79
|
+
"Verbose output") do
|
80
|
+
@options[:verbose] = true
|
81
|
+
end
|
82
|
+
|
83
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
84
|
+
puts opts
|
85
|
+
exit
|
86
|
+
end
|
87
|
+
|
88
|
+
opts.on_tail("--version", "Show version") do
|
89
|
+
puts "Rails Code Health v#{RailsCodeHealth::VERSION}"
|
90
|
+
exit
|
91
|
+
end
|
92
|
+
end.parse!(@args)
|
93
|
+
|
94
|
+
# Use remaining argument as path if provided
|
95
|
+
@options[:path] = @args.first if @args.any?
|
96
|
+
end
|
97
|
+
|
98
|
+
def analyze_project
|
99
|
+
project_path = Pathname.new(@options[:path]).expand_path
|
100
|
+
|
101
|
+
unless ProjectDetector.rails_project?(project_path)
|
102
|
+
raise Error, "Not a Rails project directory: #{project_path}"
|
103
|
+
end
|
104
|
+
|
105
|
+
puts "📁 Found Rails project!" if @options[:verbose]
|
106
|
+
|
107
|
+
analyzer = FileAnalyzer.new(project_path)
|
108
|
+
results = analyzer.analyze_all
|
109
|
+
|
110
|
+
puts "📝 Analyzed #{results.count} files" if @options[:verbose]
|
111
|
+
|
112
|
+
health_calculator = HealthCalculator.new
|
113
|
+
scored_results = health_calculator.calculate_scores(results)
|
114
|
+
|
115
|
+
puts "🧮 Calculated health scores" if @options[:verbose]
|
116
|
+
|
117
|
+
scored_results
|
118
|
+
end
|
119
|
+
|
120
|
+
def output_report(results)
|
121
|
+
case @options[:format]
|
122
|
+
when :console
|
123
|
+
output_console_report(results)
|
124
|
+
when :json
|
125
|
+
output_json_report(results)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def output_console_report(results)
|
130
|
+
report_generator = ReportGenerator.new(results)
|
131
|
+
|
132
|
+
if @options[:output]
|
133
|
+
File.write(@options[:output], capture_console_output(report_generator))
|
134
|
+
puts "📄 Report saved to: #{@options[:output]}"
|
135
|
+
else
|
136
|
+
report_generator.generate
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
def output_json_report(results)
|
141
|
+
report_generator = ReportGenerator.new(results)
|
142
|
+
json_report = report_generator.generate_json_report
|
143
|
+
|
144
|
+
if @options[:output]
|
145
|
+
File.write(@options[:output], json_report)
|
146
|
+
puts "📄 JSON report saved to: #{@options[:output]}"
|
147
|
+
else
|
148
|
+
puts json_report
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def capture_console_output(report_generator)
|
153
|
+
original_stdout = $stdout
|
154
|
+
$stdout = StringIO.new
|
155
|
+
|
156
|
+
report_generator.generate
|
157
|
+
|
158
|
+
output = $stdout.string
|
159
|
+
$stdout = original_stdout
|
160
|
+
|
161
|
+
output
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module RailsCodeHealth
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :thresholds, :excluded_paths, :output_format
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@thresholds = load_default_thresholds
|
7
|
+
@excluded_paths = default_excluded_paths
|
8
|
+
@output_format = :console
|
9
|
+
end
|
10
|
+
|
11
|
+
def thresholds
|
12
|
+
@thresholds ||= load_default_thresholds
|
13
|
+
end
|
14
|
+
|
15
|
+
def load_thresholds_from_file(file_path)
|
16
|
+
if File.exist?(file_path)
|
17
|
+
@thresholds = JSON.parse(File.read(file_path))
|
18
|
+
else
|
19
|
+
raise Error, "Thresholds file not found: #{file_path}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def load_default_thresholds
|
26
|
+
config_file = File.join(File.dirname(__FILE__), '..', '..', 'config', 'thresholds.json')
|
27
|
+
if File.exist?(config_file)
|
28
|
+
JSON.parse(File.read(config_file))
|
29
|
+
else
|
30
|
+
# Fallback to hardcoded defaults if config file is missing
|
31
|
+
default_hardcoded_thresholds
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def default_excluded_paths
|
36
|
+
[
|
37
|
+
'vendor/**/*',
|
38
|
+
'tmp/**/*',
|
39
|
+
'log/**/*',
|
40
|
+
'node_modules/**/*',
|
41
|
+
'coverage/**/*',
|
42
|
+
'.git/**/*',
|
43
|
+
'public/assets/**/*',
|
44
|
+
'db/schema.rb',
|
45
|
+
'spec/**/*',
|
46
|
+
'test/**/*'
|
47
|
+
]
|
48
|
+
end
|
49
|
+
|
50
|
+
def default_hardcoded_thresholds
|
51
|
+
{
|
52
|
+
'ruby_thresholds' => {
|
53
|
+
'method_length' => { 'green' => 15, 'yellow' => 25, 'red' => 40 },
|
54
|
+
'class_length' => { 'green' => 100, 'yellow' => 200, 'red' => 400 },
|
55
|
+
'cyclomatic_complexity' => { 'green' => 6, 'yellow' => 10, 'red' => 15 },
|
56
|
+
'abc_complexity' => { 'green' => 15, 'yellow' => 25, 'red' => 40 },
|
57
|
+
'nesting_depth' => { 'green' => 3, 'yellow' => 5, 'red' => 8 },
|
58
|
+
'parameter_count' => { 'green' => 3, 'yellow' => 5, 'red' => 8 }
|
59
|
+
},
|
60
|
+
'rails_specific' => {
|
61
|
+
'controller_actions' => { 'green' => 5, 'yellow' => 10, 'red' => 20 },
|
62
|
+
'controller_length' => { 'green' => 50, 'yellow' => 100, 'red' => 200 },
|
63
|
+
'model_public_methods' => { 'green' => 7, 'yellow' => 12, 'red' => 20 },
|
64
|
+
'view_length' => { 'green' => 30, 'yellow' => 50, 'red' => 100 },
|
65
|
+
'migration_complexity' => { 'green' => 10, 'yellow' => 20, 'red' => 40 }
|
66
|
+
},
|
67
|
+
'file_type_multipliers' => {
|
68
|
+
'controllers' => 1.2,
|
69
|
+
'models' => 1.0,
|
70
|
+
'views' => 0.8,
|
71
|
+
'helpers' => 0.9,
|
72
|
+
'lib' => 1.1,
|
73
|
+
'specs' => 0.7,
|
74
|
+
'migrations' => 0.6
|
75
|
+
},
|
76
|
+
'scoring_weights' => {
|
77
|
+
'method_length' => 0.15,
|
78
|
+
'class_length' => 0.12,
|
79
|
+
'cyclomatic_complexity' => 0.20,
|
80
|
+
'nesting_depth' => 0.18,
|
81
|
+
'parameter_count' => 0.10,
|
82
|
+
'duplication' => 0.25,
|
83
|
+
'rails_conventions' => 0.15,
|
84
|
+
'code_smells' => 0.25
|
85
|
+
}
|
86
|
+
}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|