churn_vs_complexity 1.6.2 → 1.8.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 +4 -4
- data/CHANGELOG.md +11 -0
- data/CLAUDE.md +1 -1
- data/README.md +16 -1
- data/lib/churn_vs_complexity/cli/parser.rb +12 -0
- data/lib/churn_vs_complexity/complexity/kotlin_calculator.rb +54 -0
- data/lib/churn_vs_complexity/complexity/rust_calculator.rb +54 -0
- data/lib/churn_vs_complexity/complexity/swift_calculator.rb +54 -0
- data/lib/churn_vs_complexity/complexity.rb +3 -0
- data/lib/churn_vs_complexity/complexity_validator.rb +6 -0
- data/lib/churn_vs_complexity/delta.rb +12 -0
- data/lib/churn_vs_complexity/file_selector.rb +36 -0
- data/lib/churn_vs_complexity/language_validator.rb +1 -1
- data/lib/churn_vs_complexity/normal/config.rb +24 -0
- data/lib/churn_vs_complexity/risk_classifier.rb +3 -0
- data/lib/churn_vs_complexity/version.rb +1 -1
- data/tmp/test-support/kotlin/Main.kt +7 -0
- data/tmp/test-support/kotlin/Utils.kt +11 -0
- data/tmp/test-support/rust/main.rs +7 -0
- data/tmp/test-support/rust/utils.rs +20 -0
- data/tmp/test-support/swift/main.swift +7 -0
- data/tmp/test-support/swift/utils.swift +24 -0
- metadata +14 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b5a149d026d33ac7319cc78d8c57af7e03113edf42d69f35612bbd72be708c77
|
|
4
|
+
data.tar.gz: c87fb3252fc699c681fd8da590fe02fe2d06e47b85fd5b7667fe314bd8ce3393
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '09d8eddfd30cd8c56abbd200d5f4e31529ac5fc1171837e3420ccfe2536bf203e3d003a8fbebe7c4c6b0fb54be9a84d71071ca447b9526538edd814953c8b436'
|
|
7
|
+
data.tar.gz: ad11518d39553ff5b03fb6c8ea0bc44989ba47d034cbd3b82582279055cad86806612cf0f71c1888b6ecf2aa312a20afce3ad80c8d36b5ab85480152e213e570
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## [1.8.0] - 2026-04-05
|
|
2
|
+
|
|
3
|
+
### Added
|
|
4
|
+
- Rust support for complexity calculation (via [lizard](https://github.com/terryyin/lizard), install with `pip install lizard`)
|
|
5
|
+
- Swift support for complexity calculation (via [lizard](https://github.com/terryyin/lizard), install with `pip install lizard`)
|
|
6
|
+
|
|
7
|
+
## [1.7.0] - 2026-04-05
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- Kotlin support for complexity calculation (via [lizard](https://github.com/terryyin/lizard), install with `pip install lizard`)
|
|
11
|
+
|
|
1
12
|
## [1.6.2] - 2026-02-19
|
|
2
13
|
|
|
3
14
|
### Changed
|
data/CLAUDE.md
CHANGED
|
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|
|
4
4
|
|
|
5
5
|
## Project Overview
|
|
6
6
|
|
|
7
|
-
`churn_vs_complexity` is a Ruby gem that analyzes code quality by correlating file churn (how often files change) with complexity scores. It supports Ruby (via Flog), JavaScript/TypeScript (via ESLint),
|
|
7
|
+
`churn_vs_complexity` is a Ruby gem that analyzes code quality by correlating file churn (how often files change) with complexity scores. It supports Ruby (via Flog), JavaScript/TypeScript (via ESLint), Java (via PMD), Python (via Radon), Go (via gocognit), Kotlin (via lizard), Rust (via lizard), and Swift (via lizard). Requires Ruby >= 3.3.
|
|
8
8
|
|
|
9
9
|
## Commands
|
|
10
10
|
|
data/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# ChurnVsComplexity
|
|
4
4
|
|
|
5
|
-
Correlates file churn (how often files change) with complexity scores to identify refactoring hotspots and track codebase health over time. Supports Ruby, JavaScript/TypeScript, Java, Python, and
|
|
5
|
+
Correlates file churn (how often files change) with complexity scores to identify refactoring hotspots and track codebase health over time. Supports Ruby, JavaScript/TypeScript, Java, Python, Go, Kotlin, Rust, and Swift.
|
|
6
6
|
|
|
7
7
|
Modes include hotspots ranking, triage assessment, CI quality gate, diff comparison, focus sessions, and timetravel history.
|
|
8
8
|
|
|
@@ -33,6 +33,9 @@ External tool dependencies per language:
|
|
|
33
33
|
- **JavaScript/TypeScript**: Requires [Node.js](https://nodejs.org) (uses ESLint internally).
|
|
34
34
|
- **Python**: Requires [Radon](https://radon.readthedocs.io) on the search path as `radon`. Install with `pip install radon`.
|
|
35
35
|
- **Go**: Requires [gocyclo](https://github.com/fzipp/gocyclo) on the search path. Install with `go install github.com/fzipp/gocyclo/cmd/gocyclo@latest`.
|
|
36
|
+
- **Kotlin**: Requires [lizard](https://github.com/terryyin/lizard) on the search path. Install with `pip install lizard`.
|
|
37
|
+
- **Rust**: Requires [lizard](https://github.com/terryyin/lizard) on the search path. Install with `pip install lizard`.
|
|
38
|
+
- **Swift**: Requires [lizard](https://github.com/terryyin/lizard) on the search path. Install with `pip install lizard`.
|
|
36
39
|
|
|
37
40
|
## Usage
|
|
38
41
|
|
|
@@ -48,6 +51,9 @@ Languages:
|
|
|
48
51
|
Check complexity of javascript and typescript files
|
|
49
52
|
--python Check complexity of python files
|
|
50
53
|
--go Check complexity of go files
|
|
54
|
+
--kotlin Check complexity of kotlin files
|
|
55
|
+
--rust Check complexity of rust files
|
|
56
|
+
--swift Check complexity of swift files
|
|
51
57
|
|
|
52
58
|
Modes (mutually exclusive):
|
|
53
59
|
--timetravel N Calculate summary for all commits at intervals of N days throughout project history or from the date specified with --since
|
|
@@ -121,6 +127,15 @@ churn_vs_complexity --java -m --since 2019-03-01 --timetravel 30 --graph my_java
|
|
|
121
127
|
|
|
122
128
|
# Analyse complexity of specific commits
|
|
123
129
|
churn_vs_complexity --js --delta HEAD --summary my_js_project
|
|
130
|
+
|
|
131
|
+
# Kotlin project hotspots
|
|
132
|
+
churn_vs_complexity --kotlin --hotspots my_kotlin_project
|
|
133
|
+
|
|
134
|
+
# Rust project CSV report
|
|
135
|
+
churn_vs_complexity --rust --csv my_rust_project > ~/Desktop/rust-demo.csv
|
|
136
|
+
|
|
137
|
+
# Swift project summary
|
|
138
|
+
churn_vs_complexity --swift --summary -q my_swift_project
|
|
124
139
|
```
|
|
125
140
|
|
|
126
141
|
## Development
|
|
@@ -34,6 +34,18 @@ module ChurnVsComplexity
|
|
|
34
34
|
options[:language] = :go
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
+
opts.on('--kotlin', 'Check complexity of kotlin files') do
|
|
38
|
+
options[:language] = :kotlin
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
opts.on('--rust', 'Check complexity of rust files') do
|
|
42
|
+
options[:language] = :rust
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
opts.on('--swift', 'Check complexity of swift files') do
|
|
46
|
+
options[:language] = :swift
|
|
47
|
+
end
|
|
48
|
+
|
|
37
49
|
opts.separator ''
|
|
38
50
|
opts.separator 'Modes (mutually exclusive):'
|
|
39
51
|
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'open3'
|
|
4
|
+
|
|
5
|
+
module ChurnVsComplexity
|
|
6
|
+
module Complexity
|
|
7
|
+
module KotlinCalculator
|
|
8
|
+
class << self
|
|
9
|
+
attr_writer :command_runner
|
|
10
|
+
|
|
11
|
+
def folder_based? = false
|
|
12
|
+
|
|
13
|
+
def calculate(files:)
|
|
14
|
+
csv_output = run_lizard(files)
|
|
15
|
+
parse_lizard_output(csv_output, files:)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Lizard CSV format: NLOC,CCN,tokens,params,length,"loc","file","func","long_func",start,end
|
|
19
|
+
LIZARD_LINE_PATTERN = /^\d+,(\d+),\d+,\d+,\d+,"[^"]*","([^"]*)"/.freeze
|
|
20
|
+
|
|
21
|
+
def parse_lizard_output(csv_output, files:)
|
|
22
|
+
scores = Hash.new(0)
|
|
23
|
+
csv_output.each_line do |line|
|
|
24
|
+
match = line.match(LIZARD_LINE_PATTERN)
|
|
25
|
+
next unless match
|
|
26
|
+
|
|
27
|
+
scores[match[2]] += match[1].to_i
|
|
28
|
+
end
|
|
29
|
+
files.to_h { |file| [file, scores[file] || 0] }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def check_dependencies!
|
|
33
|
+
command_runner.call('lizard --version 2>&1')
|
|
34
|
+
rescue Errno::ENOENT
|
|
35
|
+
raise Error, 'Needs lizard installed (pip install lizard)'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def command_runner
|
|
41
|
+
@command_runner || Open3.method(:capture2)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def run_lizard(files)
|
|
45
|
+
files_arg = files.map { |f| "'#{f}'" }.join(' ')
|
|
46
|
+
stdout, status = command_runner.call("lizard --csv #{files_arg}")
|
|
47
|
+
raise Error, "lizard failed (exit #{status.exitstatus}). Is it installed?" unless status.success?
|
|
48
|
+
|
|
49
|
+
stdout
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'open3'
|
|
4
|
+
|
|
5
|
+
module ChurnVsComplexity
|
|
6
|
+
module Complexity
|
|
7
|
+
module RustCalculator
|
|
8
|
+
class << self
|
|
9
|
+
attr_writer :command_runner
|
|
10
|
+
|
|
11
|
+
def folder_based? = false
|
|
12
|
+
|
|
13
|
+
def calculate(files:)
|
|
14
|
+
csv_output = run_lizard(files)
|
|
15
|
+
parse_lizard_output(csv_output, files:)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Lizard CSV format: NLOC,CCN,tokens,params,length,"loc","file","func","long_func",start,end
|
|
19
|
+
LIZARD_LINE_PATTERN = /^\d+,(\d+),\d+,\d+,\d+,"[^"]*","([^"]*)"/
|
|
20
|
+
|
|
21
|
+
def parse_lizard_output(csv_output, files:)
|
|
22
|
+
scores = Hash.new(0)
|
|
23
|
+
csv_output.each_line do |line|
|
|
24
|
+
match = line.match(LIZARD_LINE_PATTERN)
|
|
25
|
+
next unless match
|
|
26
|
+
|
|
27
|
+
scores[match[2]] += match[1].to_i
|
|
28
|
+
end
|
|
29
|
+
files.to_h { |file| [file, scores[file] || 0] }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def check_dependencies!
|
|
33
|
+
command_runner.call('lizard --version 2>&1')
|
|
34
|
+
rescue Errno::ENOENT
|
|
35
|
+
raise Error, 'Needs lizard installed (pip install lizard)'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def command_runner
|
|
41
|
+
@command_runner || Open3.method(:capture2)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def run_lizard(files)
|
|
45
|
+
files_arg = files.map { |f| "'#{f}'" }.join(' ')
|
|
46
|
+
stdout, status = command_runner.call("lizard --csv #{files_arg}")
|
|
47
|
+
raise Error, "lizard failed (exit #{status.exitstatus}). Is it installed?" unless status.success?
|
|
48
|
+
|
|
49
|
+
stdout
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'open3'
|
|
4
|
+
|
|
5
|
+
module ChurnVsComplexity
|
|
6
|
+
module Complexity
|
|
7
|
+
module SwiftCalculator
|
|
8
|
+
class << self
|
|
9
|
+
attr_writer :command_runner
|
|
10
|
+
|
|
11
|
+
def folder_based? = false
|
|
12
|
+
|
|
13
|
+
def calculate(files:)
|
|
14
|
+
csv_output = run_lizard(files)
|
|
15
|
+
parse_lizard_output(csv_output, files:)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Lizard CSV format: NLOC,CCN,tokens,params,length,"loc","file","func","long_func",start,end
|
|
19
|
+
LIZARD_LINE_PATTERN = /^\d+,(\d+),\d+,\d+,\d+,"[^"]*","([^"]*)"/
|
|
20
|
+
|
|
21
|
+
def parse_lizard_output(csv_output, files:)
|
|
22
|
+
scores = Hash.new(0)
|
|
23
|
+
csv_output.each_line do |line|
|
|
24
|
+
match = line.match(LIZARD_LINE_PATTERN)
|
|
25
|
+
next unless match
|
|
26
|
+
|
|
27
|
+
scores[match[2]] += match[1].to_i
|
|
28
|
+
end
|
|
29
|
+
files.to_h { |file| [file, scores[file] || 0] }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def check_dependencies!
|
|
33
|
+
command_runner.call('lizard --version 2>&1')
|
|
34
|
+
rescue Errno::ENOENT
|
|
35
|
+
raise Error, 'Needs lizard installed (pip install lizard)'
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def command_runner
|
|
41
|
+
@command_runner || Open3.method(:capture2)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def run_lizard(files)
|
|
45
|
+
files_arg = files.map { |f| "'#{f}'" }.join(' ')
|
|
46
|
+
stdout, status = command_runner.call("lizard --csv #{files_arg}")
|
|
47
|
+
raise Error, "lizard failed (exit #{status.exitstatus}). Is it installed?" unless status.success?
|
|
48
|
+
|
|
49
|
+
stdout
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -5,6 +5,9 @@ require_relative 'complexity/flog_calculator'
|
|
|
5
5
|
require_relative 'complexity/eslint_calculator'
|
|
6
6
|
require_relative 'complexity/python_calculator'
|
|
7
7
|
require_relative 'complexity/go_calculator'
|
|
8
|
+
require_relative 'complexity/kotlin_calculator'
|
|
9
|
+
require_relative 'complexity/rust_calculator'
|
|
10
|
+
require_relative 'complexity/swift_calculator'
|
|
8
11
|
|
|
9
12
|
module ChurnVsComplexity
|
|
10
13
|
module Complexity
|
|
@@ -12,6 +12,12 @@ module ChurnVsComplexity
|
|
|
12
12
|
Complexity::PythonCalculator.check_dependencies!
|
|
13
13
|
when :go
|
|
14
14
|
Complexity::GoCalculator.check_dependencies!
|
|
15
|
+
when :kotlin
|
|
16
|
+
Complexity::KotlinCalculator.check_dependencies!
|
|
17
|
+
when :rust
|
|
18
|
+
Complexity::RustCalculator.check_dependencies!
|
|
19
|
+
when :swift
|
|
20
|
+
Complexity::SwiftCalculator.check_dependencies!
|
|
15
21
|
end
|
|
16
22
|
end
|
|
17
23
|
end
|
|
@@ -38,6 +38,12 @@ module ChurnVsComplexity
|
|
|
38
38
|
FileSelector::Python.predefined(included:, excluded:)
|
|
39
39
|
when :go
|
|
40
40
|
FileSelector::Go.predefined(included:, excluded:)
|
|
41
|
+
when :kotlin
|
|
42
|
+
FileSelector::Kotlin.predefined(included:, excluded:)
|
|
43
|
+
when :rust
|
|
44
|
+
FileSelector::Rust.predefined(included:, excluded:)
|
|
45
|
+
when :swift
|
|
46
|
+
FileSelector::Swift.predefined(included:, excluded:)
|
|
41
47
|
end
|
|
42
48
|
end
|
|
43
49
|
|
|
@@ -53,6 +59,12 @@ module ChurnVsComplexity
|
|
|
53
59
|
Complexity::PythonCalculator
|
|
54
60
|
when :go
|
|
55
61
|
Complexity::GoCalculator
|
|
62
|
+
when :kotlin
|
|
63
|
+
Complexity::KotlinCalculator
|
|
64
|
+
when :rust
|
|
65
|
+
Complexity::RustCalculator
|
|
66
|
+
when :swift
|
|
67
|
+
Complexity::SwiftCalculator
|
|
56
68
|
end
|
|
57
69
|
end
|
|
58
70
|
end
|
|
@@ -14,6 +14,12 @@ module ChurnVsComplexity
|
|
|
14
14
|
['.py']
|
|
15
15
|
when :go
|
|
16
16
|
['.go']
|
|
17
|
+
when :kotlin
|
|
18
|
+
['.kt', '.kts']
|
|
19
|
+
when :rust
|
|
20
|
+
['.rs']
|
|
21
|
+
when :swift
|
|
22
|
+
['.swift']
|
|
17
23
|
else
|
|
18
24
|
raise Error, "Unsupported language: #{language}"
|
|
19
25
|
end
|
|
@@ -130,5 +136,35 @@ module ChurnVsComplexity
|
|
|
130
136
|
Predefined.new(included:, extensions: FileSelector.extensions(:go), excluded:)
|
|
131
137
|
end
|
|
132
138
|
end
|
|
139
|
+
|
|
140
|
+
module Kotlin
|
|
141
|
+
def self.excluding(excluded)
|
|
142
|
+
Excluding.new(FileSelector.extensions(:kotlin), excluded)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def self.predefined(included:, excluded:)
|
|
146
|
+
Predefined.new(included:, extensions: FileSelector.extensions(:kotlin), excluded:)
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
module Rust
|
|
151
|
+
def self.excluding(excluded)
|
|
152
|
+
Excluding.new(FileSelector.extensions(:rust), excluded)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def self.predefined(included:, excluded:)
|
|
156
|
+
Predefined.new(included:, extensions: FileSelector.extensions(:rust), excluded:)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
module Swift
|
|
161
|
+
def self.excluding(excluded)
|
|
162
|
+
Excluding.new(FileSelector.extensions(:swift), excluded)
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def self.predefined(included:, excluded:)
|
|
166
|
+
Predefined.new(included:, extensions: FileSelector.extensions(:swift), excluded:)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
133
169
|
end
|
|
134
170
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module ChurnVsComplexity
|
|
4
4
|
module LanguageValidator
|
|
5
|
-
SUPPORTED = %i[java ruby javascript python go].freeze
|
|
5
|
+
SUPPORTED = %i[java ruby javascript python go kotlin rust swift].freeze
|
|
6
6
|
|
|
7
7
|
def self.validate!(language)
|
|
8
8
|
raise ValidationError, "Unsupported language: #{language}" unless SUPPORTED.include?(language)
|
|
@@ -75,6 +75,30 @@ module ChurnVsComplexity
|
|
|
75
75
|
serializer:,
|
|
76
76
|
since: @since || @relative_period,
|
|
77
77
|
)
|
|
78
|
+
when :kotlin
|
|
79
|
+
Engine.concurrent(
|
|
80
|
+
complexity: Complexity::KotlinCalculator,
|
|
81
|
+
churn:,
|
|
82
|
+
file_selector: FileSelector::Kotlin.excluding(@excluded),
|
|
83
|
+
serializer:,
|
|
84
|
+
since: @since || @relative_period,
|
|
85
|
+
)
|
|
86
|
+
when :rust
|
|
87
|
+
Engine.concurrent(
|
|
88
|
+
complexity: Complexity::RustCalculator,
|
|
89
|
+
churn:,
|
|
90
|
+
file_selector: FileSelector::Rust.excluding(@excluded),
|
|
91
|
+
serializer:,
|
|
92
|
+
since: @since || @relative_period,
|
|
93
|
+
)
|
|
94
|
+
when :swift
|
|
95
|
+
Engine.concurrent(
|
|
96
|
+
complexity: Complexity::SwiftCalculator,
|
|
97
|
+
churn:,
|
|
98
|
+
file_selector: FileSelector::Swift.excluding(@excluded),
|
|
99
|
+
serializer:,
|
|
100
|
+
since: @since || @relative_period,
|
|
101
|
+
)
|
|
78
102
|
end
|
|
79
103
|
end
|
|
80
104
|
|
|
@@ -14,6 +14,9 @@ module ChurnVsComplexity
|
|
|
14
14
|
# Python Radon Cyclomatic complexity 1 ~44 5-50
|
|
15
15
|
# Java PMD Cyclomatic complexity 1 ~39 1-40
|
|
16
16
|
# Go gocognit Cognitive complexity 0 ~87 0-50
|
|
17
|
+
# Kotlin lizard Cyclomatic complexity 1 ~40 1-40
|
|
18
|
+
# Rust lizard Cyclomatic complexity 1 ~40 1-40
|
|
19
|
+
# Swift lizard Cyclomatic complexity 1 ~40 1-40
|
|
17
20
|
#
|
|
18
21
|
# The DEFAULT_LOW and DEFAULT_HIGH thresholds below are rough midpoints
|
|
19
22
|
# suitable for Java/Python/JS. They are too aggressive for Ruby (Flog
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
fn calculate_sum(numbers: &[i32]) -> i32 {
|
|
2
|
+
let mut total = 0;
|
|
3
|
+
for n in numbers {
|
|
4
|
+
total += n;
|
|
5
|
+
}
|
|
6
|
+
total
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
fn classify(value: i32) -> &'static str {
|
|
10
|
+
match value {
|
|
11
|
+
0 => "zero",
|
|
12
|
+
1..=10 => "low",
|
|
13
|
+
11..=100 => "medium",
|
|
14
|
+
_ => "high",
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
fn is_even(n: i32) -> bool {
|
|
19
|
+
n % 2 == 0
|
|
20
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
func calculateSum(_ numbers: [Int]) -> Int {
|
|
2
|
+
var total = 0
|
|
3
|
+
for n in numbers {
|
|
4
|
+
total += n
|
|
5
|
+
}
|
|
6
|
+
return total
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
func classify(_ value: Int) -> String {
|
|
10
|
+
switch value {
|
|
11
|
+
case 0:
|
|
12
|
+
return "zero"
|
|
13
|
+
case 1...10:
|
|
14
|
+
return "low"
|
|
15
|
+
case 11...100:
|
|
16
|
+
return "medium"
|
|
17
|
+
default:
|
|
18
|
+
return "high"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
func isEven(_ n: Int) -> Bool {
|
|
23
|
+
return n % 2 == 0
|
|
24
|
+
}
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: churn_vs_complexity
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Erik T. Madsen
|
|
@@ -39,9 +39,9 @@ dependencies:
|
|
|
39
39
|
version: '2.1'
|
|
40
40
|
description: Correlates file churn (how often files change) with complexity scores
|
|
41
41
|
to identify refactoring hotspots. Supports Ruby, JavaScript/TypeScript, Java, Python,
|
|
42
|
-
and
|
|
43
|
-
comparison, focus sessions, and timetravel history. Inspired
|
|
44
|
-
article "Getting Empirical about Refactoring".
|
|
42
|
+
Go, Kotlin, Rust, and Swift. Modes include hotspots ranking, triage assessment,
|
|
43
|
+
CI quality gate, diff comparison, focus sessions, and timetravel history. Inspired
|
|
44
|
+
by Michael Feathers' article "Getting Empirical about Refactoring".
|
|
45
45
|
email:
|
|
46
46
|
- beatmadsen@gmail.com
|
|
47
47
|
executables:
|
|
@@ -69,10 +69,13 @@ files:
|
|
|
69
69
|
- lib/churn_vs_complexity/complexity/eslint_calculator.rb
|
|
70
70
|
- lib/churn_vs_complexity/complexity/flog_calculator.rb
|
|
71
71
|
- lib/churn_vs_complexity/complexity/go_calculator.rb
|
|
72
|
+
- lib/churn_vs_complexity/complexity/kotlin_calculator.rb
|
|
72
73
|
- lib/churn_vs_complexity/complexity/pmd.rb
|
|
73
74
|
- lib/churn_vs_complexity/complexity/pmd/files_calculator.rb
|
|
74
75
|
- lib/churn_vs_complexity/complexity/pmd/folder_calculator.rb
|
|
75
76
|
- lib/churn_vs_complexity/complexity/python_calculator.rb
|
|
77
|
+
- lib/churn_vs_complexity/complexity/rust_calculator.rb
|
|
78
|
+
- lib/churn_vs_complexity/complexity/swift_calculator.rb
|
|
76
79
|
- lib/churn_vs_complexity/complexity_validator.rb
|
|
77
80
|
- lib/churn_vs_complexity/concurrent_calculator.rb
|
|
78
81
|
- lib/churn_vs_complexity/delta.rb
|
|
@@ -145,8 +148,14 @@ files:
|
|
|
145
148
|
- tmp/test-support/javascript/moderate.js
|
|
146
149
|
- tmp/test-support/javascript/simple.js
|
|
147
150
|
- tmp/test-support/javascript/typescript-example.ts
|
|
151
|
+
- tmp/test-support/kotlin/Main.kt
|
|
152
|
+
- tmp/test-support/kotlin/Utils.kt
|
|
148
153
|
- tmp/test-support/python/example.py
|
|
149
154
|
- tmp/test-support/python/utils.py
|
|
155
|
+
- tmp/test-support/rust/main.rs
|
|
156
|
+
- tmp/test-support/rust/utils.rs
|
|
157
|
+
- tmp/test-support/swift/main.swift
|
|
158
|
+
- tmp/test-support/swift/utils.swift
|
|
150
159
|
- tmp/test-support/txt/abc.txt
|
|
151
160
|
- tmp/test-support/txt/d.txt
|
|
152
161
|
- tmp/test-support/txt/ef.txt
|
|
@@ -179,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
179
188
|
- !ruby/object:Gem::Version
|
|
180
189
|
version: '0'
|
|
181
190
|
requirements: []
|
|
182
|
-
rubygems_version:
|
|
191
|
+
rubygems_version: 4.0.6
|
|
183
192
|
specification_version: 4
|
|
184
193
|
summary: Analyse churn vs complexity to find refactoring hotspots, gate CI quality,
|
|
185
194
|
triage risky files, and track codebase health over time.
|