code_qualia 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/README.md +254 -0
- data/bin/code-qualia +12 -0
- data/bin/update_smoke_tests +107 -0
- data/lib/code_qualia/cli.rb +217 -0
- data/lib/code_qualia/complexity_analyzer.rb +115 -0
- data/lib/code_qualia/config.rb +83 -0
- data/lib/code_qualia/config_helper.rb +122 -0
- data/lib/code_qualia/config_installer.rb +170 -0
- data/lib/code_qualia/coverage_analyzer.rb +82 -0
- data/lib/code_qualia/git_analyzer.rb +69 -0
- data/lib/code_qualia/logger.rb +47 -0
- data/lib/code_qualia/pattern_expander.rb +118 -0
- data/lib/code_qualia/score_calculator.rb +143 -0
- data/lib/code_qualia.rb +68 -0
- metadata +91 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 24203fd574ea29e81bf9ff29ce73cdacc4a9e88b4cdfe1a67b240dde959c825e
|
4
|
+
data.tar.gz: 5fba6f527637a62f966289d360e830c216b3645e09c7ba6f7cc7ae85f52ec9db
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9cf345920c0150b7b9fff683d292f2b6e3b464a83142b8001763af49692df9cb58a2d2b8c1d44ed63860d6651247c2191e3c05d8153b23dec29a7c71c063158d
|
7
|
+
data.tar.gz: 65b17c91e1e0c8c360a9a0a52709dd3c75311b412002d0478498ee8c17a3defedc9337d3c980c8c5dbc33a335b1cd77541c0d08d41d7a7398ca2193ec139d55f
|
data/README.md
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
# Code Qualia
|
2
|
+
|
3
|
+
**A tool for communicating developer intuition and code quality perception to AI through configurable parameters**
|
4
|
+
|
5
|
+
Code Qualia helps developers express their subjective understanding and feelings about code quality to AI systems. By combining quantitative metrics (coverage, complexity, git activity) with configurable weights that reflect your development priorities and intuitions, it creates a "quality fingerprint" that AI can understand and use for better code analysis and recommendations.
|
6
|
+
|
7
|
+
## 🎯 Key Features
|
8
|
+
|
9
|
+
- **Developer Intuition Translation**: Convert your subjective code quality perceptions into quantifiable parameters
|
10
|
+
- **Configurable Quality Weights**: Express what matters most to you - complexity, coverage, change frequency, or directory importance
|
11
|
+
- **AI-Ready Output**: Generate structured data that AI systems can use to understand your code priorities
|
12
|
+
- **Multiple Data Sources**: Integrates with SimpleCov, RuboCop, and Git to capture comprehensive code context
|
13
|
+
- **Flexible Interface**: CLI tool with JSON, CSV, and human-readable output formats
|
14
|
+
|
15
|
+
## 🚀 Installation
|
16
|
+
|
17
|
+
Add this line to your application's Gemfile:
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
gem 'code_qualia', group: [:development, :test]
|
21
|
+
```
|
22
|
+
|
23
|
+
And then execute:
|
24
|
+
```bash
|
25
|
+
bundle install
|
26
|
+
```
|
27
|
+
|
28
|
+
## 📋 Usage
|
29
|
+
|
30
|
+
### Setup
|
31
|
+
|
32
|
+
First, generate a configuration file for your project:
|
33
|
+
|
34
|
+
```bash
|
35
|
+
# Auto-detect project type and generate qualia.yml
|
36
|
+
bundle exec code-qualia install
|
37
|
+
```
|
38
|
+
|
39
|
+
This command automatically detects whether you're working with a Rails application or a Ruby gem and generates an appropriate configuration file.
|
40
|
+
|
41
|
+
### Basic Analysis
|
42
|
+
|
43
|
+
```bash
|
44
|
+
# Analyze top 3 methods (default)
|
45
|
+
bundle exec code-qualia generate
|
46
|
+
|
47
|
+
# Analyze top 10 methods
|
48
|
+
bundle exec code-qualia generate --top-n 10
|
49
|
+
|
50
|
+
# Use custom config file
|
51
|
+
bundle exec code-qualia generate --config custom_qualia.yml
|
52
|
+
|
53
|
+
# Output in different formats
|
54
|
+
bundle exec code-qualia generate --format json
|
55
|
+
bundle exec code-qualia generate --format csv
|
56
|
+
bundle exec code-qualia generate --format table
|
57
|
+
```
|
58
|
+
|
59
|
+
### Sample Output
|
60
|
+
|
61
|
+
```
|
62
|
+
📊 Top 3 methods requiring test coverage:
|
63
|
+
|
64
|
+
1. app/models/user.rb:21
|
65
|
+
Method: can_access_feature?
|
66
|
+
Priority Score: 18.6
|
67
|
+
Coverage: 50.0%
|
68
|
+
Complexity: 7
|
69
|
+
Git Commits: 0
|
70
|
+
|
71
|
+
2. app/models/user.rb:35
|
72
|
+
Method: calculate_discount
|
73
|
+
Priority Score: 11.4
|
74
|
+
Coverage: 50.0%
|
75
|
+
Complexity: 4
|
76
|
+
Git Commits: 0
|
77
|
+
|
78
|
+
3. packs/users/app/models/users/user_profile.rb:5
|
79
|
+
Method: display_name
|
80
|
+
Priority Score: 7.8
|
81
|
+
Coverage: 0.0%
|
82
|
+
Complexity: 5
|
83
|
+
Git Commits: 0
|
84
|
+
```
|
85
|
+
|
86
|
+
## ⚙️ Configuration
|
87
|
+
|
88
|
+
Create a `qualia.yml` file in your project root:
|
89
|
+
|
90
|
+
```yaml
|
91
|
+
# Quality indicators (code issues that need fixing)
|
92
|
+
quality_weights:
|
93
|
+
test_coverage: 1.5 # Weight for test coverage (lower coverage = higher priority)
|
94
|
+
cyclomatic_complexity: 1.0 # Weight for cyclomatic complexity (higher complexity = higher priority)
|
95
|
+
|
96
|
+
# Importance indicators (how critical the code is)
|
97
|
+
importance_weights:
|
98
|
+
change_frequency: 0.8 # Weight for git change frequency (more changes = higher importance)
|
99
|
+
architectural_importance: 1.2 # Weight for architectural importance (critical paths = higher importance)
|
100
|
+
|
101
|
+
# Path-based architectural importance weights
|
102
|
+
architectural_weights:
|
103
|
+
- path: "app/models/**/*.rb"
|
104
|
+
weight: 2.0 # Models are critical for business logic
|
105
|
+
- path: "app/services/**/*.rb"
|
106
|
+
weight: 1.8 # Services contain complex business logic
|
107
|
+
- path: "app/controllers/**/*.rb"
|
108
|
+
weight: 1.5 # Controllers handle user interactions
|
109
|
+
- path: "lib/**/*.rb"
|
110
|
+
weight: 1.0 # Library code standard weight
|
111
|
+
|
112
|
+
# Files to exclude from analysis
|
113
|
+
exclude:
|
114
|
+
- "app/helpers/**/*"
|
115
|
+
- "config/**/*"
|
116
|
+
- "db/**/*"
|
117
|
+
|
118
|
+
# Days of git history to analyze
|
119
|
+
git_history_days: 90
|
120
|
+
```
|
121
|
+
|
122
|
+
## 🔧 Requirements
|
123
|
+
|
124
|
+
- **SimpleCov**: For test coverage data
|
125
|
+
- **RuboCop**: For code complexity analysis
|
126
|
+
- **Git**: For file change history
|
127
|
+
|
128
|
+
|
129
|
+
## 🏗️ How It Works
|
130
|
+
|
131
|
+
Code Qualia calculates a priority score for each method using a multiplicative approach that separates quality issues from code importance:
|
132
|
+
|
133
|
+
**FinalScore = QualityScore × ImportanceScore**
|
134
|
+
|
135
|
+
Where:
|
136
|
+
- **QualityScore** = `(W_test_coverage × TestCoverageFactor) + (W_cyclomatic_complexity × ComplexityFactor)`
|
137
|
+
- **ImportanceScore** = `(W_change_frequency × ChangeFrequencyFactor) + (W_architectural_importance × ArchitecturalFactor)`
|
138
|
+
|
139
|
+
**Quality Indicators** (code issues that need fixing):
|
140
|
+
- **TestCoverageFactor**: `(1.0 - coverage_rate)` - lower coverage = higher quality risk
|
141
|
+
- **ComplexityFactor**: Cyclomatic complexity from RuboCop - higher complexity = higher quality risk
|
142
|
+
|
143
|
+
**Importance Indicators** (how critical the code is):
|
144
|
+
- **ChangeFrequencyFactor**: Number of commits in specified time period - more changes = higher importance
|
145
|
+
- **ArchitecturalFactor**: Weight based on file location (configurable) - critical paths = higher importance
|
146
|
+
|
147
|
+
This approach ensures that both quality issues AND importance must be present for a method to rank highly, providing more logical prioritization.
|
148
|
+
|
149
|
+
|
150
|
+
## 🧪 Development
|
151
|
+
|
152
|
+
### Running Tests
|
153
|
+
|
154
|
+
```bash
|
155
|
+
# Run all tests
|
156
|
+
bundle exec rspec
|
157
|
+
|
158
|
+
# Run integration tests only
|
159
|
+
bundle exec rspec spec/integration/
|
160
|
+
```
|
161
|
+
|
162
|
+
### Smoke Testing
|
163
|
+
|
164
|
+
Code Qualia includes a comprehensive smoke test suite that validates functionality against a sample Rails application in the `smoke/sample_app` directory.
|
165
|
+
|
166
|
+
## 📊 Output Formats
|
167
|
+
|
168
|
+
Code Qualia supports multiple output formats for flexibility:
|
169
|
+
|
170
|
+
### Human-readable (default)
|
171
|
+
```
|
172
|
+
📊 Top 3 methods requiring test coverage:
|
173
|
+
|
174
|
+
1. app/models/user.rb:21
|
175
|
+
Method: can_access_feature?
|
176
|
+
Priority Score: 10.15
|
177
|
+
Coverage: 50.0%
|
178
|
+
Complexity: 7
|
179
|
+
Git Commits: 0
|
180
|
+
|
181
|
+
2. packs/users/app/models/users/user_profile.rb:5
|
182
|
+
Method: display_name
|
183
|
+
Priority Score: 7.7
|
184
|
+
Coverage: 0.0%
|
185
|
+
Complexity: 5
|
186
|
+
Git Commits: 0
|
187
|
+
```
|
188
|
+
|
189
|
+
### JSON Format
|
190
|
+
```json
|
191
|
+
[
|
192
|
+
{
|
193
|
+
"file_path": "app/models/user.rb",
|
194
|
+
"class_name": "User",
|
195
|
+
"method_name": "can_access_feature?",
|
196
|
+
"line_number": 21,
|
197
|
+
"score": 10.15,
|
198
|
+
"details": {
|
199
|
+
"coverage": 0.5,
|
200
|
+
"complexity": 7,
|
201
|
+
"git_commits": 0
|
202
|
+
}
|
203
|
+
},
|
204
|
+
{
|
205
|
+
"file_path": "packs/users/app/models/users/user_profile.rb",
|
206
|
+
"class_name": "UserProfile",
|
207
|
+
"method_name": "display_name",
|
208
|
+
"line_number": 5,
|
209
|
+
"score": 7.7,
|
210
|
+
"details": {
|
211
|
+
"coverage": 0.0,
|
212
|
+
"complexity": 5,
|
213
|
+
"git_commits": 0
|
214
|
+
}
|
215
|
+
}
|
216
|
+
]
|
217
|
+
```
|
218
|
+
|
219
|
+
### CSV Format
|
220
|
+
```csv
|
221
|
+
file_path,method_name,line_number,score,coverage,complexity,git_commits
|
222
|
+
app/models/user.rb,can_access_feature?,21,10.15,50.0,7,0
|
223
|
+
packs/users/app/models/users/user_profile.rb,display_name,5,7.7,0.0,5,0
|
224
|
+
```
|
225
|
+
|
226
|
+
### Table Format
|
227
|
+
```
|
228
|
+
+----------------------------------------------+---------------------+------+-------+----------+------------+----------+
|
229
|
+
| File | Method | Line | Score | Coverage | Complexity | Commits |
|
230
|
+
+----------------------------------------------+---------------------+------+-------+----------+------------+----------+
|
231
|
+
| app/models/user.rb | can_access_feature? | 21 | 10.15 | 50.0% | 7 | 0 |
|
232
|
+
| packs/users/app/models/users/user_profile.rb | display_name | 5 | 7.70 | 0.0% | 5 | 0 |
|
233
|
+
+----------------------------------------------+---------------------+------+-------+----------+------------+----------+
|
234
|
+
```
|
235
|
+
|
236
|
+
All formats can be redirected to files using standard Unix redirection:
|
237
|
+
```bash
|
238
|
+
bundle exec code-qualia generate --format json > analysis.json
|
239
|
+
bundle exec code-qualia generate --format csv > analysis.csv
|
240
|
+
```
|
241
|
+
|
242
|
+
## 🤝 Contributing
|
243
|
+
|
244
|
+
1. Fork the repository
|
245
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
246
|
+
3. Make your changes
|
247
|
+
4. Run the test suite (`bundle exec rspec`)
|
248
|
+
5. Commit your changes (`git commit -am 'Add amazing feature'`)
|
249
|
+
6. Push to the branch (`git push origin feature/amazing-feature`)
|
250
|
+
7. Open a Pull Request
|
251
|
+
|
252
|
+
## 📄 License
|
253
|
+
|
254
|
+
This project is licensed under the MIT License.
|
data/bin/code-qualia
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'pathname'
|
5
|
+
|
6
|
+
# Add lib directory to load path
|
7
|
+
lib_path = Pathname.new(__FILE__).dirname.parent.join('lib')
|
8
|
+
$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path.to_s)
|
9
|
+
|
10
|
+
require 'code_qualia'
|
11
|
+
|
12
|
+
CodeQualia::CLI.new(ARGV).run
|
@@ -0,0 +1,107 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
# Script to update smoke test expected outputs
|
7
|
+
class SmokeTestUpdater
|
8
|
+
def initialize
|
9
|
+
@root_dir = File.expand_path('..', __dir__)
|
10
|
+
@smoke_dir = File.join(@root_dir, 'smoke')
|
11
|
+
@expected_outputs_dir = File.join(@root_dir, 'expected_outputs')
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
puts '🔄 Updating smoke test expected outputs...'
|
16
|
+
|
17
|
+
smoke_projects.each do |project|
|
18
|
+
puts "\n📁 Processing #{project[:name]}..."
|
19
|
+
update_project_outputs(project)
|
20
|
+
end
|
21
|
+
|
22
|
+
puts "\n✅ All smoke test expected outputs have been updated!"
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def smoke_projects
|
28
|
+
projects = []
|
29
|
+
Dir.entries(@smoke_dir).each do |entry|
|
30
|
+
project_path = File.join(@smoke_dir, entry)
|
31
|
+
expected_path = File.join(@expected_outputs_dir, entry)
|
32
|
+
|
33
|
+
# Only include directories that have a Gemfile
|
34
|
+
next unless File.directory?(project_path) &&
|
35
|
+
!entry.start_with?('.') &&
|
36
|
+
File.exist?(File.join(project_path, 'Gemfile'))
|
37
|
+
|
38
|
+
projects << {
|
39
|
+
name: entry,
|
40
|
+
dir: project_path,
|
41
|
+
expected_path: expected_path,
|
42
|
+
is_rails: File.exist?(File.join(project_path, 'config', 'application.rb'))
|
43
|
+
}
|
44
|
+
end
|
45
|
+
projects
|
46
|
+
end
|
47
|
+
|
48
|
+
def update_project_outputs(project)
|
49
|
+
# Ensure expected outputs directory exists
|
50
|
+
FileUtils.mkdir_p(project[:expected_path])
|
51
|
+
|
52
|
+
# Generate coverage data if needed
|
53
|
+
generate_coverage_data(project)
|
54
|
+
|
55
|
+
# Generate outputs for each format
|
56
|
+
%w[human json csv table].each do |format|
|
57
|
+
puts " 📊 Generating #{format} format..."
|
58
|
+
|
59
|
+
command_output = if project[:is_rails]
|
60
|
+
# For Rails projects, run from within the project directory
|
61
|
+
`cd #{project[:dir]} && bundle exec code-qualia generate --format #{format} --top-n 10 2>&1`
|
62
|
+
else
|
63
|
+
# For non-Rails projects, run from project root with --directory option
|
64
|
+
`bundle exec code-qualia generate --format #{format} --directory #{project[:dir]} --top-n 10 2>&1`
|
65
|
+
end
|
66
|
+
|
67
|
+
if $?.success?
|
68
|
+
file_extension = if format == 'json'
|
69
|
+
'json'
|
70
|
+
else
|
71
|
+
(format == 'csv' ? 'csv' : 'txt')
|
72
|
+
end
|
73
|
+
output_file = File.join(project[:expected_path], "output_#{format}.#{file_extension}")
|
74
|
+
File.write(output_file, command_output)
|
75
|
+
puts " ✓ Saved to #{File.basename(output_file)}"
|
76
|
+
else
|
77
|
+
puts " ❌ Failed to generate #{format} format for #{project[:name]}"
|
78
|
+
puts " Error output: #{command_output}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Clean up generated files
|
83
|
+
cleanup_generated_files(project)
|
84
|
+
end
|
85
|
+
|
86
|
+
def generate_coverage_data(project)
|
87
|
+
puts ' 🧪 Generating coverage data...'
|
88
|
+
Dir.chdir(project[:dir]) do
|
89
|
+
if project[:is_rails]
|
90
|
+
# For Rails projects, run RSpec to generate coverage
|
91
|
+
`bundle exec rspec 2>/dev/null || true`
|
92
|
+
elsif File.exist?('spec/spec_helper.rb')
|
93
|
+
`bundle exec rspec --require spec_helper 2>/dev/null || true`
|
94
|
+
elsif File.exist?('test/test_helper.rb')
|
95
|
+
`bundle exec rake test 2>/dev/null || true`
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def cleanup_generated_files(project)
|
101
|
+
generated_json_path = File.join(project[:dir], 'code_qualia_analysis.json')
|
102
|
+
File.delete(generated_json_path) if File.exist?(generated_json_path)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Run the updater
|
107
|
+
SmokeTestUpdater.new.run if __FILE__ == $0
|
@@ -0,0 +1,217 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'optparse'
|
4
|
+
require 'json'
|
5
|
+
require_relative '../code_qualia'
|
6
|
+
|
7
|
+
module CodeQualia
|
8
|
+
class CLI
|
9
|
+
def initialize(argv)
|
10
|
+
@argv = argv
|
11
|
+
@options = {
|
12
|
+
top_n: 3,
|
13
|
+
config: './qualia.yml',
|
14
|
+
directory: Dir.pwd,
|
15
|
+
format: 'human',
|
16
|
+
verbose: false
|
17
|
+
}
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
parse_options
|
22
|
+
|
23
|
+
case @command
|
24
|
+
when 'generate'
|
25
|
+
generate_analysis
|
26
|
+
when 'install'
|
27
|
+
install_config
|
28
|
+
else
|
29
|
+
show_help
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def parse_options
|
36
|
+
parser = OptionParser.new do |opts|
|
37
|
+
opts.banner = 'Usage: code-qualia [command] [options]'
|
38
|
+
opts.separator ''
|
39
|
+
opts.separator 'Commands:'
|
40
|
+
opts.separator ' generate Analyze codebase and generate test recommendations'
|
41
|
+
opts.separator ' install Setup configuration file for your project'
|
42
|
+
opts.separator ''
|
43
|
+
opts.separator 'Options:'
|
44
|
+
|
45
|
+
opts.on('--top-n N', Integer, 'Number of top priority methods to analyze (default: 3)') do |n|
|
46
|
+
@options[:top_n] = n
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on('--config PATH', String, 'Path to configuration file (default: ./qualia.yml)') do |path|
|
50
|
+
@options[:config] = path
|
51
|
+
end
|
52
|
+
|
53
|
+
opts.on('--directory DIR', String, 'Directory to analyze (default: current directory)') do |dir|
|
54
|
+
@options[:directory] = dir
|
55
|
+
end
|
56
|
+
|
57
|
+
opts.on('--format FORMAT', String, 'Output format: human, json, csv, table (default: human)') do |format|
|
58
|
+
unless %w[human json csv table].include?(format)
|
59
|
+
puts "Error: Invalid format '#{format}'. Valid formats: human, json, csv, table"
|
60
|
+
exit 1
|
61
|
+
end
|
62
|
+
@options[:format] = format
|
63
|
+
end
|
64
|
+
|
65
|
+
opts.on('-v', '--verbose', 'Enable verbose logging') do
|
66
|
+
@options[:verbose] = true
|
67
|
+
end
|
68
|
+
|
69
|
+
opts.on('-h', '--help', 'Show this help message') do
|
70
|
+
puts opts
|
71
|
+
exit
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
parser.parse!(@argv)
|
76
|
+
@command = @argv.shift
|
77
|
+
end
|
78
|
+
|
79
|
+
def generate_analysis
|
80
|
+
original_dir = Dir.pwd
|
81
|
+
|
82
|
+
begin
|
83
|
+
# Change to target directory for analysis
|
84
|
+
Dir.chdir(@options[:directory])
|
85
|
+
|
86
|
+
results = CodeQualia.analyze(@options[:config], verbose: @options[:verbose])
|
87
|
+
|
88
|
+
if results.empty?
|
89
|
+
case @options[:format]
|
90
|
+
when 'json'
|
91
|
+
puts '[]'
|
92
|
+
when 'csv'
|
93
|
+
puts 'file_path,method_name,line_number,score,coverage,complexity,git_commits'
|
94
|
+
when 'table'
|
95
|
+
puts 'No methods found that need additional testing.'
|
96
|
+
else
|
97
|
+
puts '✅ No methods found that need additional testing.'
|
98
|
+
end
|
99
|
+
return
|
100
|
+
end
|
101
|
+
|
102
|
+
top_results = results.take(@options[:top_n])
|
103
|
+
|
104
|
+
case @options[:format]
|
105
|
+
when 'json'
|
106
|
+
output_json_format(top_results)
|
107
|
+
when 'csv'
|
108
|
+
output_csv_format(top_results)
|
109
|
+
when 'table'
|
110
|
+
output_table_format(top_results)
|
111
|
+
else # 'human'
|
112
|
+
output_human_format(top_results)
|
113
|
+
end
|
114
|
+
rescue CodeQualia::Error => e
|
115
|
+
puts "❌ Error: #{e.message}"
|
116
|
+
exit 1
|
117
|
+
rescue StandardError => e
|
118
|
+
puts "❌ Unexpected error: #{e.message}"
|
119
|
+
exit 1
|
120
|
+
ensure
|
121
|
+
Dir.chdir(original_dir)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def output_human_format(results)
|
126
|
+
puts "📊 Top #{results.length} methods requiring test coverage:\n\n"
|
127
|
+
|
128
|
+
results.each_with_index do |method, index|
|
129
|
+
puts "#{index + 1}. #{method[:file_path]}:#{method[:line_number]}"
|
130
|
+
puts " Method: #{method[:method_name]}"
|
131
|
+
puts " Priority Score: #{method[:score]}"
|
132
|
+
puts " Coverage: #{(method[:details][:coverage] * 100).round(1)}%"
|
133
|
+
puts " Complexity: #{method[:details][:complexity]}"
|
134
|
+
puts " Git Commits: #{method[:details][:git_commits]}"
|
135
|
+
puts ''
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def output_json_format(results)
|
140
|
+
json_output = results.map do |method|
|
141
|
+
{
|
142
|
+
file_path: method[:file_path],
|
143
|
+
class_name: extract_class_name(method[:file_path]),
|
144
|
+
method_name: method[:method_name],
|
145
|
+
line_number: method[:line_number],
|
146
|
+
score: method[:score],
|
147
|
+
details: method[:details]
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
puts JSON.pretty_generate(json_output)
|
152
|
+
end
|
153
|
+
|
154
|
+
def output_csv_format(results)
|
155
|
+
puts 'file_path,method_name,line_number,score,coverage,complexity,git_commits'
|
156
|
+
|
157
|
+
results.each do |method|
|
158
|
+
coverage_percent = (method[:details][:coverage] * 100).round(1)
|
159
|
+
puts "#{method[:file_path]},#{method[:method_name]},#{method[:line_number]},#{method[:score]},#{coverage_percent},#{method[:details][:complexity]},#{method[:details][:git_commits]}"
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
def output_table_format(results)
|
164
|
+
require 'io/console'
|
165
|
+
|
166
|
+
# Calculate column widths
|
167
|
+
max_file = results.map { |r| r[:file_path].length }.max || 20
|
168
|
+
max_method = [results.map { |r| r[:method_name].length }.max, 20].min
|
169
|
+
|
170
|
+
# Header
|
171
|
+
puts "+#{'-' * (max_file + 2)}+#{'-' * (max_method + 2)}+------+-------+----------+------------+----------+"
|
172
|
+
printf "| %-#{max_file}s | %-#{max_method}s | Line | Score | Coverage | Complexity | Commits |\n", 'File', 'Method'
|
173
|
+
puts "+#{'-' * (max_file + 2)}+#{'-' * (max_method + 2)}+------+-------+----------+------------+----------+"
|
174
|
+
|
175
|
+
# Data rows
|
176
|
+
results.each do |method|
|
177
|
+
file_name = method[:file_path]
|
178
|
+
method_name = method[:method_name].length > max_method ? method[:method_name][0...max_method - 1] + '…' : method[:method_name]
|
179
|
+
coverage_percent = (method[:details][:coverage] * 100).round(1)
|
180
|
+
|
181
|
+
printf "| %-#{max_file}s | %-#{max_method}s | %4d | %5.2f | %7.1f%% | %10d | %8d |\n",
|
182
|
+
file_name, method_name, method[:line_number], method[:score],
|
183
|
+
coverage_percent, method[:details][:complexity], method[:details][:git_commits]
|
184
|
+
end
|
185
|
+
|
186
|
+
puts "+#{'-' * (max_file + 2)}+#{'-' * (max_method + 2)}+------+-------+----------+------------+----------+"
|
187
|
+
end
|
188
|
+
|
189
|
+
def extract_class_name(file_path)
|
190
|
+
# Simple heuristic to extract class name from file path
|
191
|
+
File.basename(file_path, '.rb').split('_').map(&:capitalize).join
|
192
|
+
end
|
193
|
+
|
194
|
+
def install_config
|
195
|
+
installer = CodeQualia::ConfigInstaller.new(@options[:directory])
|
196
|
+
installer.install
|
197
|
+
rescue CodeQualia::Error => e
|
198
|
+
puts "❌ Error: #{e.message}"
|
199
|
+
exit 1
|
200
|
+
rescue StandardError => e
|
201
|
+
puts "❌ Unexpected error: #{e.message}"
|
202
|
+
exit 1
|
203
|
+
end
|
204
|
+
|
205
|
+
def show_help
|
206
|
+
puts 'code-qualia - AI-powered test coverage analysis tool'
|
207
|
+
puts ''
|
208
|
+
puts 'Usage: code-qualia [command] [options]'
|
209
|
+
puts ''
|
210
|
+
puts 'Commands:'
|
211
|
+
puts ' generate Analyze codebase and generate test recommendations'
|
212
|
+
puts ' install Setup configuration file for your project'
|
213
|
+
puts ''
|
214
|
+
puts "Run 'code-qualia [command] --help' for more information."
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|