Skip to content

Commit

Permalink
Extract console report
Browse files Browse the repository at this point in the history
Closing #103
  • Loading branch information
JuanVqz committed Jul 31, 2023
1 parent f6f63c8 commit 9e9aae8
Show file tree
Hide file tree
Showing 10 changed files with 261 additions and 165 deletions.
6 changes: 5 additions & 1 deletion .reek.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,21 @@ detectors:
- Skunk::Command::StatusReporter#analysed_modules
FeatureEnvy:
exclude:
- Skunk::Command::StatusReporter#table
- Skunk::Generator::ConsoleReport#table
InstanceVariableAssumption:
exclude:
- Skunk::Cli::Options::Argv
- Skunk::Scorer
- RubyCritic::AnalysedModulesCollection
IrresponsibleModule:
exclude:
- RubyCritic::AnalysedModulesCollection
NestedIterators:
exclude:
- Skunk::Cli::Options::Argv#parse
TooManyMethods:
exclude:
- Skunk::Command::StatusSharer
TooManyStatements:
exclude:
- initialize
Expand Down
1 change: 1 addition & 0 deletions lib/skunk/cli/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def execute

# :reek:NilCheck
@parsed_options = @options.parse.to_h

command = Skunk::CommandFactory.create(@parsed_options)
reporter = command.execute

Expand Down
11 changes: 6 additions & 5 deletions lib/skunk/commands/default.rb
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# frozen_string_literal: true

require "rubycritic/commands/default"
require "rubycritic/analysers_runner"
require "rubycritic/revision_comparator"
require "rubycritic/reporter"

require "skunk/commands/base"
require "skunk/commands/shareable"
require "skunk/commands/status_reporter"
require "skunk/commands/shareable"
require "skunk/generators/console_report"
require "skunk/core/scorer"

module Skunk
module Command
Expand Down Expand Up @@ -39,6 +37,9 @@ def execute
#
# @param [RubyCritic::AnalysedModulesCollection] A collection of analysed modules
def report(analysed_modules)
skunk_scorer = Skunk::Scorer.new(analysed_modules)
Skunk::Generator::ConsoleReport.new(skunk_scorer).generate_report

status_reporter.analysed_modules = analysed_modules
status_reporter.score = analysed_modules.score
end
Expand Down
87 changes: 1 addition & 86 deletions lib/skunk/commands/status_reporter.rb
Original file line number Diff line number Diff line change
@@ -1,97 +1,12 @@
# frozen_string_literal: true

require "erb"
require "rubycritic/commands/status_reporter"
require "terminal-table"

module Skunk
module Command
# Knows how to report status for stinky files
# Implements analysed_modules to share it when SHARE is true
class StatusReporter < RubyCritic::Command::StatusReporter
attr_accessor :analysed_modules

HEADINGS = %w[file skunk_score churn_times_cost churn cost coverage].freeze
HEADINGS_WITHOUT_FILE = HEADINGS - %w[file]
HEADINGS_WITHOUT_FILE_WIDTH = HEADINGS_WITHOUT_FILE.size * 17 # padding

TEMPLATE = ERB.new(<<-TEMPL
<%= _ttable %>\n
SkunkScore Total: <%= total_skunk_score %>
Modules Analysed: <%= analysed_modules_count %>
SkunkScore Average: <%= skunk_score_average %>
<% if worst %>Worst SkunkScore: <%= worst.skunk_score %> (<%= worst.pathname %>)<% end %>
Generated with Skunk v<%= Skunk::VERSION %>
TEMPL
)

# Returns a status message with a table of all analysed_modules and
# a skunk score average
def update_status_message
opts = table_options.merge(headings: HEADINGS, rows: table)

_ttable = Terminal::Table.new(opts)

@status_message = TEMPLATE.result(binding)
end

private

def analysed_modules_count
@analysed_modules_count ||= non_test_modules.count
end

def non_test_modules
@non_test_modules ||= analysed_modules.reject do |a_module|
module_path = a_module.pathname.dirname.to_s
module_path.start_with?("test", "spec") || module_path.end_with?("test", "spec")
end
end

def worst
@worst ||= sorted_modules.first
end

def sorted_modules
@sorted_modules ||= non_test_modules.sort_by(&:skunk_score).reverse!
end

def total_skunk_score
@total_skunk_score ||= non_test_modules.sum(&:skunk_score)
end

def total_churn_times_cost
non_test_modules.sum(&:churn_times_cost)
end

def skunk_score_average
return 0 if analysed_modules_count.zero?

(total_skunk_score.to_d / analysed_modules_count).to_f.round(2)
end

def table_options
max = sorted_modules.max_by { |a_mod| a_mod.pathname.to_s.length }
width = max.pathname.to_s.length + HEADINGS_WITHOUT_FILE_WIDTH
{
style: {
width: width
}
}
end

def table
sorted_modules.map do |a_mod|
[
a_mod.pathname,
a_mod.skunk_score,
a_mod.churn_times_cost,
a_mod.churn,
a_mod.cost.round(2),
a_mod.coverage.round(2)
]
end
end
end
end
end
43 changes: 36 additions & 7 deletions lib/skunk/commands/status_sharer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
require "json"

require "skunk/commands/status_reporter"
require "skunk/core/scorer"

module Skunk
module Command
Expand Down Expand Up @@ -40,26 +41,22 @@ def base_url

def json_summary
result = {
total_skunk_score: total_skunk_score,
total_skunk_score: total_score,
analysed_modules_count: analysed_modules_count,
skunk_score_average: skunk_score_average,
skunk_version: Skunk::VERSION
}

if worst
result[:worst_skunk_score] = {
file: worst.pathname.to_s,
skunk_score: worst.skunk_score
file: worst_pathname.to_s,
skunk_score: worst_skunk_score
}
end

result
end

def json_results
sorted_modules.map(&:to_hash)
end

# :reek:UtilityFunction
def not_sharing?
ENV["SHARE"] != "true" && ENV["SHARE_URL"].to_s == ""
Expand Down Expand Up @@ -94,6 +91,38 @@ def post_payload
def url
URI(File.join(base_url, "reports"))
end

def skunk_score_average
skunk_scorer.average
end

def total_score
skunk_scorer.total_score
end

def worst
skunk_scorer.worst
end

def worst_pathname
skunk_scorer.worst_pathname
end

def worst_skunk_score
skunk_scorer.worst_skunk_score
end

def analysed_modules_count
skunk_scorer.analysed_modules_count
end

def json_results
skunk_scorer.sorted_modules.map(&:to_hash)
end

def skunk_scorer
@skunk_scorer ||= Skunk::Scorer.new(analysed_modules)
end
end
end
end
57 changes: 57 additions & 0 deletions lib/skunk/core/scorer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# frozen_string_literal: true

module Skunk
# Skunk Score to share with generators and sharers
class Scorer
attr_reader :analysed_modules

def initialize(analysed_modules)
@analysed_modules = analysed_modules
end

def score
analysed_modules.score
end

def analysed_modules_count
@analysed_modules_count ||= non_test_modules.count
end

def non_test_modules
@non_test_modules ||= analysed_modules.reject do |a_module|
module_path = a_module.pathname.dirname.to_s
module_path.start_with?("test", "spec") || module_path.end_with?("test", "spec")
end
end

def total_score
@total_score ||= non_test_modules.sum(&:skunk_score)
end

def total_churn_times_cost
non_test_modules.sum(&:churn_times_cost)
end

def average
return 0 if analysed_modules_count.zero?

(total_score.to_d / analysed_modules_count).to_f.round(2)
end

def worst
@worst ||= sorted_modules.first
end

def worst_skunk_score
@worst.skunk_score
end

def worst_pathname
@worst.pathname
end

def sorted_modules
@sorted_modules ||= non_test_modules.sort_by(&:skunk_score).reverse!
end
end
end
93 changes: 93 additions & 0 deletions lib/skunk/generators/console_report.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# frozen_string_literal: true

require "erb"
require "terminal-table"
require "rubycritic/generators/console_report"

module Skunk
module Generator
# Print SkunkScore at the console in plain text
class ConsoleReport < RubyCritic::Generator::ConsoleReport
def initialize(skunk_scorer)
@skunk_scorer = skunk_scorer
super
end

HEADINGS = %w[file skunk_score churn_times_cost churn cost coverage].freeze
HEADINGS_WITHOUT_FILE = HEADINGS - %w[file]
HEADINGS_WITHOUT_FILE_WIDTH = HEADINGS_WITHOUT_FILE.size * 17 # padding

TEMPLATE = ERB.new(<<~TEMPL
<%= _ttable %>\n
SkunkScore Total: <%= total_skunk_score %>
Modules Analysed: <%= analysed_modules_count %>
SkunkScore Average: <%= skunk_score_average %>
<% if worst %>Worst SkunkScore: <%= worst_skunk_score %> (<%= worst_pathname %>)<% end %>
Generated with Skunk v<%= Skunk::VERSION %>
TEMPL
)

def generate_report
opts = table_options.merge(headings: HEADINGS, rows: table)

_ttable = Terminal::Table.new(opts)

puts TEMPLATE.result(binding)
end

private

def total_skunk_score
@skunk_scorer.total_score
end

def analysed_modules_count
@skunk_scorer.analysed_modules_count
end

def skunk_score_average
@skunk_scorer.average
end

def worst
@skunk_scorer.worst
end

def worst_skunk_score
@skunk_scorer.worst_skunk_score
end

def worst_pathname
@skunk_scorer.worst_pathname
end

def sorted_modules
@skunk_scorer.sorted_modules
end

def table_options
max = sorted_modules.max_by { |a_mod| a_mod.pathname.to_s.length }
width = max.pathname.to_s.length + HEADINGS_WITHOUT_FILE_WIDTH
{
style: {
width: width
}
}
end

def table
sorted_modules.map do |a_mod|
[
a_mod.pathname,
a_mod.skunk_score,
a_mod.churn_times_cost,
a_mod.churn,
a_mod.cost.round(2),
a_mod.coverage.round(2)
]
end
end
end
end
end
Loading

0 comments on commit 9e9aae8

Please sign in to comment.