attractor 2.0.5 → 2.4.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.
@@ -6,18 +6,18 @@ module Attractor
6
6
  def report
7
7
  super
8
8
 
9
- puts 'Generating an HTML report'
9
+ puts "Generating an HTML report"
10
10
  @serve_static = true
11
11
 
12
- FileUtils.mkdir_p './attractor_output'
13
- FileUtils.mkdir_p './attractor_output/stylesheets'
14
- FileUtils.mkdir_p './attractor_output/images'
15
- FileUtils.mkdir_p './attractor_output/javascripts'
12
+ FileUtils.mkdir_p "./attractor_output"
13
+ FileUtils.mkdir_p "./attractor_output/stylesheets"
14
+ FileUtils.mkdir_p "./attractor_output/images"
15
+ FileUtils.mkdir_p "./attractor_output/javascripts"
16
16
 
17
- File.open('./attractor_output/images/attractor_logo.svg', 'w') { |file| file.write(logo) }
18
- File.open('./attractor_output/images/attractor_favicon.png', 'w') { |file| file.write(favicon) }
19
- File.open('./attractor_output/stylesheets/main.css', 'w') { |file| file.write(css) }
20
- File.open('./attractor_output/javascripts/index.pack.js', 'w') { |file| file.write(javascript_pack) }
17
+ File.open("./attractor_output/images/attractor_logo.svg", "w") { |file| file.write(logo) }
18
+ File.open("./attractor_output/images/attractor_favicon.png", "w") { |file| file.write(favicon) }
19
+ File.open("./attractor_output/stylesheets/main.css", "w") { |file| file.write(css) }
20
+ File.open("./attractor_output/javascripts/index.pack.js", "w") { |file| file.write(javascript_pack) }
21
21
 
22
22
  if @calculators.size > 1
23
23
  @calculators.each do |calc|
@@ -25,9 +25,9 @@ module Attractor
25
25
  suggester = Suggester.new(values(type: @short_type))
26
26
  @suggestions = suggester.suggest
27
27
 
28
- File.open("./attractor_output/javascripts/index.#{@short_type}.js", 'w') { |file| file.write(javascript) }
29
- File.open("./attractor_output/index.#{@short_type}.html", 'w') { |file| file.write(render) }
30
- puts "Generated HTML report at #{File.expand_path './attractor_output/'}/index.#{@short_type}.html"
28
+ File.open("./attractor_output/javascripts/index.#{@short_type}.js", "w") { |file| file.write(javascript) }
29
+ File.open("./attractor_output/index.#{@short_type}.html", "w") { |file| file.write(render) }
30
+ puts "Generated HTML report at #{File.expand_path "./attractor_output/"}/index.#{@short_type}.html"
31
31
  end
32
32
 
33
33
  if @open_browser
@@ -35,41 +35,40 @@ module Attractor
35
35
  puts "Opening browser window..."
36
36
  end
37
37
  else
38
- File.open('./attractor_output/javascripts/index.js', 'w') { |file| file.write(javascript) }
39
- File.open('./attractor_output/index.html', 'w') { |file| file.write(render) }
40
- puts "Generated HTML report at #{File.expand_path './attractor_output/index.html'}"
38
+ File.open("./attractor_output/javascripts/index.js", "w") { |file| file.write(javascript) }
39
+ File.open("./attractor_output/index.html", "w") { |file| file.write(render) }
40
+ puts "Generated HTML report at #{File.expand_path "./attractor_output/index.html"}"
41
41
 
42
42
  if @open_browser
43
- Launchy.open(File.expand_path('./attractor_output/index.html'))
43
+ Launchy.open(File.expand_path("./attractor_output/index.html"))
44
44
  puts "Opening browser window..."
45
45
  end
46
46
  end
47
-
48
47
  end
49
48
 
50
49
  def logo
51
- File.read(File.expand_path('../../../app/assets/images/attractor_logo.svg', __dir__))
50
+ File.read(File.expand_path("../../../app/assets/images/attractor_logo.svg", __dir__))
52
51
  end
53
52
 
54
53
  def favicon
55
- File.read(File.expand_path('../../../app/assets/images/attractor_favicon.png', __dir__))
54
+ File.read(File.expand_path("../../../app/assets/images/attractor_favicon.png", __dir__))
56
55
  end
57
56
 
58
57
  def css
59
- File.read(File.expand_path('../../../app/assets/stylesheets/main.css', __dir__))
58
+ File.read(File.expand_path("../../../app/assets/stylesheets/main.css", __dir__))
60
59
  end
61
60
 
62
61
  def javascript_pack
63
- File.read(File.expand_path('../../../app/assets/javascripts/index.pack.js', __dir__))
62
+ File.read(File.expand_path("../../../app/assets/javascripts/index.pack.js", __dir__))
64
63
  end
65
64
 
66
65
  def javascript
67
- template = Tilt.new(File.expand_path('../../../app/assets/javascripts/index.js.erb', __dir__))
66
+ template = Tilt.new(File.expand_path("../../../app/assets/javascripts/index.js.erb", __dir__))
68
67
  template.render self
69
68
  end
70
69
 
71
70
  def render
72
- template = Tilt.new(File.expand_path('../../../app/views/index.html.erb', __dir__))
71
+ template = Tilt.new(File.expand_path("../../../app/views/index.html.erb", __dir__))
73
72
  template.render self
74
73
  end
75
74
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rack/livereload'
4
- require 'rack'
5
- require 'sinatra/base'
3
+ require "rack/livereload"
4
+ require "rack"
5
+ require "sinatra/base"
6
6
 
7
7
  module Attractor
8
8
  # skeleton sinatra app
@@ -13,31 +13,31 @@ module Attractor
13
13
  end
14
14
 
15
15
  enable :static
16
- set :public_folder, File.expand_path('../../../app/assets', __dir__)
16
+ set :public_folder, File.expand_path("../../../app/assets", __dir__)
17
17
  set :show_exceptions, :after_handler
18
18
 
19
- get '/' do
19
+ get "/" do
20
20
  @types = @reporter.types
21
- erb File.read(File.expand_path('../../../app/views/index.html.erb', __dir__))
21
+ erb File.read(File.expand_path("../../../app/views/index.html.erb", __dir__))
22
22
  end
23
23
 
24
- get '/file_prefix' do
25
- { file_prefix: @reporter.file_prefix }.to_json
24
+ get "/file_prefix" do
25
+ {file_prefix: @reporter.file_prefix}.to_json
26
26
  end
27
27
 
28
- get '/values' do
29
- type = params[:type] || 'rb'
28
+ get "/values" do
29
+ type = params[:type] || "rb"
30
30
  @reporter.values(type: type).to_json
31
31
  end
32
32
 
33
- get '/suggestions' do
33
+ get "/suggestions" do
34
34
  threshold = params[:t] || 95
35
- type = params[:type] || 'rb'
35
+ type = params[:type] || "rb"
36
36
  @reporter.suggestions(quantile: threshold, type: type).to_json
37
37
  end
38
38
 
39
39
  error NoMethodError do
40
- { error: env['sinatra.error'].message }.to_json
40
+ {error: env["sinatra.error"].message}.to_json
41
41
  end
42
42
  end
43
43
 
@@ -48,10 +48,10 @@ module Attractor
48
48
 
49
49
  app = AttractorApp.new(self)
50
50
 
51
- puts 'Serving attractor at http://localhost:7890'
51
+ puts "Serving attractor at http://localhost:7890"
52
52
 
53
53
  if @open_browser
54
- Launchy.open('http://localhost:7890') if @open_browser
54
+ Launchy.open("http://localhost:7890") if @open_browser
55
55
  puts "Opening browser window..."
56
56
  end
57
57
 
@@ -63,9 +63,9 @@ module Attractor
63
63
 
64
64
  app = AttractorApp.new(self)
65
65
 
66
- puts 'Serving attractor at http://localhost:7890'
66
+ puts "Serving attractor at http://localhost:7890"
67
67
  if @open_browser
68
- Launchy.open('http://localhost:7890')
68
+ Launchy.open("http://localhost:7890")
69
69
  puts "Opening browser window..."
70
70
  end
71
71
 
@@ -4,18 +4,18 @@ module Attractor
4
4
  # makes suggestions for refactorings
5
5
  class Suggester
6
6
  attr_accessor :values
7
-
7
+
8
8
  def initialize(values)
9
9
  @values = values || []
10
10
  end
11
11
 
12
12
  def suggest(threshold = 95)
13
- products = @values.map { |val| val.churn * val.complexity }
13
+ products = @values.map(&:score)
14
14
  products.extend(DescriptiveStatistics)
15
15
  quantile = products.percentile(threshold.to_i)
16
16
 
17
- @values.select { |val| val.churn * val.complexity > quantile }
18
- .sort_by { |val| val.churn * val.complexity }.reverse
17
+ @values.select { |val| val.score > quantile }
18
+ .sort_by { |val| val.score }.reverse
19
19
  end
20
20
  end
21
21
  end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
3
+ require "json"
4
4
 
5
5
  module Attractor
6
6
  # holds a churn/complexity value
7
7
  class Value
8
8
  attr_reader :file_path, :churn, :complexity, :details, :history
9
9
 
10
- def initialize(file_path: '', churn: 1, complexity: 0, details: [], history: [])
10
+ def initialize(file_path: "", churn: 1, complexity: 0, details: [], history: [])
11
11
  @file_path = file_path
12
12
  @churn = churn
13
13
  @complexity = complexity
@@ -15,12 +15,20 @@ module Attractor
15
15
  @history = history
16
16
  end
17
17
 
18
+ def current_commit
19
+ history&.first&.first
20
+ end
21
+
22
+ def score
23
+ @complexity * @churn
24
+ end
25
+
18
26
  def to_s
19
- format('%-64s%8.1f%8i', @file_path, @complexity, @churn)
27
+ format("%-64s%8.1f%8i", @file_path, @complexity, @churn)
20
28
  end
21
29
 
22
30
  def to_h
23
- { file_path: file_path, x: churn, y: complexity, details: details, history: history }
31
+ {file_path: file_path, x: churn, y: complexity, details: details, history: history}
24
32
  end
25
33
 
26
34
  def to_json(_opt)
@@ -1,3 +1,3 @@
1
1
  module Attractor
2
- VERSION = "2.0.5"
2
+ VERSION = "2.4.0"
3
3
  end
@@ -0,0 +1,7 @@
1
+ module Attractor
2
+ <<<<<<< HEAD
3
+ VERSION = "2.4.0"
4
+ =======
5
+ VERSION = "2.3.0"
6
+ >>>>>>> 1b4d274a6c7f6634ac4b6c2627f5de500788cef4
7
+ end
@@ -5,17 +5,19 @@ require "listen"
5
5
  module Attractor
6
6
  # functionality for watching file system changes
7
7
  class Watcher
8
- def initialize(file_prefix, callback)
8
+ def initialize(file_prefix, ignores, callback)
9
9
  @file_prefix = file_prefix
10
10
  @callback = callback
11
+ @ignores = ignores.split(",").map(&:strip)
11
12
  end
12
13
 
13
14
  def watch
14
15
  @callback.call
16
+ ignore = @ignores + [/^attractor_output/]
15
17
 
16
- listener = Listen.to(File.absolute_path(@file_prefix), ignore: /^attractor_output/) do |modified, _added, _removed|
18
+ listener = Listen.to(File.absolute_path(@file_prefix), ignore: ignore) do |modified, _added, _removed|
17
19
  if modified
18
- puts "#{modified.map(&:to_s).join(', ')} modified, recalculating..."
20
+ puts "#{modified.map(&:to_s).join(", ")} modified, recalculating..."
19
21
  @callback.call
20
22
  end
21
23
  end
data/lib/attractor.rb CHANGED
@@ -1,16 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'attractor/version'
4
- require 'attractor/gem_names'
5
- require 'attractor/duration_parser'
6
- require 'attractor/calculators/base_calculator'
7
- require 'attractor/detectors/base_detector'
8
- require 'attractor/reporters/base_reporter'
9
- require 'attractor/suggester'
10
- require 'attractor/watcher'
11
-
12
- Dir[File.join(__dir__, 'attractor', 'reporters', '*.rb')].each do |file|
13
- next if file.start_with?('base')
3
+ require "attractor/version"
4
+ require "attractor/gem_names"
5
+ require "attractor/duration_parser"
6
+ require "attractor/calculators/base_calculator"
7
+ require "attractor/detectors/base_detector"
8
+ require "attractor/reporters/base_reporter"
9
+ require "attractor/suggester"
10
+ require "attractor/watcher"
11
+ require "attractor/cache"
12
+
13
+ Dir[File.join(__dir__, "attractor", "reporters", "*.rb")].sort.each do |file|
14
+ next if file.start_with?("base")
14
15
 
15
16
  require file
16
17
  end
@@ -20,6 +21,15 @@ module Attractor
20
21
 
21
22
  @registry_entries = {}
22
23
 
24
+ def init(calculators)
25
+ calculators ||= all_registered_calculators
26
+ calculators.to_a.map(&:last).each(&:calculate)
27
+ end
28
+
29
+ def clear
30
+ Cache.clear
31
+ end
32
+
23
33
  def register(registry_entry)
24
34
  @registry_entries[registry_entry.type] = registry_entry
25
35
  end
@@ -27,16 +37,22 @@ module Attractor
27
37
  def calculators_for_type(type, **options)
28
38
  registry_entry_for_type = @registry_entries[type]
29
39
 
30
- return { type => registry_entry_for_type.calculator_class.new(**options) } if type
40
+ return {type => registry_entry_for_type.calculator_class.new(**options)} if type
41
+
42
+ all_registered_calculators(**options)
43
+ end
31
44
 
32
-
33
- Hash[@registry_entries.map do |type, entry|
45
+ def all_registered_calculators(options = {})
46
+ @registry_entries.map do |type, entry|
34
47
  [type, entry.calculator_class.new(**options)] if entry.detector_class.new.detect
35
- end.compact]
48
+ end.compact.to_h
36
49
  end
37
50
 
38
51
  module_function :calculators_for_type
52
+ module_function :all_registered_calculators
39
53
  module_function :register
54
+ module_function :init
55
+ module_function :clear
40
56
  end
41
57
 
42
58
  Attractor::GemNames.new.to_a.each do |gem_name|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attractor
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.5
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Julian Rubisch
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-03-24 00:00:00.000000000 Z
11
+ date: 2021-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: churn
@@ -154,30 +154,30 @@ dependencies:
154
154
  name: attractor-javascript
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - ">="
157
+ - - "~>"
158
158
  - !ruby/object:Gem::Version
159
- version: '0'
159
+ version: 0.2.0
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - ">="
164
+ - - "~>"
165
165
  - !ruby/object:Gem::Version
166
- version: '0'
166
+ version: 0.2.0
167
167
  - !ruby/object:Gem::Dependency
168
168
  name: attractor-ruby
169
169
  requirement: !ruby/object:Gem::Requirement
170
170
  requirements:
171
- - - ">="
171
+ - - "~>"
172
172
  - !ruby/object:Gem::Version
173
- version: '0'
173
+ version: 0.2.0
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
- - - ">="
178
+ - - "~>"
179
179
  - !ruby/object:Gem::Version
180
- version: '0'
180
+ version: 0.2.0
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: autoprefixer-rails
183
183
  requirement: !ruby/object:Gem::Requirement
@@ -371,32 +371,22 @@ files:
371
371
  - app/views/index.html.erb
372
372
  - exe/attractor
373
373
  - lib/attractor.rb
374
- - lib/attractor.rb~
375
- - lib/attractor/#duration_parser.rb#
374
+ - lib/attractor/cache.rb
376
375
  - lib/attractor/calculators/base_calculator.rb
377
- - lib/attractor/calculators/base_calculator.rb~
378
376
  - lib/attractor/cli.rb
379
377
  - lib/attractor/detectors/base_detector.rb
380
- - lib/attractor/detectors/base_detector.rb~
381
378
  - lib/attractor/duration_parser.rb
382
- - lib/attractor/duration_parser.rb~
383
379
  - lib/attractor/gem_names.rb
384
- - lib/attractor/gem_names.rb~
385
380
  - lib/attractor/registry_entry.rb
386
- - lib/attractor/registry_entry.rb~
387
381
  - lib/attractor/reporters/base_reporter.rb
388
- - lib/attractor/reporters/base_reporter.rb~
389
382
  - lib/attractor/reporters/console_reporter.rb
390
- - lib/attractor/reporters/console_reporter.rb~
391
383
  - lib/attractor/reporters/html_reporter.rb
392
- - lib/attractor/reporters/html_reporter.rb~
393
384
  - lib/attractor/reporters/sinatra_reporter.rb
394
385
  - lib/attractor/suggester.rb
395
- - lib/attractor/tmp/churn/9f86bc9b7ec6bf59cbf7a111ce8b1159ae128347.json
396
386
  - lib/attractor/value.rb
397
387
  - lib/attractor/version.rb
388
+ - lib/attractor/version.rb~
398
389
  - lib/attractor/watcher.rb
399
- - lib/attractor/watcher.rb~
400
390
  homepage: https://github.com/julianrubisch/attractor
401
391
  licenses:
402
392
  - MIT
@@ -405,7 +395,7 @@ metadata:
405
395
  source_code_uri: https://github.com/julianrubisch/attractor
406
396
  bug_tracker_uri: https://github.com/julianrubisch/attractor/issues
407
397
  changelog_uri: https://github.com/julianrubisch/attractor/CHANGELOG.md
408
- post_install_message:
398
+ post_install_message:
409
399
  rdoc_options: []
410
400
  require_paths:
411
401
  - lib
@@ -421,7 +411,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
421
411
  version: '0'
422
412
  requirements: []
423
413
  rubygems_version: 3.1.4
424
- signing_key:
414
+ signing_key:
425
415
  specification_version: 4
426
416
  summary: Churn vs Complexity Chart Generator
427
417
  test_files: []
@@ -1,24 +0,0 @@
1
- module Attractor
2
- class DurationParser
3
- TOKENS = {
4
- 'd" => 1,
5
- w" => 7,
6
- m" => 30,
7
- y" => 365
8
- }
9
-
10
- attr_reader :duration
11
-
12
- def initialize(input)
13
- @input = input
14
- @duration = 0
15
- parse
16
- end
17
-
18
- def parse
19
- @input.scan(/(\d+)(\w)/).each do |amount, measure|
20
- @duration += amount.to_i * TOKENS[measure]
21
- end
22
- end
23
- end
24
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'churn/calculator'
4
- require 'csv'
5
- require 'date'
6
- require 'flog'
7
- require 'listen'
8
-
9
- require 'attractor/value'
10
-
11
- module Attractor
12
- # calculates churn and complexity
13
- class BaseCalculator
14
- def initialize(file_prefix: '', file_extension: 'rb', minimum_churn_count: 3)
15
- @file_prefix = file_prefix
16
- @file_extension = file_extension
17
- @minimum_churn_count = minimum_churn_count
18
- end
19
-
20
- def calculate
21
- churn = ::Churn::ChurnCalculator.new(
22
- file_extension: @file_extension,
23
- file_prefix: @file_prefix,
24
- minimum_churn_count: @minimum_churn_count,
25
- start_date: Date.today - 365 * 5
26
- ).report(false)
27
-
28
- churn[:churn][:changes].map do |change|
29
- complexity, details = yield(change)
30
- # flogger = Flog.new(all: true)
31
- # flogger.flog(change[:file_path])
32
- # complexity = flogger.total_score
33
- # details = flogger.totals
34
- Value.new(file_path: change[:file_path],
35
- churn: change[:times_changed],
36
- complexity: complexity,
37
- details: details,
38
- history: git_history_for_file(file_path: change[:file_path]))
39
- end
40
- end
41
-
42
- private
43
-
44
- def git_history_for_file(file_path:, limit: 10)
45
- history = `git log --oneline -n #{limit} -- #{file_path}`
46
- history.split("\n")
47
- .map do |log_entry|
48
- log_entry.partition(/\A(\S+)\s/)
49
- .map(&:strip)
50
- .reject(&:empty?)
51
- end
52
- end
53
- end
54
- end
@@ -1,4 +0,0 @@
1
- module Attractor
2
- class BaseDetector
3
- end
4
- end
@@ -1,23 +0,0 @@
1
- module Attractor
2
- class DurationParser
3
- TOKENS = {
4
- "m" => (60),
5
- "h" => (60 * 60),
6
- "d" => (60 * 60 * 24)
7
- }
8
-
9
- attr_reader :time
10
-
11
- def initialize(input)
12
- @input = input
13
- @time = 0
14
- parse
15
- end
16
-
17
- def parse
18
- @input.scan(/(\d+)(\w)/).each do |amount, measure|
19
- @time += amount.to_i * TOKENS[measure]
20
- end
21
- end
22
- end
23
- end
@@ -1,23 +0,0 @@
1
- module Attractor
2
-
3
- # from https://github.com/prontolabs/pronto/blob/master/lib/pronto/gem_names.rb
4
- class GemNames
5
- def to_a
6
- gems.map { |gem| gem.name.sub(/^pronto-/, '') }.uniq.sort
7
- end
8
-
9
- private
10
-
11
- def gems
12
- Gem::Specification.find_all.select do |gem|
13
- if gem.name =~ /^pronto-/
14
- true
15
- elsif gem.name != 'pronto'
16
- runner_path = File.join(gem.full_gem_path,
17
- "lib/pronto/#{gem.name}.rb")
18
- File.exist?(runner_path)
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,2 +0,0 @@
1
- RegistryEntry = Struct.new :type, :detector, :calculator
2
-
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'descriptive_statistics/safe'
4
- require 'fileutils'
5
- require 'forwardable'
6
- require 'launchy'
7
- require 'tilt'
8
-
9
- module Attractor
10
- # base reporter
11
- class BaseReporter
12
- extend Forwardable
13
- attr_accessor :file_prefix
14
- attr_reader :types
15
- attr_writer :values
16
- def_delegator :@watcher, :watch
17
-
18
- def initialize(file_prefix: '', calculators:, open_browser: true)
19
- @file_prefix = file_prefix
20
- @calculators = calculators
21
- @open_browser = open_browser
22
- @values = @calculators.first.last.calculate
23
- @suggester = Suggester.new(values)
24
-
25
- @watcher = Watcher.new(file_prefix, lambda do
26
- report
27
- end)
28
- rescue NoMethodError => e
29
- raise 'There was a problem gathering churn changes'
30
- end
31
-
32
- def suggestions(quantile:, type: 'rb')
33
- @suggester.values = values(type: type)
34
- @suggestions = @suggester.suggest(quantile)
35
- @suggestions
36
- end
37
-
38
- def report
39
- @suggestions = @suggester.suggest
40
- @types = Hash[@calculators.map { |calc| [calc.first, calc.last.type] }]
41
- end
42
-
43
- def render
44
- 'Attractor'
45
- end
46
-
47
- def values(type: 'rb')
48
- @values = @calculators[type].calculate
49
- @values
50
- rescue NoMethodError => e
51
- puts "No calculator for type #{type}"
52
- end
53
- end
54
- end
@@ -1,21 +0,0 @@
1
- require 'base_reporter'
2
-
3
- module Attractor
4
- # console reporter
5
- class ConsoleReporter < BaseReporter
6
- def report
7
- super
8
- puts 'Calculated churn and complexity'
9
- puts
10
- puts "file_path#{' ' * 53}complexity churn"
11
- puts '-' * 80
12
-
13
- puts @values.map(&:to_s)
14
-
15
- puts
16
- puts 'Suggestions for refactorings:'
17
- @suggestions.each { |sug| puts sug.file_path }
18
- puts
19
- end
20
- end
21
- end