Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract console report #114

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
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

Check warning on line 13 in lib/skunk/core/scorer.rb

View check run for this annotation

Codecov / codecov/patch

lib/skunk/core/scorer.rb#L13

Added line #L13 was not covered by tests
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)

Check warning on line 32 in lib/skunk/core/scorer.rb

View check run for this annotation

Codecov / codecov/patch

lib/skunk/core/scorer.rb#L32

Added line #L32 was not covered by tests
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