attractor 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b116bbaa914ca032391378e04b8e41f27b28fa4feaca3fc50c93053d1954a15a
4
- data.tar.gz: 3e5620d661d19d3d2308457921389ce78b4ba3b844a6a4d3dd33c1ef9d093a56
3
+ metadata.gz: c1b66250e293edf3d4298ee78c92a928b92128d0f8525a012ba4c99b8e16a77e
4
+ data.tar.gz: 354068cdc6c91978e80e3860ac65255811daf364d64c15dcd7221db2bac79f22
5
5
  SHA512:
6
- metadata.gz: '092ff47f81f9d6f0e7fa025d21a89501413e1dc8c7044d5420d4db8ea04f72fc6554840a9656b0ac002c2f0c25ef3f0fa9c1204214d4b29a284eabb565428f82'
7
- data.tar.gz: 83ad8a7dafa969e68c4db77629663738513137a3f91ad058451d9a37c1ed39aff1cfea785c34042d543b7caac8ec625207cf3701c7003d63a23f631cbba109b5
6
+ metadata.gz: 456416f564b3e7e5efa7874f901fea6a0c26c23e59bf157dd5c78cb58014f4bcee58f0172cebdc83061d94195d94631e1818eba905835799e1664527fc26caa9
7
+ data.tar.gz: 472072d37700e794de8ee98d48f2252186598f709094c9046acc97deb91ef34dfbc089a4c7b70f0965ce8fc4621877c63d41a167f4d2968f2b734b9f5e4e18de
@@ -40,10 +40,10 @@ module Attractor
40
40
  complexity, details = yield(change)
41
41
 
42
42
  value = Value.new(file_path: change[:file_path],
43
- churn: change[:times_changed],
44
- complexity: complexity,
45
- details: details,
46
- history: history)
43
+ churn: change[:times_changed],
44
+ complexity: complexity,
45
+ details: details,
46
+ history: history)
47
47
  Cache.write(file_path: change[:file_path], value: value)
48
48
  end
49
49
 
data/lib/attractor/cli.rb CHANGED
@@ -45,10 +45,12 @@ module Attractor
45
45
  shared_options.each do |shared_option|
46
46
  option(*shared_option)
47
47
  end
48
+ option(:format, aliases: :f, default: :table)
48
49
  def calc
49
50
  file_prefix = options[:file_prefix]
51
+ output_format = options[:format]
50
52
 
51
- report! Attractor::ConsoleReporter.new(file_prefix: file_prefix, ignores: options[:ignore], calculators: calculators(options))
53
+ report! Attractor::ConsoleReporter.new(file_prefix: file_prefix, ignores: options[:ignore], calculators: calculators(options), format: output_format)
52
54
  rescue RuntimeError => e
53
55
  puts "Runtime error: #{e.message}"
54
56
  end
@@ -36,7 +36,7 @@ module Attractor
36
36
 
37
37
  def report
38
38
  @suggestions = @suggester.suggest
39
- @types = Hash[@calculators.map { |calc| [calc.first, calc.last.type] }]
39
+ @types = @calculators.map { |calc| [calc.first, calc.last.type] }.to_h
40
40
  end
41
41
 
42
42
  def render
@@ -3,26 +3,65 @@
3
3
  module Attractor
4
4
  # console reporter
5
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
6
+ class TableFormatter
7
+ def call(calculators)
8
+ puts "Calculated churn and complexity"
9
+ puts
10
+ puts "file_path#{" " * 53}complexity churn"
11
+ puts "-" * 80
12
12
 
13
- @calculators.each do |calc|
14
- # e.g. ['js', JsCalculator']
15
- puts calc.last.type
13
+ calculators.each do |calc|
14
+ # e.g. ['js', JsCalculator']
15
+ puts calc.last.type
16
16
 
17
- values = calc.last.calculate
18
- suggester = Suggester.new(values)
17
+ values = calc.last.calculate
18
+ suggester = Suggester.new(values)
19
19
 
20
- puts values&.map(&:to_s)
21
- puts
22
- puts "Suggestions for refactorings:"
23
- suggester.suggest&.each { |sug| puts sug.file_path }
24
- puts
20
+ puts values&.map(&:to_s)
21
+ puts
22
+ puts "Suggestions for refactorings:"
23
+ suggester.suggest&.each { |sug| puts sug.file_path }
24
+ puts
25
+ end
25
26
  end
26
27
  end
28
+
29
+ class CSVFormatter
30
+ def call(calculators)
31
+ require "csv"
32
+
33
+ result = CSV.generate do |csv|
34
+ csv << %w[file_path score complexity churn type refactor]
35
+
36
+ calculators.each do |calc|
37
+ type = calc.last.type
38
+ values = calc.last.calculate
39
+ suggester = Suggester.new(values)
40
+ to_be_refactored = suggester.suggest.map(&:file_path)
41
+
42
+ values.each do |value|
43
+ csv << [value.file_path, value.score, value.complexity, value.churn, type, to_be_refactored.include?(value.file_path)]
44
+ end
45
+ end
46
+ end
47
+
48
+ puts result
49
+ end
50
+ end
51
+
52
+ def initialize(format:, **other)
53
+ super(**other)
54
+ @formatter = case format.to_sym
55
+ when :csv
56
+ CSVFormatter.new
57
+ else
58
+ TableFormatter.new
59
+ end
60
+ end
61
+
62
+ def report
63
+ super
64
+ @formatter.call(@calculators)
65
+ end
27
66
  end
28
67
  end
@@ -10,12 +10,12 @@ module Attractor
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
@@ -19,6 +19,10 @@ module Attractor
19
19
  history&.first&.first
20
20
  end
21
21
 
22
+ def score
23
+ @complexity * @churn
24
+ end
25
+
22
26
  def to_s
23
27
  format("%-64s%8.1f%8i", @file_path, @complexity, @churn)
24
28
  end
@@ -1,3 +1,3 @@
1
1
  module Attractor
2
- VERSION = "2.3.0"
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
data/lib/attractor.rb CHANGED
@@ -43,9 +43,9 @@ module Attractor
43
43
  end
44
44
 
45
45
  def all_registered_calculators(options = {})
46
- Hash[@registry_entries.map do |type, entry|
46
+ @registry_entries.map do |type, entry|
47
47
  [type, entry.calculator_class.new(**options)] if entry.detector_class.new.detect
48
- end.compact]
48
+ end.compact.to_h
49
49
  end
50
50
 
51
51
  module_function :calculators_for_type
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.3.0
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-04-12 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
@@ -371,35 +371,22 @@ files:
371
371
  - app/views/index.html.erb
372
372
  - exe/attractor
373
373
  - lib/attractor.rb
374
- - lib/attractor.rb~
375
374
  - lib/attractor/cache.rb
376
- - lib/attractor/cache.rb~
377
375
  - lib/attractor/calculators/base_calculator.rb
378
- - lib/attractor/calculators/base_calculator.rb~
379
376
  - lib/attractor/cli.rb
380
- - lib/attractor/cli.rb~
381
377
  - lib/attractor/detectors/base_detector.rb
382
- - lib/attractor/detectors/base_detector.rb~
383
378
  - lib/attractor/duration_parser.rb
384
- - lib/attractor/duration_parser.rb~
385
379
  - lib/attractor/gem_names.rb
386
- - lib/attractor/gem_names.rb~
387
380
  - lib/attractor/registry_entry.rb
388
- - lib/attractor/registry_entry.rb~
389
381
  - lib/attractor/reporters/base_reporter.rb
390
- - lib/attractor/reporters/base_reporter.rb~
391
382
  - lib/attractor/reporters/console_reporter.rb
392
- - lib/attractor/reporters/console_reporter.rb~
393
383
  - lib/attractor/reporters/html_reporter.rb
394
- - lib/attractor/reporters/html_reporter.rb~
395
384
  - lib/attractor/reporters/sinatra_reporter.rb
396
385
  - lib/attractor/suggester.rb
397
- - lib/attractor/tmp/churn/9f86bc9b7ec6bf59cbf7a111ce8b1159ae128347.json
398
386
  - lib/attractor/value.rb
399
- - lib/attractor/value.rb~
400
387
  - lib/attractor/version.rb
388
+ - lib/attractor/version.rb~
401
389
  - lib/attractor/watcher.rb
402
- - lib/attractor/watcher.rb~
403
390
  homepage: https://github.com/julianrubisch/attractor
404
391
  licenses:
405
392
  - MIT
@@ -408,7 +395,7 @@ metadata:
408
395
  source_code_uri: https://github.com/julianrubisch/attractor
409
396
  bug_tracker_uri: https://github.com/julianrubisch/attractor/issues
410
397
  changelog_uri: https://github.com/julianrubisch/attractor/CHANGELOG.md
411
- post_install_message:
398
+ post_install_message:
412
399
  rdoc_options: []
413
400
  require_paths:
414
401
  - lib
@@ -423,8 +410,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
423
410
  - !ruby/object:Gem::Version
424
411
  version: '0'
425
412
  requirements: []
426
- rubygems_version: 3.2.3
427
- signing_key:
413
+ rubygems_version: 3.1.4
414
+ signing_key:
428
415
  specification_version: 4
429
416
  summary: Churn vs Complexity Chart Generator
430
417
  test_files: []
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "fileutils"
4
- require "psych"
5
-
6
- module Attractor
7
- class Cache
8
- class << self
9
- def read(file_path:)
10
- adapter.read(file_path: file_path)
11
- end
12
-
13
- def write(file_path:, value:)
14
- adapter.write(file_path: file_path, value: value)
15
- end
16
-
17
- private
18
-
19
- def adapter
20
- @@adapter ||= CacheAdapter::JSON.instance
21
- end
22
- end
23
- end
24
-
25
- module CacheAdapter
26
- class Base
27
- include Singleton
28
- end
29
-
30
- class JSON < Base
31
- def initialize
32
- super
33
-
34
- @data_directory = "tmp"
35
- FileUtils.mkdir_p @data_directory
36
- FileUtils.touch filename
37
-
38
- begin
39
- @store = ::JSON.parse(File.read(filename))
40
- rescue ::JSON::ParserError
41
- @store = {}
42
- end
43
- end
44
-
45
- def read(file_path:)
46
- value_hash = @store[file_path]
47
-
48
- Value.new(**value_hash.values.first.transform_keys(&:to_sym)) unless value_hash.nil?
49
- rescue ArgumentError => e
50
- puts "Couldn't rehydrate value from cache: #{e.message}"
51
- nil
52
- end
53
-
54
- def write(file_path:, value:)
55
- mappings = {x: :churn, y: :complexity}
56
-
57
- transformed_value = value.to_h.transform_keys { |k| mappings[k] || k }
58
- @store[file_path] = {value.current_commit => transformed_value}
59
- File.write(filename, ::JSON.dump(@store))
60
- end
61
-
62
- def filename
63
- "#{@data_directory}/attractor-cache.json"
64
- end
65
- end
66
- end
67
- end
@@ -1,64 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "churn/calculator"
4
-
5
- require "attractor/value"
6
-
7
- module Attractor
8
- # calculates churn and complexity
9
- class BaseCalculator
10
- attr_reader :type
11
-
12
- def initialize(file_prefix: "", ignores: "", file_extension: "rb", minimum_churn_count: 3, start_ago: "5y")
13
- @file_prefix = file_prefix
14
- @file_extension = file_extension
15
- @minimum_churn_count = minimum_churn_count
16
- @start_date = Date.today - Attractor::DurationParser.new(start_ago).duration
17
- @ignores = ignores
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: @start_date,
26
- ignores: @ignores
27
- ).report(false)
28
-
29
- churn[:churn][:changes].map do |change|
30
- history = git_history_for_file(file_path: change[:file_path])
31
- commit = history&.first&.first
32
-
33
- cached_value = Cache.read(file_path: change[:file_path])
34
-
35
- if !cached_value.nil? && !cached_value.current_commit.nil? && cached_value.current_commit == commit
36
- value = cached_value
37
- else
38
- complexity, details = yield(change)
39
-
40
- value = Value.new(file_path: change[:file_path],
41
- churn: change[:times_changed],
42
- complexity: complexity,
43
- details: details,
44
- history: history)
45
- Cache.write(file_path: change[:file_path], value: value)
46
- end
47
-
48
- value
49
- end
50
- end
51
-
52
- private
53
-
54
- def git_history_for_file(file_path:, limit: 10)
55
- history = `git log --oneline -n #{limit} -- #{file_path}`
56
- history.split("\n")
57
- .map do |log_entry|
58
- log_entry.partition(/\A(\S+)\s/)
59
- .map(&:strip)
60
- .reject(&:empty?)
61
- end
62
- end
63
- end
64
- end
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "thor"
4
-
5
- require "attractor"
6
-
7
- module Attractor
8
- # contains methods implementing the CLI
9
- class CLI < Thor
10
- shared_options = [[:file_prefix, aliases: :p],
11
- [:ignore, aliases: :i, default: ""],
12
- [:watch, aliases: :w, type: :boolean],
13
- [:minimum_churn, aliases: :c, type: :numeric, default: 3],
14
- [:start_ago, aliases: :s, type: :string, default: "5y"],
15
- [:type, aliases: :t]]
16
-
17
- advanced_options = [[:format, aliases: :f, default: "html"],
18
- [:no_open_browser, type: :boolean],
19
- [:ci, type: :boolean]]
20
-
21
- desc "version", "Prints Attractor's version information"
22
- map %w[-v --version] => :version
23
- def version
24
- puts "Attractor version #{Attractor::VERSION}"
25
- rescue RuntimeError => e
26
- puts "Runtime error: #{e.message}"
27
- end
28
-
29
- desc "calc", "Calculates churn and complexity for all ruby files in current directory"
30
- shared_options.each do |shared_option|
31
- option(*shared_option)
32
- end
33
- def calc
34
- file_prefix = options[:file_prefix]
35
-
36
- report! Attractor::ConsoleReporter.new(file_prefix: file_prefix, ignores: options[:ignore], calculators: calculators(options))
37
- rescue RuntimeError => e
38
- puts "Runtime error: #{e.message}"
39
- end
40
-
41
- desc "report", "Generates an HTML report"
42
- (shared_options + advanced_options).each do |option|
43
- option(*option)
44
- end
45
- def report
46
- file_prefix = options[:file_prefix]
47
- open_browser = !(options[:no_open_browser] || options[:ci])
48
-
49
- report! Attractor::HtmlReporter.new(file_prefix: file_prefix, ignores: options[:ignore], calculators: calculators(options), open_browser: open_browser)
50
- rescue RuntimeError => e
51
- puts "Runtime error: #{e.message}"
52
- end
53
-
54
- desc "serve", "Serves the report on localhost"
55
- (shared_options + advanced_options).each do |option|
56
- option(*option)
57
- end
58
- def serve
59
- file_prefix = options[:file_prefix]
60
- open_browser = !(options[:no_open_browser] || options[:ci])
61
-
62
- report! Attractor::SinatraReporter.new(file_prefix: file_prefix, ignores: options[:ignore], calculators: calculators(options), open_browser: open_browser)
63
- end
64
-
65
- private
66
-
67
- def calculators(options)
68
- Attractor.calculators_for_type(options[:type],
69
- file_prefix: options[:file_prefix],
70
- minimum_churn_count: options[:minimum_churn],
71
- ignores: options[:ignore],
72
- start_ago: options[:start_ago])
73
- end
74
-
75
- def report!(reporter)
76
- if options[:watch]
77
- puts "Listening for file changes..."
78
- reporter.watch
79
- else
80
- reporter.report
81
- end
82
- end
83
- end
84
- end
@@ -1,4 +0,0 @@
1
- module Attractor
2
- class BaseDetector
3
- end
4
- end
@@ -1,27 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Attractor
4
- # converts a duration string into an amount of days
5
- class DurationParser
6
- TOKENS = {
7
- "d" => 1,
8
- "w" => 7,
9
- "m" => 30,
10
- "y" => 365
11
- }.freeze
12
-
13
- attr_reader :duration
14
-
15
- def initialize(input)
16
- @input = input
17
- @duration = 0
18
- parse
19
- end
20
-
21
- def parse
22
- @input.scan(/(\d+)(\w)/).each do |amount, measure|
23
- @duration += amount.to_i * TOKENS[measure]
24
- end
25
- end
26
- end
27
- 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(calculators:, file_prefix: "", ignores: "", 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, ignores, 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
@@ -1,48 +0,0 @@
1
- module Attractor
2
- # HTML reporter
3
- class HtmlReporter < BaseReporter
4
- def report
5
- super
6
-
7
- puts 'Generating an HTML report'
8
- @serve_static = true
9
-
10
- FileUtils.mkdir_p './attractor_output'
11
- FileUtils.mkdir_p './attractor_output/stylesheets'
12
- FileUtils.mkdir_p './attractor_output/images'
13
- FileUtils.mkdir_p './attractor_output/javascripts'
14
-
15
- File.open('./attractor_output/images/attractor_logo.svg', 'w') { |file| file.write(logo) }
16
- File.open('./attractor_output/stylesheets/main.css', 'w') { |file| file.write(css) }
17
- File.open('./attractor_output/javascripts/index.js', 'w') { |file| file.write(javascript) }
18
- File.open('./attractor_output/javascripts/index.pack.js', 'w') { |file| file.write(javascript_pack) }
19
-
20
- File.open('./attractor_output/index.html', 'w') { |file| file.write(render) }
21
- puts "Generated HTML report at #{File.expand_path './attractor_output/index.html'}"
22
-
23
- Launchy.open(File.expand_path('./attractor_output/index.html'))
24
- end
25
-
26
- def logo
27
- File.read(File.expand_path('../../../app/assets/images/attractor_logo.svg', __dir__))
28
- end
29
-
30
- def css
31
- File.read(File.expand_path('../../../app/assets/stylesheets/main.css', __dir__))
32
- end
33
-
34
- def javascript_pack
35
- File.read(File.expand_path('../../../app/assets/javascripts/index.pack.js', __dir__))
36
- end
37
-
38
- def javascript
39
- template = Tilt.new(File.expand_path('../../../app/assets/javascripts/index.js.erb', __dir__))
40
- template.render self
41
- end
42
-
43
- def render
44
- template = Tilt.new(File.expand_path('../../../app/views/index.html.erb', __dir__))
45
- template.render self
46
- end
47
- end
48
- end
@@ -1 +0,0 @@
1
- {"churn":{"changes":[{"file_path":"app/assets/javascripts/index.pack.js","times_changed":21},{"file_path":"src/javascript/functions.js","times_changed":16},{"file_path":"src/javascript/index.js","times_changed":4}],"class_churn":[],"method_churn":[],"changed_files":[".gitignore","Rakefile","attractor.gemspec","lib/attractor.rb","lib/attractor/calculators/js_calculator.rb","lib/attractor/cli.rb","src/javascript/calculator/index.js","src/javascript/calculator/package-lock.json","src/javascript/calculator/package.json","src/javascript/calculator/webpack.config.js"],"changed_classes":[],"changed_methods":[]}}
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "json"
4
-
5
- module Attractor
6
- # holds a churn/complexity value
7
- class Value
8
- attr_reader :file_path, :churn, :complexity, :details, :history
9
-
10
- def initialize(file_path: "", churn: 1, complexity: 0, details: [], history: [])
11
- @file_path = file_path
12
- @churn = churn
13
- @complexity = complexity
14
- @details = details
15
- @history = history
16
- end
17
-
18
- def to_s
19
- format("%-64s%8.1f%8i", @file_path, @complexity, @churn)
20
- end
21
-
22
- def to_h
23
- {file_path: file_path, x: churn, y: complexity, details: details, history: history}
24
- end
25
-
26
- def to_json(_opt)
27
- to_h.to_json
28
- end
29
- end
30
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Attractor
4
- # functionality for watching file system changes
5
- class Watcher
6
- def initialize(file_prefix, callback)
7
- @file_prefix = file_prefix
8
- @callback = callback
9
- end
10
-
11
- def watch
12
- @callback.call
13
-
14
- listener = Listen.to(@file_prefix, ignore: /^attractor_output/) do |modified, _added, _removed|
15
- if modified
16
- puts "#{modified.map(&:to_s).join(', ')} modified, recalculating..."
17
- @callback.call
18
- end
19
- end
20
- listener.start
21
- sleep
22
- end
23
- end
24
- end
data/lib/attractor.rb~ DELETED
@@ -1,44 +0,0 @@
1
- # frozen_string_literal: true
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
- require "attractor/cache"
12
-
13
- Dir[File.join(__dir__, "attractor", "reporters", "*.rb")].sort.each do |file|
14
- next if file.start_with?("base")
15
-
16
- require file
17
- end
18
-
19
- module Attractor
20
- class Error < StandardError; end
21
-
22
- @registry_entries = {}
23
-
24
- def register(registry_entry)
25
- @registry_entries[registry_entry.type] = registry_entry
26
- end
27
-
28
- def calculators_for_type(type, **options)
29
- registry_entry_for_type = @registry_entries[type]
30
-
31
- return {type => registry_entry_for_type.calculator_class.new(**options)} if type
32
-
33
- Hash[@registry_entries.map do |type, entry|
34
- [type, entry.calculator_class.new(**options)] if entry.detector_class.new.detect
35
- end.compact]
36
- end
37
-
38
- module_function :calculators_for_type
39
- module_function :register
40
- end
41
-
42
- Attractor::GemNames.new.to_a.each do |gem_name|
43
- require "attractor/#{gem_name}"
44
- end