skunk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9792e73da1c20854f3eb7f9f96af486132bf2e2cca8a7f3aadd6038487ec7ef0
4
+ data.tar.gz: 5cb6a6c3bfd1b009db448b3584a7871452753a124540da96d5b448eec20191e2
5
+ SHA512:
6
+ metadata.gz: 333bf77a14154f09e8ed7f205bfc3b93845788da9ac0088e66b2a3269c858184234cd5efa5eec92371ee74d22e568bff86f360d371622f24e446153bd5d7c89b
7
+ data.tar.gz: 997bad01c5e50c8b936f9364e497dbff9f99cff76c352c51f44f43922f4073ae1378d21177f52c786b3555cb09296eb8daed6b492ddbabfe808c2bcecb9db980
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ .byebug_history
11
+
12
+ .ruby-version
data/.reek.yml ADDED
@@ -0,0 +1,28 @@
1
+ # Auto generated by Reeks --todo flag
2
+ ---
3
+ detectors:
4
+ UtilityFunction:
5
+ exclude:
6
+ - capture_output_streams
7
+ InstanceVariableAssumption:
8
+ exclude:
9
+ - Skunk::Cli::Application
10
+ - Skunk::Cli::Command::Default
11
+ IrresponsibleModule:
12
+ exclude:
13
+ - Skunk::Cli::Application
14
+ - Skunk::Cli::Command::Default
15
+ - Skunk::Cli::Command::Help
16
+ - Skunk::Command::StatusReporter
17
+ - Skunk::Cli::Options
18
+ - RubyCritic::AnalysedModule
19
+ TooManyStatements:
20
+ exclude:
21
+ - initialize
22
+ - Skunk::Cli::Application#execute
23
+ Attribute:
24
+ exclude:
25
+ - Skunk::Command::StatusReporter#analysed_modules
26
+ FeatureEnvy:
27
+ exclude:
28
+ - Skunk::Command::StatusReporter#table
data/.rubocop.yml ADDED
@@ -0,0 +1,4 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ Style/StringLiterals:
4
+ EnforcedStyle: double_quotes
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,27 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config --exclude-limit 500`
3
+ # on 2019-10-15 15:20:00 -0400 using RuboCop version 0.75.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Configuration parameters: CountComments, ExcludedMethods.
11
+ # ExcludedMethods: refine
12
+ Metrics/BlockLength:
13
+ Max: 34
14
+
15
+ # Offense count: 1
16
+ # Cop supports --auto-correct.
17
+ # Configuration parameters: PreferredName.
18
+ Naming/RescuedExceptionsVariableName:
19
+ Exclude:
20
+ - 'lib/skunk/cli/application.rb'
21
+
22
+ # Offense count: 8
23
+ # Cop supports --auto-correct.
24
+ # Configuration parameters: AutoCorrect, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
25
+ # URISchemes: http, https
26
+ Metrics/LineLength:
27
+ Max: 107
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
+
7
+ # Specify your gem's dependencies in skunk.gemspec
8
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,119 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ skunk (0.1.0)
5
+ rubycritic-simplecov (~> 4.1.1)
6
+ terminal-table (~> 1.8.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ addressable (2.7.0)
12
+ public_suffix (>= 2.0.2, < 5.0)
13
+ ansi (1.5.0)
14
+ ast (2.4.0)
15
+ axiom-types (0.1.1)
16
+ descendants_tracker (~> 0.0.4)
17
+ ice_nine (~> 0.11.0)
18
+ thread_safe (~> 0.3, >= 0.3.1)
19
+ byebug (11.0.1)
20
+ codeclimate-engine-rb (0.4.1)
21
+ virtus (~> 1.0)
22
+ coercible (1.0.0)
23
+ descendants_tracker (~> 0.0.1)
24
+ descendants_tracker (0.0.4)
25
+ thread_safe (~> 0.3, >= 0.3.1)
26
+ docile (1.3.2)
27
+ equalizer (0.0.11)
28
+ erubis (2.7.0)
29
+ flay (2.12.1)
30
+ erubis (~> 2.7.0)
31
+ path_expander (~> 1.0)
32
+ ruby_parser (~> 3.0)
33
+ sexp_processor (~> 4.0)
34
+ flog (4.6.3)
35
+ path_expander (~> 1.0)
36
+ ruby_parser (~> 3.1, > 3.1.0)
37
+ sexp_processor (~> 4.8)
38
+ ice_nine (0.11.2)
39
+ jaro_winkler (1.5.3)
40
+ json (2.2.0)
41
+ kwalify (0.7.2)
42
+ launchy (2.4.3)
43
+ addressable (~> 2.3)
44
+ minitest (5.8.5)
45
+ minitest-around (0.5.0)
46
+ minitest (~> 5.0)
47
+ parallel (1.18.0)
48
+ parser (2.6.5.0)
49
+ ast (~> 2.4.0)
50
+ path_expander (1.1.0)
51
+ psych (3.1.0)
52
+ public_suffix (4.0.1)
53
+ rainbow (3.0.0)
54
+ rake (10.5.0)
55
+ reek (5.4.0)
56
+ codeclimate-engine-rb (~> 0.4.0)
57
+ kwalify (~> 0.7.0)
58
+ parser (>= 2.5.0.0, < 2.7, != 2.5.1.1)
59
+ psych (~> 3.1.0)
60
+ rainbow (>= 2.0, < 4.0)
61
+ rubocop (0.75.1)
62
+ jaro_winkler (~> 1.5.1)
63
+ parallel (~> 1.10)
64
+ parser (>= 2.6)
65
+ rainbow (>= 2.2.2, < 4.0)
66
+ ruby-progressbar (~> 1.7)
67
+ unicode-display_width (>= 1.4.0, < 1.7)
68
+ ruby-progressbar (1.10.1)
69
+ ruby_parser (3.14.0)
70
+ sexp_processor (~> 4.9)
71
+ rubycritic-simplecov (4.1.1)
72
+ flay (~> 2.8)
73
+ flog (~> 4.4)
74
+ launchy (= 2.4.3)
75
+ parser (~> 2.6.0)
76
+ rainbow (~> 3.0)
77
+ reek (~> 5.0, < 6.0)
78
+ ruby_parser (~> 3.8)
79
+ simplecov (~> 0.17.0)
80
+ tty-which (~> 0.4.0)
81
+ virtus (~> 1.0)
82
+ sexp_processor (4.13.0)
83
+ simplecov (0.17.1)
84
+ docile (~> 1.1)
85
+ json (>= 1.8, < 3)
86
+ simplecov-html (~> 0.10.0)
87
+ simplecov-console (0.5.0)
88
+ ansi
89
+ simplecov
90
+ terminal-table
91
+ simplecov-html (0.10.2)
92
+ terminal-table (1.8.0)
93
+ unicode-display_width (~> 1.1, >= 1.1.1)
94
+ thread_safe (0.3.6)
95
+ tty-which (0.4.1)
96
+ unicode-display_width (1.6.0)
97
+ virtus (1.0.5)
98
+ axiom-types (~> 0.1)
99
+ coercible (~> 1.0)
100
+ descendants_tracker (~> 0.0, >= 0.0.3)
101
+ equalizer (~> 0.0, >= 0.0.9)
102
+
103
+ PLATFORMS
104
+ ruby
105
+
106
+ DEPENDENCIES
107
+ bundler (~> 2.0)
108
+ byebug (~> 11)
109
+ minitest (~> 5.8.4)
110
+ minitest-around (~> 0.5.0)
111
+ rake (~> 10.0)
112
+ reek (~> 5.4.0)
113
+ rubocop (< 1.0)
114
+ simplecov (~> 0.17.1)
115
+ simplecov-console (= 0.5.0)
116
+ skunk!
117
+
118
+ BUNDLED WITH
119
+ 2.0.2
data/README.md ADDED
@@ -0,0 +1,116 @@
1
+ # Skunk
2
+
3
+ A RubyCritic extension to calculate StinkScore for a file or project.
4
+
5
+ ## What is the StinkScore?
6
+
7
+ The StinkScore is a value that assess the quality of a module. It takes into
8
+ account:
9
+
10
+ - Code Quality
11
+ - Code Smells
12
+ - Churn
13
+ - Code Coverage
14
+
15
+ The formula is not perfect and it is certainly controversial.
16
+
17
+ ## Installation
18
+
19
+ Add this line to your application's Gemfile:
20
+
21
+ ```ruby
22
+ gem 'skunk'
23
+ ```
24
+
25
+ And then execute:
26
+
27
+ $ bundle
28
+
29
+ Or install it yourself as:
30
+
31
+ $ gem install skunk
32
+
33
+ ## Usage
34
+
35
+ Simply run:
36
+
37
+ ```
38
+ skunk
39
+ ```
40
+
41
+ Then get a list of stinky files:
42
+
43
+ ```
44
+ $ skunk
45
+ warning: parser/current is loading parser/ruby26, which recognizes
46
+ warning: 2.6.5-compliant syntax, but you are running 2.6.2.
47
+ warning: please see https://github.com/whitequark/parser#compatibility-with-ruby-mri.
48
+ running flay smells
49
+
50
+ running flog smells
51
+ .............
52
+ running reek smells
53
+ .............
54
+ running complexity
55
+ .............
56
+ running attributes
57
+ .............
58
+ running churn
59
+ .............
60
+ running simple_cov
61
+ .............
62
+ New critique at file:////Users/etagwerker/Projects/fastruby/skunk/tmp/rubycritic/overview.html
63
+ +-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+
64
+ | file | stink_score | churn_times_cost | churn | cost | coverage |
65
+ +-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+
66
+ | lib/skunk/cli/commands/default.rb | 166.44 | 1.6643999999999999 | 3 | 0.5548 | 0 |
67
+ | lib/skunk/cli/application.rb | 139.2 | 1.392 | 3 | 0.46399999999999997 | 0 |
68
+ | lib/skunk/cli/command_factory.rb | 97.6 | 0.976 | 2 | 0.488 | 0 |
69
+ | test/test_helper.rb | 75.2 | 0.752 | 2 | 0.376 | 0 |
70
+ | lib/skunk/rubycritic/analysed_module.rb | 48.12 | 1.7184 | 2 | 0.8592 | 72.72727272727273 |
71
+ | test/lib/skunk/cli/commands/status_reporter_test.rb | 45.6 | 0.456 | 1 | 0.456 | 0 |
72
+ | lib/skunk/cli/commands/base.rb | 29.52 | 0.2952 | 3 | 0.0984 | 0 |
73
+ | lib/skunk/cli/commands/status_reporter.rb | 8.0 | 7.9956 | 3 | 2.6652 | 100.0 |
74
+ | test/lib/skunk/rubycritic/analysed_module_test.rb | 2.63 | 2.6312 | 2 | 1.3156 | 100.0 |
75
+ | lib/skunk.rb | 0.0 | 0.0 | 2 | 0.0 | 0 |
76
+ | lib/skunk/cli/options.rb | 0.0 | 0.0 | 2 | 0.0 | 0 |
77
+ | lib/skunk/version.rb | 0.0 | 0.0 | 2 | 0.0 | 0 |
78
+ | lib/skunk/cli/commands/help.rb | 0.0 | 0.0 | 2 | 0.0 | 0 |
79
+ +-----------------------------------------------------+----------------------------+----------------------------+----------------------------+----------------------------+----------------------------+
80
+
81
+ StinkScore Total: 612.31
82
+ Modules Analysed: 13
83
+ StinkScore Average: 0.47100769230769230769230769231e2
84
+ Worst StinkScore: 166.44 (lib/skunk/cli/commands/default.rb)
85
+ ```
86
+
87
+ The command will run `rubycritic`, so that will generate a RubyCritic overview
88
+ HTML report as well.
89
+
90
+ Skunk's report will be in the console. Use it wisely. :)
91
+
92
+ ## Known Issues
93
+
94
+ The StinkScore should be calculated per method. This would provide a more accurate
95
+ representation of the average StinkScore in a module.
96
+
97
+ I think that the StinkScore of a module should be the average of the StinkScores of
98
+ all of its methods.
99
+
100
+ Right now the StinkScore is calculated using the totals for a module:
101
+
102
+ - Total Code Coverage Percentage per Module
103
+ - Total Churn per Module
104
+ - Total Cost per Module
105
+
106
+ For more details, feel free to review and improve this method: [RubyCritic::AnalysedModule#stink_score]
107
+
108
+ ## Development
109
+
110
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
111
+
112
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
113
+
114
+ ## Contributing
115
+
116
+ Bug reports and pull requests are welcome on GitHub at https://github.com/fastruby/skunk.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rake/testtask"
5
+ require "rubocop/rake_task"
6
+ require "reek/rake/task"
7
+ require "rubycritic/rake_task"
8
+
9
+ Rake::TestTask.new do |task|
10
+ task.libs.push "lib"
11
+ task.libs.push "test"
12
+ task.pattern = "test/**/*_test.rb"
13
+ end
14
+
15
+ RuboCop::RakeTask.new
16
+
17
+ Reek::Rake::Task.new
18
+
19
+ RubyCritic::RakeTask.new do |task|
20
+ task.paths = FileList["lib/**/*.rb"]
21
+ end
22
+
23
+ task default: %i[test reek rubocop]
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "skunk"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/exe/skunk ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Always look in the lib directory of this gem
5
+ # first when searching the load path
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
7
+
8
+ require "skunk/cli/application"
9
+
10
+ exit Skunk::Cli::Application.new(ARGV).execute
data/lib/skunk.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "skunk/version"
4
+
5
+ # Knows how to calculate the `StinkScore` for each file analyzed by `RubyCritic`
6
+ # and `SimpleCov`
7
+ module Skunk
8
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "skunk"
4
+ require "skunk/rubycritic/analysed_module"
5
+ require "skunk/cli/options"
6
+ require "skunk/cli/command_factory"
7
+
8
+ require "rubycritic/cli/application"
9
+
10
+ module Skunk
11
+ module Cli
12
+ # Knows how to execute command line commands
13
+ class Application < RubyCritic::Cli::Application
14
+ def execute
15
+ parsed_options = @options.parse.to_h
16
+
17
+ reporter = Skunk::Cli::CommandFactory.create(parsed_options).execute
18
+ print(reporter.status_message)
19
+ reporter.status
20
+ rescue OptionParser::InvalidOption => error
21
+ warn "Error: #{error}"
22
+ STATUS_ERROR
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubycritic/command_factory"
4
+
5
+ module Skunk
6
+ module Cli
7
+ # Knows how to calculate the command that was request by the CLI user
8
+ class CommandFactory < RubyCritic::CommandFactory
9
+ COMMAND_CLASS_MODES = %i[version help default].freeze
10
+
11
+ # Returns the command class based on the command that was executed
12
+ #
13
+ # @param mode
14
+ # @return [Class]
15
+ def self.command_class(mode)
16
+ mode = mode.to_s.split("_").first.to_sym
17
+ if COMMAND_CLASS_MODES.include? mode
18
+ require "skunk/cli/commands/#{mode}"
19
+ Command.const_get(mode.capitalize)
20
+ else
21
+ require "skunk/cli/commands/default"
22
+ Command::Default
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubycritic/commands/base"
4
+ require "skunk/cli/commands/status_reporter"
5
+
6
+ module Skunk
7
+ module Cli
8
+ module Command
9
+ # Base class for `Skunk` commands. It knows how to build a command with
10
+ # options. It always uses a [Skunk::Command::StatusReporter] as its
11
+ # reporter object.
12
+ class Base < RubyCritic::Command::Base
13
+ def initialize(options)
14
+ @options = options
15
+ @status_reporter = Skunk::Command::StatusReporter.new(@options)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubycritic/commands/default"
4
+ require "rubycritic/analysers_runner"
5
+ require "rubycritic/revision_comparator"
6
+ require "rubycritic/reporter"
7
+
8
+ require "skunk/cli/commands/base"
9
+ require "skunk/cli/commands/status_reporter"
10
+
11
+ module Skunk
12
+ module Cli
13
+ module Command
14
+ # Default command runs a critique using RubyCritic and uses
15
+ # Skunk::Command::StatusReporter to report status
16
+ class Default < RubyCritic::Command::Default
17
+ def initialize(options)
18
+ super
19
+ @status_reporter = Skunk::Command::StatusReporter.new(@options)
20
+ end
21
+
22
+ def execute
23
+ report(critique)
24
+ status_reporter
25
+ end
26
+
27
+ def critique
28
+ RubyCritic::AnalysersRunner.new(paths).run
29
+ end
30
+
31
+ def report(analysed_modules)
32
+ RubyCritic::Reporter.generate_report(analysed_modules)
33
+ status_reporter.analysed_modules = analysed_modules
34
+ status_reporter.score = analysed_modules.score
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "skunk/cli/commands/base"
4
+
5
+ module Skunk
6
+ module Cli
7
+ module Command
8
+ class Help < RubyCritic::Command::Help
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubycritic/commands/status_reporter"
4
+ require "terminal-table"
5
+
6
+ module Skunk
7
+ module Command
8
+ # Knows how to report status for stinky files
9
+ class StatusReporter < RubyCritic::Command::StatusReporter
10
+ attr_accessor :analysed_modules
11
+
12
+ HEADINGS = %w[file stink_score churn_times_cost churn cost coverage].freeze
13
+
14
+ # Returns a status message with a table of all analysed_modules and
15
+ # a stink score average
16
+ def update_status_message
17
+ opts = table_options.merge(headings: HEADINGS, rows: table)
18
+
19
+ ttable = Terminal::Table.new(opts)
20
+
21
+ @status_message = "#{ttable}\n\n"
22
+
23
+ @status_message += "StinkScore Total: #{total_stink_score}\n"
24
+ @status_message += "Modules Analysed: #{analysed_modules_count}\n"
25
+ @status_message += "StinkScore Average: #{stink_score}\n"
26
+ @status_message += "Worst StinkScore: #{worst.stink_score} (#{worst.pathname})\n" if worst
27
+ end
28
+
29
+ private
30
+
31
+ def analysed_modules_count
32
+ @analysed_modules_count ||= analysed_modules.count
33
+ end
34
+
35
+ def worst
36
+ @worst ||= sorted_modules.first
37
+ end
38
+
39
+ def sorted_modules
40
+ @sorted_modules ||= analysed_modules.sort_by(&:stink_score).reverse!
41
+ end
42
+
43
+ def total_stink_score
44
+ @total_stink_score ||= analysed_modules.map(&:stink_score).inject(0.0, :+)
45
+ end
46
+
47
+ def total_churn_times_cost
48
+ analysed_modules.map(&:churn_times_cost).sum
49
+ end
50
+
51
+ def stink_score
52
+ return 0 if analysed_modules_count == 0
53
+
54
+ total_stink_score.to_d / analysed_modules_count
55
+ end
56
+
57
+ def table_options
58
+ {
59
+ style: {
60
+ width: 200
61
+ }
62
+ }
63
+ end
64
+
65
+ def table
66
+ sorted_modules.map do |a_mod|
67
+ [
68
+ a_mod.pathname,
69
+ a_mod.stink_score,
70
+ a_mod.churn_times_cost,
71
+ a_mod.churn,
72
+ a_mod.cost,
73
+ a_mod.coverage
74
+ ]
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubycritic/cli/options"
4
+
5
+ module Skunk
6
+ module Cli
7
+ class Options < RubyCritic::Cli::Options
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rubycritic/core/analysed_module"
4
+
5
+ module RubyCritic
6
+ # Monkey-patches RubyCritic::AnalysedModule to add a stink_score method
7
+ class AnalysedModule
8
+ PERFECT_COVERAGE = 100
9
+
10
+ # Returns a numeric value that represents the stink_score of a module:
11
+ #
12
+ # If module is perfectly covered, stink score is the same as the
13
+ # `churn_times_cost`
14
+ #
15
+ # If module has no coverage, stink score is a penalized value of
16
+ # `churn_times_cost`
17
+ #
18
+ # For now the stink_score is calculated by multiplying `churn_times_cost`
19
+ # times the lack of coverage.
20
+ #
21
+ # For example:
22
+ #
23
+ # When `churn_times_cost` is 100 and module is perfectly covered:
24
+ # stink_score => 100
25
+ #
26
+ # When `churn_times_cost` is 100 and module is not covered at all:
27
+ # stink_score => 100 * 100 = 10_000
28
+ #
29
+ # When `churn_times_cost` is 100 and module is covered at 75%:
30
+ # stink_score => 100 * 25 (percentage uncovered) = 2_500
31
+ #
32
+ # @return [Float]
33
+ def stink_score
34
+ return churn_times_cost.round(2) if coverage == PERFECT_COVERAGE
35
+
36
+ (churn_times_cost * (PERFECT_COVERAGE - coverage.to_i)).round(2)
37
+ end
38
+
39
+ # Returns the value of churn times cost.
40
+ #
41
+ # @return [Integer]
42
+ def churn_times_cost
43
+ safe_churn = churn > 0 ? churn : 1
44
+ @churn_times_cost ||= safe_churn * cost
45
+ end
46
+
47
+ def method_name
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Skunk
4
+ VERSION = "0.1.0"
5
+ end
data/skunk.gemspec ADDED
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require "skunk/version"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "skunk"
9
+ spec.version = Skunk::VERSION
10
+ spec.authors = ["Ernesto Tagwerker"]
11
+ spec.email = ["ernesto+github@ombulabs.com"]
12
+
13
+ spec.summary = "A library to assess code quality vs. code coverage"
14
+ spec.description = "Knows how to calculate the StinkScore for a Ruby file"
15
+ spec.homepage = "https://github.com/fastruby/skunk"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ if spec.respond_to?(:metadata)
20
+ spec.metadata["allowed_push_host"] = "https://www.rubygems.org"
21
+
22
+ spec.metadata["homepage_uri"] = spec.homepage
23
+ spec.metadata["source_code_uri"] = "https://github.com/fastruby/skunk"
24
+ spec.metadata["changelog_uri"] = "https://github.com/fastruby/skunk/changelog"
25
+ else
26
+ raise "RubyGems 2.0 or newer is required to protect against " \
27
+ "public gem pushes."
28
+ end
29
+
30
+ # Specify which files should be added to the gem when it is released.
31
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
32
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
33
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
34
+ end
35
+ spec.bindir = "exe"
36
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
37
+ spec.require_paths = ["lib"]
38
+
39
+ spec.add_dependency "rubycritic-simplecov", "~> 4.1.1"
40
+ spec.add_dependency "terminal-table", "~> 1.8.0"
41
+
42
+ spec.add_development_dependency "bundler", "~> 2.0"
43
+ spec.add_development_dependency "byebug", "~> 11"
44
+ spec.add_development_dependency "minitest", "~> 5.8.4"
45
+ spec.add_development_dependency "minitest-around", "~> 0.5.0"
46
+ spec.add_development_dependency "rake", "~> 10.0"
47
+ spec.add_development_dependency "reek", "~> 5.4.0"
48
+ spec.add_development_dependency "rubocop", "< 1.0"
49
+ spec.add_development_dependency "simplecov", "~> 0.17.1"
50
+ spec.add_development_dependency "simplecov-console", "0.5.0"
51
+ end
metadata ADDED
@@ -0,0 +1,223 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: skunk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Ernesto Tagwerker
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2019-10-16 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rubycritic-simplecov
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.1.1
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.1.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: terminal-table
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.8.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.8.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: byebug
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '11'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 5.8.4
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: 5.8.4
83
+ - !ruby/object:Gem::Dependency
84
+ name: minitest-around
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 0.5.0
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: 0.5.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '10.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '10.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: reek
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 5.4.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: 5.4.0
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "<"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "<"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: simplecov
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: 0.17.1
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: 0.17.1
153
+ - !ruby/object:Gem::Dependency
154
+ name: simplecov-console
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '='
158
+ - !ruby/object:Gem::Version
159
+ version: 0.5.0
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - '='
165
+ - !ruby/object:Gem::Version
166
+ version: 0.5.0
167
+ description: Knows how to calculate the StinkScore for a Ruby file
168
+ email:
169
+ - ernesto+github@ombulabs.com
170
+ executables:
171
+ - skunk
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - ".gitignore"
176
+ - ".reek.yml"
177
+ - ".rubocop.yml"
178
+ - ".rubocop_todo.yml"
179
+ - Gemfile
180
+ - Gemfile.lock
181
+ - README.md
182
+ - Rakefile
183
+ - bin/console
184
+ - bin/setup
185
+ - exe/skunk
186
+ - lib/skunk.rb
187
+ - lib/skunk/cli/application.rb
188
+ - lib/skunk/cli/command_factory.rb
189
+ - lib/skunk/cli/commands/base.rb
190
+ - lib/skunk/cli/commands/default.rb
191
+ - lib/skunk/cli/commands/help.rb
192
+ - lib/skunk/cli/commands/status_reporter.rb
193
+ - lib/skunk/cli/options.rb
194
+ - lib/skunk/rubycritic/analysed_module.rb
195
+ - lib/skunk/version.rb
196
+ - skunk.gemspec
197
+ homepage: https://github.com/fastruby/skunk
198
+ licenses: []
199
+ metadata:
200
+ allowed_push_host: https://www.rubygems.org
201
+ homepage_uri: https://github.com/fastruby/skunk
202
+ source_code_uri: https://github.com/fastruby/skunk
203
+ changelog_uri: https://github.com/fastruby/skunk/changelog
204
+ post_install_message:
205
+ rdoc_options: []
206
+ require_paths:
207
+ - lib
208
+ required_ruby_version: !ruby/object:Gem::Requirement
209
+ requirements:
210
+ - - ">="
211
+ - !ruby/object:Gem::Version
212
+ version: '0'
213
+ required_rubygems_version: !ruby/object:Gem::Requirement
214
+ requirements:
215
+ - - ">="
216
+ - !ruby/object:Gem::Version
217
+ version: '0'
218
+ requirements: []
219
+ rubygems_version: 3.0.3
220
+ signing_key:
221
+ specification_version: 4
222
+ summary: A library to assess code quality vs. code coverage
223
+ test_files: []