code_keeper 0.1.0 → 0.5.1
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/.github/workflows/main.yml +5 -1
- data/.rubocop.yml +16 -1
- data/CHANGELOG.md +24 -0
- data/README.md +8 -13
- data/code_keeper.gemspec +4 -4
- data/lib/code_keeper/config.rb +3 -2
- data/lib/code_keeper/finder.rb +0 -6
- data/lib/code_keeper/formatter.rb +12 -13
- data/lib/code_keeper/metrics/abc_metric.rb +31 -0
- data/lib/code_keeper/metrics/class_length.rb +123 -0
- data/lib/code_keeper/metrics/cyclomatic_complexity.rb +4 -2
- data/lib/code_keeper/metrics.rb +7 -1
- data/lib/code_keeper/parser.rb +1 -1
- data/lib/code_keeper/result.rb +2 -2
- data/lib/code_keeper/scorer.rb +13 -6
- data/lib/code_keeper/version.rb +1 -1
- data/lib/code_keeper.rb +2 -0
- metadata +18 -16
- data/Gemfile.lock +0 -69
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1032e75ff8322d23a622e6bac5a04039939999032d5559e9ff54d46f04ccd16
|
4
|
+
data.tar.gz: 51e78032de7754ea37aacd6ea422d46e4c66cc94c5c5d10a2baf963cee475ee1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eedf3bcecbd0ad563300548c9b1ac9b7d2ddec52550b459754fa1556e052940ad36ce7c5fd9afdb6df0768ea5ce9dd04680d3cae6a68112d106cb4ddf6611073
|
7
|
+
data.tar.gz: c527a3f3a175535b53512f8291276b34edf6cf8b3afe267a093603a14b59c4bedb867af0383dd137b6b78992d7b9194dfd133535f811f2654a1077d61409c8ee
|
data/.github/workflows/main.yml
CHANGED
@@ -5,12 +5,16 @@ on: [push,pull_request]
|
|
5
5
|
jobs:
|
6
6
|
build:
|
7
7
|
runs-on: ubuntu-latest
|
8
|
+
strategy:
|
9
|
+
matrix:
|
10
|
+
ruby: [2.7, 3.0]
|
11
|
+
name: Ruby ${{ matrix.ruby }}
|
8
12
|
steps:
|
9
13
|
- uses: actions/checkout@v2
|
10
14
|
- name: Set up Ruby
|
11
15
|
uses: ruby/setup-ruby@v1
|
12
16
|
with:
|
13
|
-
ruby-version:
|
17
|
+
ruby-version: ${{ matrix.ruby }}
|
14
18
|
- name: Run the default task
|
15
19
|
run: |
|
16
20
|
gem install bundler -v 2.2.3
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion: 3.0
|
3
2
|
Exclude:
|
4
3
|
- spec/fixtures/**/*.rb
|
5
4
|
|
@@ -44,3 +43,19 @@ Style/Documentation:
|
|
44
43
|
|
45
44
|
Metrics/AbcSize:
|
46
45
|
Max: 25
|
46
|
+
Exclude:
|
47
|
+
# It's hard to control.
|
48
|
+
- lib/code_keeper/metrics/class_length.rb
|
49
|
+
|
50
|
+
Metrics/CyclomaticComplexity:
|
51
|
+
Exclude:
|
52
|
+
# It's hard to control.
|
53
|
+
- lib/code_keeper/metrics/class_length.rb
|
54
|
+
|
55
|
+
Metrics/PerceivedComplexity:
|
56
|
+
Exclude:
|
57
|
+
# It's hard to control.
|
58
|
+
- lib/code_keeper/metrics/class_length.rb
|
59
|
+
|
60
|
+
Metrics/MethodLength:
|
61
|
+
Max: 40
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Change log
|
2
|
+
|
3
|
+
## Unrelease
|
4
|
+
|
5
|
+
## 0.5.1 (2021-09-19)
|
6
|
+
### Bug fixes
|
7
|
+
- [34](https://github.com/ebihara99999/code_keeper/pull/34): A result of the class_length doesn't show namespaces, and the class_length doesn't count comments of inner classes correctly.
|
8
|
+
|
9
|
+
## 0.5.0 (2021-09-16)
|
10
|
+
### Changes
|
11
|
+
- [32](https://github.com/ebihara99999/code_keeper/pull/32): Specify dependency versions and loosen the supported ruby version.
|
12
|
+
|
13
|
+
## 0.4.0 (2021-09-15)
|
14
|
+
### New features
|
15
|
+
- [#30](https://github.com/ebihara99999/code_keeper/pull/30): Support CSV and JSON format.
|
16
|
+
|
17
|
+
## 0.3.0 (2021-09-15)
|
18
|
+
|
19
|
+
### New features
|
20
|
+
- [#26](https://github.com/ebihara99999/code_keeper/pull/26): Support an ABC software metric.
|
21
|
+
- [#27](https://github.com/ebihara99999/code_keeper/pull/27): Support a class length metric.
|
22
|
+
|
23
|
+
### Changes
|
24
|
+
- [#25](https://github.com/ebihara99999/code_keeper/pull/25): Remove redundant codes.
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@ The CodeKeeper measures metrics especially about complexity and size of Ruby fil
|
|
3
3
|
|
4
4
|
Mesuring metrics leads to keep codebase simple and clean, and I name the gem CodeKeeper.
|
5
5
|
|
6
|
-
Now CodeKeeper supports the cyclomatic complexity. The scores are output to stdout.
|
6
|
+
Now CodeKeeper supports the cyclomatic complexity of a file, the ABC software metric of a file, and class length. The scores are output to stdout of a json or csv format.
|
7
7
|
|
8
8
|
## Installation
|
9
9
|
|
@@ -25,18 +25,11 @@ Or install it yourself as:
|
|
25
25
|
Run CodeKeeper and you get scores of metrics from stdout like
|
26
26
|
|
27
27
|
```rb
|
28
|
-
$ bundle exec code_keeper
|
29
|
-
|
30
|
-
|
31
|
-
Metric: cyclomatic_complexity
|
32
|
-
Filename: app/models/admin.rb
|
33
|
-
Score: 1
|
34
|
-
---
|
35
|
-
Metric: cyclomatic_complexity
|
36
|
-
Filename: app/models/user.rb
|
37
|
-
Score: 23
|
38
|
-
---
|
28
|
+
$ bundle exec code_keeper app/models/user.rb app/models/admin.rb > metrics.json
|
29
|
+
$ cat metrics.json
|
30
|
+
{"cyclomatic_complexity":{"app/models/admin.rb":9,"app/models/user.rb":23},"class_length":{"Admin":86,"User":1475},"abc_metric":{"app/models/admin.rb":76.909,"app/models/user.rb":1546.4155}}
|
39
31
|
```
|
32
|
+
If you need a csv format, change the configuration as explained later.
|
40
33
|
|
41
34
|
### Run CodeKeeper
|
42
35
|
To measure metrics of all the ruby files recursively in the current directory, run
|
@@ -55,9 +48,11 @@ CodeKeeper makes you configure the following way:
|
|
55
48
|
```rb
|
56
49
|
CodeKeeper.configure do |config|
|
57
50
|
# If you choose metrics, specify as follows:
|
58
|
-
config.metrics =
|
51
|
+
config.metrics = %i(cyclomatic_complexity abc_metric class_length)
|
59
52
|
# The number of threads. The default is 2. Executed sequentially if you set 1.
|
60
53
|
config.number_of_threads = 4
|
54
|
+
# The default is json
|
55
|
+
config.format = :json
|
61
56
|
end
|
62
57
|
```
|
63
58
|
|
data/code_keeper.gemspec
CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.description = "The CodeKeeper measures metrics especially about complexity and size of Ruby files, aiming to be a Ruby version of gmetrics."
|
13
13
|
spec.homepage = "https://github.com/ebihara99999/code_keeper"
|
14
14
|
spec.license = "MIT"
|
15
|
-
spec.required_ruby_version = Gem::Requirement.new(">=
|
15
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
16
16
|
|
17
17
|
spec.metadata["homepage_uri"] = spec.homepage
|
18
18
|
spec.metadata["source_code_uri"] = "https://github.com/ebihara99999/code_keeper/"
|
@@ -28,9 +28,9 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
|
30
30
|
# Uncomment to register a new dependency of your gem
|
31
|
-
spec.add_dependency "parallel"
|
32
|
-
spec.add_dependency "rubocop"
|
33
|
-
spec.add_dependency "rubocop-ast"
|
31
|
+
spec.add_dependency "parallel", '~> 1.20.1'
|
32
|
+
spec.add_dependency "rubocop", '~> 1.13.0'
|
33
|
+
spec.add_dependency "rubocop-ast", '~> 1.4.1'
|
34
34
|
|
35
35
|
# For more information and examples about making a new gem, checkout our
|
36
36
|
# guide at: https://bundler.io/guides/creating_gem.html
|
data/lib/code_keeper/config.rb
CHANGED
@@ -3,11 +3,12 @@
|
|
3
3
|
module CodeKeeper
|
4
4
|
# Provide configuration
|
5
5
|
class Config
|
6
|
-
attr_accessor :metrics, :number_of_threads
|
6
|
+
attr_accessor :metrics, :number_of_threads, :format
|
7
7
|
|
8
8
|
def initialize
|
9
|
-
@metrics = [
|
9
|
+
@metrics = %i[cyclomatic_complexity class_length abc_metric]
|
10
10
|
@number_of_threads = 2
|
11
|
+
@format = :json # json and csv are supported.
|
11
12
|
end
|
12
13
|
end
|
13
14
|
end
|
data/lib/code_keeper/finder.rb
CHANGED
@@ -16,13 +16,7 @@ module CodeKeeper
|
|
16
16
|
private
|
17
17
|
|
18
18
|
def search_recursively(file_or_dir_paths)
|
19
|
-
checked = {}
|
20
|
-
|
21
19
|
file_or_dir_paths.each do |edge|
|
22
|
-
next if checked[:"#{edge}"]
|
23
|
-
|
24
|
-
checked[:"#{edge}"] = true
|
25
|
-
|
26
20
|
if FileTest.file?(edge)
|
27
21
|
file_or_dir_paths << edge unless file_or_dir_paths.include?(edge)
|
28
22
|
else
|
@@ -1,26 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'csv'
|
4
|
+
|
3
5
|
module CodeKeeper
|
4
6
|
# Format a result and make it human-readable.
|
5
7
|
class Formatter
|
6
8
|
class << self
|
7
9
|
def format(result)
|
8
|
-
|
9
|
-
formatted_result = +title
|
10
|
+
return result.scores.to_json if CodeKeeper.config.format == :json
|
10
11
|
|
12
|
+
# csv is supported besides json
|
13
|
+
csv_array = []
|
11
14
|
result.scores.each_key do |metric|
|
12
|
-
result.scores[metric].each
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
EOS
|
20
|
-
)
|
21
|
-
end
|
15
|
+
result.scores[metric].each { |k, v| csv_array << [metric, k, v] }
|
16
|
+
end
|
17
|
+
|
18
|
+
headers = %w[metric file score]
|
19
|
+
CSV.generate(headers: true) do |csv|
|
20
|
+
csv << headers
|
21
|
+
csv_array.each { |array| csv << array }
|
22
22
|
end
|
23
|
-
formatted_result
|
24
23
|
end
|
25
24
|
end
|
26
25
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CodeKeeper
|
4
|
+
module Metrics
|
5
|
+
# Caluculate cyclomatic complexity
|
6
|
+
class AbcMetric
|
7
|
+
include ::RuboCop::Cop::Metrics::Utils::IteratingBlock
|
8
|
+
include ::RuboCop::Cop::Metrics::Utils::RepeatedCsendDiscount
|
9
|
+
|
10
|
+
def initialize(file_path)
|
11
|
+
ps = Parser.parse(file_path)
|
12
|
+
@path = file_path
|
13
|
+
@body = ps.ast
|
14
|
+
@assignments = 0
|
15
|
+
@branches = 0
|
16
|
+
@conditionals = 0
|
17
|
+
end
|
18
|
+
|
19
|
+
def score
|
20
|
+
caluculator = ::RuboCop::Cop::Metrics::Utils::AbcSizeCalculator.new(@body)
|
21
|
+
caluculator.calculate
|
22
|
+
@assignments = caluculator.instance_variable_get('@assignment')
|
23
|
+
@conditionals = caluculator.instance_variable_get('@condition')
|
24
|
+
@branches = caluculator.instance_variable_get('@branch')
|
25
|
+
|
26
|
+
value = Math.sqrt(@assignments**2 + @branches**2 + @conditionals**2).round(4)
|
27
|
+
{ "#{@path}": value }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CodeKeeper
|
4
|
+
module Metrics
|
5
|
+
# Caluculate Class Length.
|
6
|
+
class ClassLength
|
7
|
+
def initialize(file_path)
|
8
|
+
@ps = Parser.parse(file_path)
|
9
|
+
@body = @ps.ast
|
10
|
+
@score_hash = {}
|
11
|
+
end
|
12
|
+
|
13
|
+
# NOTE: This doesn't exclude foldale sources like Array, Hash and Heredoc.
|
14
|
+
def score
|
15
|
+
@body.each_node(:class, :casgn, :module) do |node|
|
16
|
+
if node.class_type? || node.module_type?
|
17
|
+
@score_hash.store(build_namespace(node), calculate(node))
|
18
|
+
elsif node.casgn_type?
|
19
|
+
parent = node.parent
|
20
|
+
|
21
|
+
if parent&.assignment?
|
22
|
+
block_node = node.children[2]
|
23
|
+
klass = node.loc.name.source
|
24
|
+
elsif parent&.parent&.masgn_type?
|
25
|
+
# In the case where `A, B = Struct.new(:a, :b)`,
|
26
|
+
# B is always nil.
|
27
|
+
assigned = parent.loc.expression.source.split(',').first
|
28
|
+
next unless node.loc.name.source == assigned
|
29
|
+
|
30
|
+
block_node = parent.parent.children[1]
|
31
|
+
klass = node.loc.name.source
|
32
|
+
else
|
33
|
+
_scope, klass, block_node = *node
|
34
|
+
klass = klass.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
# This is not to raise error on dynamic assignments like `X = Y = Z = Class.new`.
|
38
|
+
# the block node is as follows if node is X:
|
39
|
+
# `s(:casgn, nil, :Y, s(:casgn, nil, :Z, s(:block, ...`
|
40
|
+
# Similarly the block node is `:X` as follows if node is Y.
|
41
|
+
next unless block_node.respond_to?(:class_definition?) && block_node.class_definition?
|
42
|
+
|
43
|
+
# NOTE: klass doesn't have a namespace.
|
44
|
+
# Only supports namepaces in `class A; end` case.
|
45
|
+
if klass
|
46
|
+
@score_hash.store(klass, calculate(block_node)) if klass
|
47
|
+
else
|
48
|
+
@score_hash.store(build_namespace(block_node), calculate(block_node))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
@score_hash
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def calculate(node)
|
58
|
+
# node.body.line_count doesn't include comments after definition of a class.
|
59
|
+
# Don't use nonempty_lines. Empty lines are considered on only the node.
|
60
|
+
count = node.line_count - 2
|
61
|
+
|
62
|
+
count - line_count_of_inner_nodes(node) - comment_line_count(node) - empty_line_count(node)
|
63
|
+
end
|
64
|
+
|
65
|
+
def body_lines(node)
|
66
|
+
(node.first_line..node.last_line).to_a - descendant_class_lines(node)
|
67
|
+
end
|
68
|
+
|
69
|
+
def descendant_class_lines(node)
|
70
|
+
# A class may have multiple inner classes seperately.
|
71
|
+
# So it needs to store all descendant classes line ranges.
|
72
|
+
node.each_descendant(:class, :module).map do |desendant|
|
73
|
+
# To make easier to compare and consider inner nodes, change array of line range into an array of line numbers.
|
74
|
+
(desendant.first_line..desendant.last_line).to_a
|
75
|
+
end.flatten.uniq
|
76
|
+
end
|
77
|
+
|
78
|
+
def empty_line_count(node)
|
79
|
+
empty_lines = @ps.lines.filter_map.with_index { |line, i| i + 1 if line.empty? }
|
80
|
+
(empty_lines & body_lines(node)).size
|
81
|
+
end
|
82
|
+
|
83
|
+
def line_count_of_inner_nodes(node)
|
84
|
+
line_numbers = node.each_descendant(:class, :module).map do |descendant|
|
85
|
+
(descendant.first_line..descendant.last_line).to_a
|
86
|
+
end.flatten.uniq
|
87
|
+
|
88
|
+
line_numbers.size
|
89
|
+
end
|
90
|
+
|
91
|
+
# Only counts the comment of the class or module of a node.
|
92
|
+
# Because `#line_count_of_inner_nodes` only considers the first inner node,
|
93
|
+
# the second or later inner nodes' commments are not necesarry to be counted.
|
94
|
+
def comment_line_count(node)
|
95
|
+
node_range = node.first_line...node.last_line
|
96
|
+
comment_lines = @ps.comments.map { |comment| comment.loc.line }
|
97
|
+
# The latter condition considers a class ouside or above the node.
|
98
|
+
comment_lines.select { |cl| !descendant_class_lines(node).include?(cl) && node_range.include?(cl) }.count
|
99
|
+
end
|
100
|
+
|
101
|
+
def build_namespace(node)
|
102
|
+
self_name = name_with_ns(node)
|
103
|
+
|
104
|
+
return self_name if node.each_ancestor(:class, :module).to_a.empty?
|
105
|
+
|
106
|
+
full_name = self_name.dup
|
107
|
+
node.each_ancestor(:class, :module) do |ancestor|
|
108
|
+
full_name = "#{name_with_ns(ancestor)}::#{full_name}"
|
109
|
+
end
|
110
|
+
full_name
|
111
|
+
end
|
112
|
+
|
113
|
+
def name_with_ns(node)
|
114
|
+
ns = node.children.first&.namespace&.source
|
115
|
+
if ns.nil?
|
116
|
+
node.children.first&.short_name.to_s
|
117
|
+
else
|
118
|
+
node.children.first.namespace.source + "::#{node.children.first.short_name}"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -10,18 +10,20 @@ module CodeKeeper
|
|
10
10
|
CONSIDERED_NODES = %i[if while until for csend block block_pass rescue when and or or_asgnand_asgn].freeze
|
11
11
|
|
12
12
|
def initialize(file_path)
|
13
|
-
|
13
|
+
@path = file_path
|
14
|
+
ps = Parser.parse(@path)
|
14
15
|
@body = ps.ast
|
15
16
|
end
|
16
17
|
|
17
18
|
# returns score of cyclomatic complexity
|
18
19
|
def score
|
19
|
-
@body.each_node(:lvasgn, *CONSIDERED_NODES).reduce(1) do |score, node|
|
20
|
+
final_score = @body.each_node(:lvasgn, *CONSIDERED_NODES).reduce(1) do |score, node|
|
20
21
|
next score if !iterating_block?(node) || node.lvasgn_type?
|
21
22
|
next score if node.csend_type? && discount_for_repeated_csend?(node)
|
22
23
|
|
23
24
|
next 1 + score
|
24
25
|
end
|
26
|
+
{ "#{@path}": final_score }
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
data/lib/code_keeper/metrics.rb
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'code_keeper/metrics/abc_metric'
|
3
4
|
require 'code_keeper/metrics/cyclomatic_complexity'
|
5
|
+
require 'code_keeper/metrics/class_length'
|
4
6
|
|
5
7
|
module CodeKeeper
|
6
8
|
# Manage config values of metrics and the correspond classes
|
7
9
|
module Metrics
|
8
|
-
MAPPINGS = {
|
10
|
+
MAPPINGS = {
|
11
|
+
abc_metric: CodeKeeper::Metrics::AbcMetric,
|
12
|
+
cyclomatic_complexity: CodeKeeper::Metrics::CyclomaticComplexity,
|
13
|
+
class_length: CodeKeeper::Metrics::ClassLength
|
14
|
+
}.freeze
|
9
15
|
end
|
10
16
|
end
|
data/lib/code_keeper/parser.rb
CHANGED
@@ -7,7 +7,7 @@ module CodeKeeper
|
|
7
7
|
|
8
8
|
def initialize(file_path)
|
9
9
|
source = File.read(File.expand_path(file_path))
|
10
|
-
@processed_source = ::RuboCop::AST::ProcessedSource.new(source,
|
10
|
+
@processed_source = ::RuboCop::AST::ProcessedSource.new(source, RUBY_VERSION.to_f)
|
11
11
|
rescue Errno::ENOENT
|
12
12
|
raise TargetFileNotFoundError, "The target file does not exist. Check the file path: #{file_path}."
|
13
13
|
end
|
data/lib/code_keeper/result.rb
CHANGED
@@ -9,8 +9,8 @@ module CodeKeeper
|
|
9
9
|
@scores = CodeKeeper.config.metrics.map { |key| [key, {}] }.to_h
|
10
10
|
end
|
11
11
|
|
12
|
-
def add(metric,
|
13
|
-
scores[:"#{metric}"].store(
|
12
|
+
def add(metric, klass_or_path, score)
|
13
|
+
scores[:"#{metric}"].store(klass_or_path, score)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
data/lib/code_keeper/scorer.rb
CHANGED
@@ -14,20 +14,27 @@ module CodeKeeper
|
|
14
14
|
# `in_threads: 1` makes 2 threads, a sleep_forever thread and the main thread.
|
15
15
|
if num_threads == 1
|
16
16
|
ruby_file_paths.each do |path|
|
17
|
-
metrics.each
|
18
|
-
result.add(:cyclomatic_complexity, path, ::CodeKeeper::Metrics::MAPPINGS[metric].new(path).score)
|
19
|
-
end
|
17
|
+
metrics.each { |metric| calculate_score(metric, path, result) }
|
20
18
|
end
|
21
19
|
else
|
22
20
|
Parallel.map(ruby_file_paths, in_threads: num_threads) do |path|
|
23
|
-
metrics.each
|
24
|
-
result.add(:cyclomatic_complexity, path, ::CodeKeeper::Metrics::MAPPINGS[metric].new(path).score)
|
25
|
-
end
|
21
|
+
metrics.each { |metric| calculate_score(metric, path, result) }
|
26
22
|
end
|
27
23
|
end
|
28
24
|
|
29
25
|
result
|
30
26
|
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def calculate_score(metric, path, result)
|
31
|
+
score = ::CodeKeeper::Metrics::MAPPINGS[metric].new(path).score
|
32
|
+
|
33
|
+
# The class length metric's score has multiple classes.
|
34
|
+
score.each do |k, v|
|
35
|
+
result.add(metric, k.to_s, v)
|
36
|
+
end
|
37
|
+
end
|
31
38
|
end
|
32
39
|
end
|
33
40
|
end
|
data/lib/code_keeper/version.rb
CHANGED
data/lib/code_keeper.rb
CHANGED
@@ -10,7 +10,9 @@ require 'code_keeper/config'
|
|
10
10
|
require 'code_keeper/scorer'
|
11
11
|
require 'code_keeper/result'
|
12
12
|
require 'code_keeper/metrics'
|
13
|
+
require 'code_keeper/metrics/abc_metric'
|
13
14
|
require 'code_keeper/metrics/cyclomatic_complexity'
|
15
|
+
require 'code_keeper/metrics/class_length'
|
14
16
|
|
15
17
|
module CodeKeeper
|
16
18
|
class << self
|
metadata
CHANGED
@@ -1,57 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: code_keeper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yusuke Ebihara
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parallel
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.20.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.20.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rubocop
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
33
|
+
version: 1.13.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
40
|
+
version: 1.13.0
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rubocop-ast
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 1.4.1
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 1.4.1
|
55
55
|
description: The CodeKeeper measures metrics especially about complexity and size
|
56
56
|
of Ruby files, aiming to be a Ruby version of gmetrics.
|
57
57
|
email:
|
@@ -65,9 +65,9 @@ files:
|
|
65
65
|
- ".gitignore"
|
66
66
|
- ".rspec"
|
67
67
|
- ".rubocop.yml"
|
68
|
+
- CHANGELOG.md
|
68
69
|
- CODE_OF_CONDUCT.md
|
69
70
|
- Gemfile
|
70
|
-
- Gemfile.lock
|
71
71
|
- LICENSE.txt
|
72
72
|
- README.md
|
73
73
|
- Rakefile
|
@@ -81,6 +81,8 @@ files:
|
|
81
81
|
- lib/code_keeper/finder.rb
|
82
82
|
- lib/code_keeper/formatter.rb
|
83
83
|
- lib/code_keeper/metrics.rb
|
84
|
+
- lib/code_keeper/metrics/abc_metric.rb
|
85
|
+
- lib/code_keeper/metrics/class_length.rb
|
84
86
|
- lib/code_keeper/metrics/cyclomatic_complexity.rb
|
85
87
|
- lib/code_keeper/parser.rb
|
86
88
|
- lib/code_keeper/result.rb
|
@@ -101,7 +103,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
101
103
|
requirements:
|
102
104
|
- - ">="
|
103
105
|
- !ruby/object:Gem::Version
|
104
|
-
version:
|
106
|
+
version: 2.7.0
|
105
107
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
108
|
requirements:
|
107
109
|
- - ">="
|
data/Gemfile.lock
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
code_keeper (0.1.0)
|
5
|
-
parallel
|
6
|
-
rubocop
|
7
|
-
rubocop-ast
|
8
|
-
|
9
|
-
GEM
|
10
|
-
remote: https://rubygems.org/
|
11
|
-
specs:
|
12
|
-
ast (2.4.2)
|
13
|
-
coderay (1.1.3)
|
14
|
-
diff-lcs (1.4.4)
|
15
|
-
method_source (0.9.2)
|
16
|
-
parallel (1.20.1)
|
17
|
-
parser (3.0.1.0)
|
18
|
-
ast (~> 2.4.1)
|
19
|
-
pry (0.12.2)
|
20
|
-
coderay (~> 1.1.0)
|
21
|
-
method_source (~> 0.9.0)
|
22
|
-
pry-nav (0.3.0)
|
23
|
-
pry (>= 0.9.10, < 0.13.0)
|
24
|
-
rainbow (3.0.0)
|
25
|
-
rake (13.0.3)
|
26
|
-
regexp_parser (2.1.1)
|
27
|
-
rexml (3.2.5)
|
28
|
-
rspec (3.10.0)
|
29
|
-
rspec-core (~> 3.10.0)
|
30
|
-
rspec-expectations (~> 3.10.0)
|
31
|
-
rspec-mocks (~> 3.10.0)
|
32
|
-
rspec-core (3.10.1)
|
33
|
-
rspec-support (~> 3.10.0)
|
34
|
-
rspec-expectations (3.10.1)
|
35
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
36
|
-
rspec-support (~> 3.10.0)
|
37
|
-
rspec-mocks (3.10.2)
|
38
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
39
|
-
rspec-support (~> 3.10.0)
|
40
|
-
rspec-support (3.10.2)
|
41
|
-
rubocop (1.13.0)
|
42
|
-
parallel (~> 1.10)
|
43
|
-
parser (>= 3.0.0.0)
|
44
|
-
rainbow (>= 2.2.2, < 4.0)
|
45
|
-
regexp_parser (>= 1.8, < 3.0)
|
46
|
-
rexml
|
47
|
-
rubocop-ast (>= 1.2.0, < 2.0)
|
48
|
-
ruby-progressbar (~> 1.7)
|
49
|
-
unicode-display_width (>= 1.4.0, < 3.0)
|
50
|
-
rubocop-ast (1.4.1)
|
51
|
-
parser (>= 2.7.1.5)
|
52
|
-
ruby-progressbar (1.11.0)
|
53
|
-
unicode-display_width (2.0.0)
|
54
|
-
|
55
|
-
PLATFORMS
|
56
|
-
x86_64-linux
|
57
|
-
|
58
|
-
DEPENDENCIES
|
59
|
-
code_keeper!
|
60
|
-
parallel
|
61
|
-
pry
|
62
|
-
pry-nav
|
63
|
-
rake (~> 13.0)
|
64
|
-
rspec (~> 3.0)
|
65
|
-
rubocop
|
66
|
-
rubocop-ast
|
67
|
-
|
68
|
-
BUNDLED WITH
|
69
|
-
2.2.3
|