attractor 2.3.0 → 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.
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