skunk 0.3.1 → 0.5.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/.github/ISSUE_TEMPLATE/bug_report.md +53 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +47 -0
- data/.github/workflows/main.yml +89 -0
- data/.github/workflows/skunk.yml +29 -0
- data/.gitignore +1 -0
- data/.reek.yml +18 -13
- data/.rubocop_todo.yml +39 -17
- data/CHANGELOG.md +41 -6
- data/CODEOWNERS +5 -0
- data/Gemfile-Ruby-2-4 +10 -0
- data/README.md +78 -25
- data/fastruby-logo.png +0 -0
- data/lib/skunk.rb +1 -1
- data/lib/skunk/cli/application.rb +41 -6
- data/lib/skunk/cli/commands/base.rb +2 -0
- data/lib/skunk/cli/commands/compare.rb +12 -6
- data/lib/skunk/cli/commands/compare_score.rb +39 -0
- data/lib/skunk/cli/commands/default.rb +22 -1
- data/lib/skunk/cli/commands/help.rb +12 -1
- data/lib/skunk/cli/commands/output.rb +12 -0
- data/lib/skunk/cli/commands/status_reporter.rb +25 -18
- data/lib/skunk/cli/commands/status_sharer.rb +100 -0
- data/lib/skunk/cli/commands/version.rb +16 -0
- data/lib/skunk/cli/options.rb +26 -2
- data/lib/skunk/cli/options/argv.rb +45 -0
- data/lib/skunk/rubycritic/analysed_module.rb +30 -10
- data/lib/skunk/rubycritic/analysed_modules_collection.rb +2 -2
- data/lib/skunk/version.rb +1 -1
- data/logo.png +0 -0
- data/samples/engines/spec/nested_sample_spec.rb +5 -0
- data/samples/rubycritic/analysed_module.rb +9 -9
- data/skunk.gemspec +14 -8
- metadata +105 -30
- data/.travis.yml +0 -5
- data/Gemfile.lock +0 -119
- data/bin/console +0 -16
- data/bin/setup +0 -8
data/README.md
CHANGED
@@ -1,25 +1,27 @@
|
|
1
1
|
# Skunk
|
2
2
|
|
3
|
-
|
3
|
+

|
4
4
|
|
5
|
-
|
5
|
+
[](CODE_OF_CONDUCT.md) [](https://travis-ci.org/fastruby/skunk) [](https://codeclimate.com/github/fastruby/skunk/maintainability) [](http://rubydoc.info/gems/skunk) [](https://codecov.io/gh/fastruby/skunk)
|
6
6
|
|
7
|
-
|
7
|
+
A RubyCritic extension to calculate SkunkScore for a file or project.
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
## What is the SkunkScore?
|
10
|
+
|
11
|
+
The SkunkScore is a value that assesses the technical debt of a module. It takes
|
12
|
+
into account:
|
11
13
|
|
12
14
|
- Code Complexity
|
13
15
|
- Code Smells
|
14
16
|
- Code Coverage
|
15
17
|
|
16
|
-
The main goal of the
|
18
|
+
The main goal of the SkunkScore is to serve as a compass in your next
|
17
19
|
refactoring adventure. It will help you answer these questions:
|
18
20
|
|
19
21
|
- What can I do to pay off technical debt?
|
20
22
|
- What are the most complicated files with the least code coverage?
|
21
23
|
- What are good candidates for your next test-writing efforts?
|
22
|
-
- What are good candidates for your
|
24
|
+
- What are good candidates for your next refactoring efforts?
|
23
25
|
|
24
26
|
The formula is not perfect and it is certainly controversial, so any feedback is
|
25
27
|
welcome as a new issue!
|
@@ -42,7 +44,20 @@ Or install it yourself as:
|
|
42
44
|
|
43
45
|
## Usage
|
44
46
|
|
45
|
-
###
|
47
|
+
### Help details
|
48
|
+
|
49
|
+
There are not that many options but here they are:
|
50
|
+
|
51
|
+
```
|
52
|
+
skunk -h
|
53
|
+
Usage: skunk [options] [paths]
|
54
|
+
-b, --branch BRANCH Set branch to compare
|
55
|
+
-o, --out FILE Output report to file
|
56
|
+
-v, --version Show gem's version
|
57
|
+
-h, --help Show this message
|
58
|
+
```
|
59
|
+
|
60
|
+
### Getting a sorted list of smelly files
|
46
61
|
|
47
62
|
To get the best results, make sure that you have `coverage/.resultset.json` in
|
48
63
|
your application directory. That way `skunk` knows what's the status of your
|
@@ -54,13 +69,10 @@ Then simply run:
|
|
54
69
|
skunk
|
55
70
|
```
|
56
71
|
|
57
|
-
Then get a list of
|
72
|
+
Then get a list of smelly files:
|
58
73
|
|
59
74
|
```
|
60
75
|
$ skunk
|
61
|
-
warning: parser/current is loading parser/ruby26, which recognizes
|
62
|
-
warning: 2.6.5-compliant syntax, but you are running 2.6.2.
|
63
|
-
warning: please see https://github.com/whitequark/parser#compatibility-with-ruby-mri.
|
64
76
|
running flay smells
|
65
77
|
|
66
78
|
running flog smells
|
@@ -77,7 +89,7 @@ running simple_cov
|
|
77
89
|
.............
|
78
90
|
New critique at file:////Users/etagwerker/Projects/fastruby/skunk/tmp/rubycritic/overview.html
|
79
91
|
+-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+
|
80
|
-
| file |
|
92
|
+
| file | skunk_score | churn_times_cost | churn | cost | coverage |
|
81
93
|
+-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+
|
82
94
|
| lib/skunk/cli/commands/default.rb | 166.44 | 1.6643999999999999 | 3 | 0.5548 | 0 |
|
83
95
|
| lib/skunk/cli/application.rb | 139.2 | 1.392 | 3 | 0.46399999999999997 | 0 |
|
@@ -94,14 +106,14 @@ New critique at file:////Users/etagwerker/Projects/fastruby/skunk/tmp/rubycritic
|
|
94
106
|
| lib/skunk/cli/commands/help.rb | 0.0 | 0.0 | 2 | 0.0 | 0 |
|
95
107
|
+-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+
|
96
108
|
|
97
|
-
|
109
|
+
SkunkScore Total: 612.31
|
98
110
|
Modules Analysed: 13
|
99
|
-
|
100
|
-
Worst
|
111
|
+
SkunkScore Average: 0.47100769230769230769230769231e2
|
112
|
+
Worst SkunkScore: 166.44 (lib/skunk/cli/commands/default.rb)
|
101
113
|
```
|
102
114
|
|
103
115
|
The command will run `rubycritic` and it will try to load code coverage data
|
104
|
-
from your
|
116
|
+
from your `coverage/.resultset.json` file.
|
105
117
|
|
106
118
|
Skunk's report will be in the console. Use it wisely. :)
|
107
119
|
|
@@ -113,7 +125,7 @@ Simply run:
|
|
113
125
|
skunk -b <target-branch-name>
|
114
126
|
```
|
115
127
|
|
116
|
-
Then get a
|
128
|
+
Then get a SkunkScore average comparison:
|
117
129
|
|
118
130
|
```
|
119
131
|
$ skunk -b master
|
@@ -147,28 +159,63 @@ running churn
|
|
147
159
|
.................
|
148
160
|
running simple_cov
|
149
161
|
.................
|
150
|
-
Base branch (master) average
|
151
|
-
Feature branch (feature/compare) average
|
162
|
+
Base branch (master) average skunk score: 290.53999999999996
|
163
|
+
Feature branch (feature/compare) average skunk score: 340.3005882352941
|
152
164
|
Score: 340.3
|
153
165
|
```
|
154
166
|
|
155
167
|
This should give you an idea if you're moving in the right direction or not.
|
156
168
|
|
169
|
+
### Sharing results
|
170
|
+
|
171
|
+
If you want to quickly share the results of your report, you can use an
|
172
|
+
environment variable:
|
173
|
+
|
174
|
+
```
|
175
|
+
SHARE=true skunk app/
|
176
|
+
...
|
177
|
+
SkunkScore Total: 126.99
|
178
|
+
Modules Analysed: 17
|
179
|
+
SkunkScore Average: 7.47
|
180
|
+
Worst SkunkScore: 41.92 (lib/skunk/cli/commands/status_sharer.rb)
|
181
|
+
|
182
|
+
Generated with Skunk v0.5.0
|
183
|
+
Shared at: https://skunk.fastruby.io/k
|
184
|
+
```
|
185
|
+
|
186
|
+
Results will be posted by default to https://skunk.fastruby.io which is a free
|
187
|
+
and open source Ruby on Rails application sponsored by
|
188
|
+
[OmbuLabs](https://www.ombulabs.com) ([source code](https://github.com/fastruby/skunk.fyi)).
|
189
|
+
|
190
|
+
If you prefer to post results to your own server, you can do so:
|
191
|
+
|
192
|
+
```
|
193
|
+
SHARE_URL=https://path.to.your.skunk-fyi-server.example.com skunk app/
|
194
|
+
...
|
195
|
+
SkunkScore Total: 126.99
|
196
|
+
Modules Analysed: 17
|
197
|
+
SkunkScore Average: 7.47
|
198
|
+
Worst SkunkScore: 41.92 (lib/skunk/cli/commands/status_sharer.rb)
|
199
|
+
|
200
|
+
Generated with Skunk v0.5.0
|
201
|
+
Shared at: https://path.to.your.skunk-fyi-server.example.com/k
|
202
|
+
```
|
203
|
+
|
157
204
|
## Known Issues
|
158
205
|
|
159
|
-
The
|
160
|
-
representation of the average
|
206
|
+
The SkunkScore should be calculated per method. This would provide a more accurate
|
207
|
+
representation of the average SkunkScore in a module.
|
161
208
|
|
162
|
-
I think that the
|
209
|
+
I think that the SkunkScore of a module should be the average of the SkunkScores of
|
163
210
|
all of its methods.
|
164
211
|
|
165
|
-
Right now the
|
212
|
+
Right now the SkunkScore is calculated using the totals for a module:
|
166
213
|
|
167
214
|
- Total Code Coverage Percentage per Module
|
168
215
|
- Total Churn per Module
|
169
216
|
- Total Cost per Module
|
170
217
|
|
171
|
-
For more details, feel free to review and improve this method: [RubyCritic::AnalysedModule#
|
218
|
+
For more details, feel free to review and improve this method: [RubyCritic::AnalysedModule#skunk_score]
|
172
219
|
|
173
220
|
## Development
|
174
221
|
|
@@ -179,3 +226,9 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
179
226
|
## Contributing
|
180
227
|
|
181
228
|
Bug reports and pull requests are welcome on GitHub at https://github.com/fastruby/skunk/issues.
|
229
|
+
|
230
|
+
## Sponsorship
|
231
|
+
|
232
|
+

|
233
|
+
|
234
|
+
`skunk` is maintained and funded by [FastRuby.io](https://fastruby.io). The names and logos for FastRuby.io are trademarks of The Lean Software Boutique LLC.
|
data/fastruby-logo.png
ADDED
Binary file
|
data/lib/skunk.rb
CHANGED
@@ -1,25 +1,60 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "rubycritic/cli/options"
|
4
|
+
require "rubycritic/cli/application"
|
5
|
+
|
3
6
|
require "skunk"
|
4
7
|
require "skunk/rubycritic/analysed_module"
|
5
8
|
require "skunk/cli/options"
|
6
9
|
require "skunk/cli/command_factory"
|
7
|
-
|
8
|
-
require "rubycritic/cli/application"
|
10
|
+
require "skunk/cli/commands/status_sharer"
|
9
11
|
|
10
12
|
module Skunk
|
11
13
|
module Cli
|
12
14
|
# Knows how to execute command line commands
|
15
|
+
# :reek:InstanceVariableAssumption
|
13
16
|
class Application < RubyCritic::Cli::Application
|
17
|
+
COVERAGE_FILE = "coverage/.resultset.json"
|
18
|
+
|
19
|
+
def initialize(argv)
|
20
|
+
@options = Skunk::Cli::Options.new(argv)
|
21
|
+
end
|
22
|
+
|
23
|
+
# :reek:UncommunicativeVariableName
|
14
24
|
def execute
|
15
|
-
|
16
|
-
|
25
|
+
warn_coverage_info unless File.exist?(COVERAGE_FILE)
|
26
|
+
|
27
|
+
# :reek:NilCheck
|
28
|
+
@parsed_options = @options.parse.to_h
|
29
|
+
command = Skunk::Cli::CommandFactory.create(@parsed_options)
|
30
|
+
reporter = command.execute
|
31
|
+
|
17
32
|
print(reporter.status_message)
|
33
|
+
share_status_message = command.share(reporter)
|
34
|
+
print(share_status_message)
|
35
|
+
|
18
36
|
reporter.status
|
19
|
-
rescue OptionParser::InvalidOption =>
|
20
|
-
warn "Error: #{
|
37
|
+
rescue OptionParser::InvalidOption => e
|
38
|
+
warn "Error: #{e}"
|
21
39
|
STATUS_ERROR
|
22
40
|
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def warn_coverage_info
|
45
|
+
warn "warning: Couldn't find coverage info at #{COVERAGE_FILE}."
|
46
|
+
warn "warning: Having no coverage metrics will make your SkunkScore worse."
|
47
|
+
end
|
48
|
+
|
49
|
+
# :reek:NilCheck
|
50
|
+
def print(message)
|
51
|
+
filename = @parsed_options[:output_filename]
|
52
|
+
if filename.nil?
|
53
|
+
$stdout.puts(message)
|
54
|
+
else
|
55
|
+
File.open(filename, "a") { |file| file << message }
|
56
|
+
end
|
57
|
+
end
|
23
58
|
end
|
24
59
|
end
|
25
60
|
end
|
@@ -2,17 +2,19 @@
|
|
2
2
|
|
3
3
|
require "rubycritic/commands/compare"
|
4
4
|
require "skunk/rubycritic/analysed_modules_collection"
|
5
|
+
require "skunk/cli/commands/output"
|
6
|
+
require "skunk/cli/commands/compare_score"
|
5
7
|
|
6
8
|
# nodoc #
|
7
9
|
module Skunk
|
8
10
|
module Command
|
9
|
-
# Knows how to compare two branches and their
|
11
|
+
# Knows how to compare two branches and their skunk score average
|
10
12
|
class Compare < RubyCritic::Command::Compare
|
11
13
|
# switch branch and analyse files but don't generate a report
|
12
14
|
def analyse_branch(branch)
|
13
15
|
::RubyCritic::SourceControlSystem::Git.switch_branch(::RubyCritic::Config.send(branch))
|
14
16
|
critic = critique(branch)
|
15
|
-
::RubyCritic::Config.send(:"#{branch}_score=", critic.
|
17
|
+
::RubyCritic::Config.send(:"#{branch}_score=", critic.skunk_score_average)
|
16
18
|
::RubyCritic::Config.root = branch_directory(branch)
|
17
19
|
end
|
18
20
|
|
@@ -28,10 +30,14 @@ module Skunk
|
|
28
30
|
|
29
31
|
# create a txt file with the branch score details
|
30
32
|
def build_details
|
31
|
-
details =
|
32
|
-
|
33
|
-
|
34
|
-
|
33
|
+
details = CompareScore.new(
|
34
|
+
::RubyCritic::Config.base_branch,
|
35
|
+
::RubyCritic::Config.feature_branch,
|
36
|
+
::RubyCritic::Config.base_branch_score.to_f.round(2),
|
37
|
+
::RubyCritic::Config.feature_branch_score.to_f.round(2)
|
38
|
+
).message
|
39
|
+
|
40
|
+
Skunk::Command::Output.create_directory(::RubyCritic::Config.compare_root_directory)
|
35
41
|
File.open(build_details_path, "w") { |file| file.write(details) }
|
36
42
|
puts details
|
37
43
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# nodoc #
|
4
|
+
module Skunk
|
5
|
+
module Command
|
6
|
+
# Knows how to describe score evolution between two branches
|
7
|
+
class CompareScore
|
8
|
+
def initialize(base_branch, feature_branch, base_branch_score, feature_branch_score)
|
9
|
+
@base_branch = base_branch
|
10
|
+
@feature_branch = feature_branch
|
11
|
+
@base_branch_score = base_branch_score
|
12
|
+
@feature_branch_score = feature_branch_score
|
13
|
+
end
|
14
|
+
|
15
|
+
def message
|
16
|
+
"Base branch (#{@base_branch}) "\
|
17
|
+
"average skunk score: #{@base_branch_score} \n"\
|
18
|
+
"Feature branch (#{@feature_branch}) "\
|
19
|
+
"average skunk score: #{@feature_branch_score} \n"\
|
20
|
+
"#{score_evolution_message}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def score_evolution_message
|
24
|
+
"Skunk score average is #{score_evolution} #{score_evolution_appreciation} \n"
|
25
|
+
end
|
26
|
+
|
27
|
+
def score_evolution_appreciation
|
28
|
+
@feature_branch_score > @base_branch_score ? "worse" : "better"
|
29
|
+
end
|
30
|
+
|
31
|
+
def score_evolution
|
32
|
+
return "Infinitely" if @base_branch_score.zero?
|
33
|
+
|
34
|
+
precentage = (100 * (@base_branch_score - @feature_branch_score) / @base_branch_score)
|
35
|
+
"#{precentage.round(0).abs}%"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -16,20 +16,41 @@ module Skunk
|
|
16
16
|
class Default < RubyCritic::Command::Default
|
17
17
|
def initialize(options)
|
18
18
|
super
|
19
|
-
@
|
19
|
+
@options = options
|
20
|
+
@status_reporter = Skunk::Command::StatusReporter.new(options)
|
20
21
|
end
|
21
22
|
|
23
|
+
# It generates a report and it returns an instance of
|
24
|
+
# Skunk::Command::StatusReporter
|
25
|
+
#
|
26
|
+
# @return [Skunk::Command::StatusReporter]
|
22
27
|
def execute
|
23
28
|
RubyCritic::Config.formats = []
|
24
29
|
|
25
30
|
report(critique)
|
31
|
+
|
26
32
|
status_reporter
|
27
33
|
end
|
28
34
|
|
35
|
+
# It connects the Skunk::Command::StatusReporter with the collection
|
36
|
+
# of analysed modules.
|
37
|
+
#
|
38
|
+
# @param [RubyCritic::AnalysedModulesCollection] A collection of analysed modules
|
29
39
|
def report(analysed_modules)
|
30
40
|
status_reporter.analysed_modules = analysed_modules
|
31
41
|
status_reporter.score = analysed_modules.score
|
32
42
|
end
|
43
|
+
|
44
|
+
# It shares the report using SHARE_URL or https://skunk.fastruby.io. It
|
45
|
+
# will post all results in JSON format and return a status message.
|
46
|
+
#
|
47
|
+
# @param [Skunk::Command::StatusReporter] A status reporter with analysed modules
|
48
|
+
# :reek:FeatureEnvy
|
49
|
+
def share(reporter)
|
50
|
+
sharer = Skunk::Command::StatusSharer.new(@options)
|
51
|
+
sharer.status_reporter = reporter
|
52
|
+
sharer.share
|
53
|
+
end
|
33
54
|
end
|
34
55
|
end
|
35
56
|
end
|
@@ -1,11 +1,22 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "skunk/cli/commands/base"
|
4
|
+
require "rubycritic/commands/help"
|
4
5
|
|
5
6
|
module Skunk
|
6
7
|
module Cli
|
7
8
|
module Command
|
8
|
-
|
9
|
+
# Knows how to guide user into using `skunk` properly
|
10
|
+
class Help < Skunk::Cli::Command::Base
|
11
|
+
# Outputs a help message
|
12
|
+
def execute
|
13
|
+
puts options[:help_text]
|
14
|
+
status_reporter
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
attr_reader :options, :status_reporter
|
9
20
|
end
|
10
21
|
end
|
11
22
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Skunk
|
4
|
+
module Command
|
5
|
+
# Implements the needed methods for a successful compare output
|
6
|
+
class Output
|
7
|
+
def self.create_directory(directory)
|
8
|
+
FileUtils.mkdir_p(directory) unless File.exist?(directory)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -10,23 +10,27 @@ module Skunk
|
|
10
10
|
class StatusReporter < RubyCritic::Command::StatusReporter
|
11
11
|
attr_accessor :analysed_modules
|
12
12
|
|
13
|
-
HEADINGS = %w[file
|
13
|
+
HEADINGS = %w[file skunk_score churn_times_cost churn cost coverage].freeze
|
14
|
+
HEADINGS_WITHOUT_FILE = HEADINGS - %w[file]
|
15
|
+
HEADINGS_WITHOUT_FILE_WIDTH = HEADINGS_WITHOUT_FILE.size * 17 # padding
|
14
16
|
|
15
17
|
TEMPLATE = ERB.new(<<-TEMPL
|
16
|
-
<%=
|
17
|
-
|
18
|
+
<%= _ttable %>\n
|
19
|
+
SkunkScore Total: <%= total_skunk_score %>
|
18
20
|
Modules Analysed: <%= analysed_modules_count %>
|
19
|
-
|
20
|
-
<% if worst %>Worst
|
21
|
+
SkunkScore Average: <%= skunk_score_average %>
|
22
|
+
<% if worst %>Worst SkunkScore: <%= worst.skunk_score %> (<%= worst.pathname %>)<% end %>
|
23
|
+
|
24
|
+
Generated with Skunk v<%= Skunk::VERSION %>
|
21
25
|
TEMPL
|
22
26
|
)
|
23
27
|
|
24
28
|
# Returns a status message with a table of all analysed_modules and
|
25
|
-
# a
|
29
|
+
# a skunk score average
|
26
30
|
def update_status_message
|
27
31
|
opts = table_options.merge(headings: HEADINGS, rows: table)
|
28
32
|
|
29
|
-
|
33
|
+
_ttable = Terminal::Table.new(opts)
|
30
34
|
|
31
35
|
@status_message = TEMPLATE.result(binding)
|
32
36
|
end
|
@@ -39,7 +43,8 @@ TEMPL
|
|
39
43
|
|
40
44
|
def non_test_modules
|
41
45
|
@non_test_modules ||= analysed_modules.reject do |a_module|
|
42
|
-
a_module.pathname.to_s
|
46
|
+
module_path = a_module.pathname.dirname.to_s
|
47
|
+
module_path.start_with?("test", "spec") || module_path.end_with?("test", "spec")
|
43
48
|
end
|
44
49
|
end
|
45
50
|
|
@@ -48,27 +53,29 @@ TEMPL
|
|
48
53
|
end
|
49
54
|
|
50
55
|
def sorted_modules
|
51
|
-
@sorted_modules ||= non_test_modules.sort_by(&:
|
56
|
+
@sorted_modules ||= non_test_modules.sort_by(&:skunk_score).reverse!
|
52
57
|
end
|
53
58
|
|
54
|
-
def
|
55
|
-
@
|
59
|
+
def total_skunk_score
|
60
|
+
@total_skunk_score ||= non_test_modules.sum(&:skunk_score)
|
56
61
|
end
|
57
62
|
|
58
63
|
def total_churn_times_cost
|
59
|
-
non_test_modules.
|
64
|
+
non_test_modules.sum(&:churn_times_cost)
|
60
65
|
end
|
61
66
|
|
62
|
-
def
|
67
|
+
def skunk_score_average
|
63
68
|
return 0 if analysed_modules_count.zero?
|
64
69
|
|
65
|
-
(
|
70
|
+
(total_skunk_score.to_d / analysed_modules_count).to_f.round(2)
|
66
71
|
end
|
67
72
|
|
68
73
|
def table_options
|
74
|
+
max = sorted_modules.max_by { |a_mod| a_mod.pathname.to_s.length }
|
75
|
+
width = max.pathname.to_s.length + HEADINGS_WITHOUT_FILE_WIDTH
|
69
76
|
{
|
70
77
|
style: {
|
71
|
-
width:
|
78
|
+
width: width
|
72
79
|
}
|
73
80
|
}
|
74
81
|
end
|
@@ -77,11 +84,11 @@ TEMPL
|
|
77
84
|
sorted_modules.map do |a_mod|
|
78
85
|
[
|
79
86
|
a_mod.pathname,
|
80
|
-
a_mod.
|
87
|
+
a_mod.skunk_score,
|
81
88
|
a_mod.churn_times_cost,
|
82
89
|
a_mod.churn,
|
83
|
-
a_mod.cost,
|
84
|
-
a_mod.coverage
|
90
|
+
a_mod.cost.round(2),
|
91
|
+
a_mod.coverage.round(2)
|
85
92
|
]
|
86
93
|
end
|
87
94
|
end
|