attractor 2.0.5 → 2.1.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 +4 -4
- data/README.md +3 -0
- data/Rakefile +13 -13
- data/exe/attractor +1 -1
- data/lib/attractor.rb +12 -13
- data/lib/attractor/calculators/base_calculator.rb +9 -7
- data/lib/attractor/cli.rb +33 -44
- data/lib/attractor/duration_parser.rb +4 -4
- data/lib/attractor/gem_names.rb +1 -1
- data/lib/attractor/registry_entry.rb +0 -1
- data/lib/attractor/reporters/base_reporter.rb +13 -13
- data/lib/attractor/reporters/console_reporter.rb +4 -4
- data/lib/attractor/reporters/html_reporter.rb +22 -23
- data/lib/attractor/reporters/sinatra_reporter.rb +17 -17
- data/lib/attractor/suggester.rb +2 -2
- data/lib/attractor/value.rb +4 -4
- data/lib/attractor/version.rb +1 -1
- data/lib/attractor/watcher.rb +5 -3
- metadata +10 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a044632a13376f395112a65b938be9c3173a16499f4eab725e97afffc1e83925
|
4
|
+
data.tar.gz: 20aafed307f3cf4f047130aa6aafc2395838ba50ecf48dedc0bd205fe5e6c391
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 12a4dd82ff8d50a7d5e7c3663b6b013e93d6575a706581c7b64a5bbb75714d9d8126c3f24344f57e2c5c79905ea549e82370def04fb6643ff25fbc38f365c846
|
7
|
+
data.tar.gz: f27f15c33b573ab2cccb9be34d59f89c12575e19fe18454d5380c4fd500f98e63e2b0e8be2bd4e7a86c18512124fb6792e5f625101ef4e8333b54bf59a03a165
|
data/README.md
CHANGED
@@ -195,6 +195,7 @@ attractor calc
|
|
195
195
|
--watch|-w
|
196
196
|
--start_ago|-s (e.g. 5y, 3m, 7w)
|
197
197
|
--minimum_churn|-c (minimum times a file must have changed to be processed)
|
198
|
+
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
|
198
199
|
```
|
199
200
|
|
200
201
|
Generate a full report
|
@@ -207,6 +208,7 @@ attractor report
|
|
207
208
|
--no-open-browser|--ci
|
208
209
|
--start_ago|-s (e.g. 5y, 3m, 7w)
|
209
210
|
--minimum_churn|-c (minimum times a file must have changed to be processed)
|
211
|
+
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
|
210
212
|
```
|
211
213
|
|
212
214
|
Serve the output on `http://localhost:7890`
|
@@ -218,6 +220,7 @@ attractor serve
|
|
218
220
|
--no-open-browser|--ci
|
219
221
|
--start_ago|-s (e.g. 5y, 3m, 7w)
|
220
222
|
--minimum_churn|-c (minimum times a file must have changed to be processed)
|
223
|
+
--ignore|-i 'spec/*_spec.rb,db/schema.rb,tmp'
|
221
224
|
```
|
222
225
|
|
223
226
|
## Development
|
data/Rakefile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
3
|
+
require "autoprefixer-rails"
|
4
|
+
require "bootstrap"
|
5
|
+
require "bundler/gem_tasks"
|
6
|
+
require "fileutils"
|
7
|
+
require "rspec/core/rake_task"
|
8
|
+
require "sassc"
|
9
|
+
require "structured_changelog/tasks"
|
10
10
|
|
11
11
|
RSpec::Core::RakeTask.new(:spec)
|
12
12
|
|
@@ -14,18 +14,18 @@ task default: :spec
|
|
14
14
|
|
15
15
|
task build: :assets
|
16
16
|
|
17
|
-
desc
|
17
|
+
desc "Preprocess assets"
|
18
18
|
task :assets do
|
19
|
-
puts
|
19
|
+
puts "Preprocessing SCSS and JS files"
|
20
20
|
|
21
|
-
puts
|
21
|
+
puts "Copying over bootstrap"
|
22
22
|
|
23
|
-
FileUtils.cp_r Gem::Specification.find_by_name(
|
23
|
+
FileUtils.cp_r Gem::Specification.find_by_name("bootstrap").gem_dir, "tmp"
|
24
24
|
|
25
|
-
sass = File.read(File.expand_path(
|
25
|
+
sass = File.read(File.expand_path("./src/stylesheets/main.scss"))
|
26
26
|
css = SassC::Engine.new(sass, style: :compressed).render
|
27
27
|
prefixed = AutoprefixerRails.process(css)
|
28
|
-
File.open(File.expand_path(
|
28
|
+
File.open(File.expand_path("./app/assets/stylesheets/main.css"), "w") { |file| file.write(prefixed) }
|
29
29
|
|
30
30
|
npm_output = `npm run build`
|
31
31
|
puts npm_output
|
data/exe/attractor
CHANGED
data/lib/attractor.rb
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
|
12
|
-
Dir[File.join(__dir__,
|
13
|
-
next if file.start_with?(
|
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")].sort.each do |file|
|
13
|
+
next if file.start_with?("base")
|
14
14
|
|
15
15
|
require file
|
16
16
|
end
|
@@ -27,9 +27,8 @@ module Attractor
|
|
27
27
|
def calculators_for_type(type, **options)
|
28
28
|
registry_entry_for_type = @registry_entries[type]
|
29
29
|
|
30
|
-
return {
|
30
|
+
return {type => registry_entry_for_type.calculator_class.new(**options)} if type
|
31
31
|
|
32
|
-
|
33
32
|
Hash[@registry_entries.map do |type, entry|
|
34
33
|
[type, entry.calculator_class.new(**options)] if entry.detector_class.new.detect
|
35
34
|
end.compact]
|
@@ -1,19 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "churn/calculator"
|
4
4
|
|
5
|
-
require
|
5
|
+
require "attractor/value"
|
6
6
|
|
7
7
|
module Attractor
|
8
8
|
# calculates churn and complexity
|
9
9
|
class BaseCalculator
|
10
10
|
attr_reader :type
|
11
11
|
|
12
|
-
def initialize(file_prefix:
|
12
|
+
def initialize(file_prefix: "", ignores: "", file_extension: "rb", minimum_churn_count: 3, start_ago: "5y")
|
13
13
|
@file_prefix = file_prefix
|
14
14
|
@file_extension = file_extension
|
15
15
|
@minimum_churn_count = minimum_churn_count
|
16
16
|
@start_date = Date.today - Attractor::DurationParser.new(start_ago).duration
|
17
|
+
@ignores = ignores
|
17
18
|
end
|
18
19
|
|
19
20
|
def calculate
|
@@ -21,7 +22,8 @@ module Attractor
|
|
21
22
|
file_extension: @file_extension,
|
22
23
|
file_prefix: @file_prefix,
|
23
24
|
minimum_churn_count: @minimum_churn_count,
|
24
|
-
start_date: @start_date
|
25
|
+
start_date: @start_date,
|
26
|
+
ignores: @ignores
|
25
27
|
).report(false)
|
26
28
|
|
27
29
|
churn[:churn][:changes].map do |change|
|
@@ -39,10 +41,10 @@ module Attractor
|
|
39
41
|
def git_history_for_file(file_path:, limit: 10)
|
40
42
|
history = `git log --oneline -n #{limit} -- #{file_path}`
|
41
43
|
history.split("\n")
|
42
|
-
|
44
|
+
.map do |log_entry|
|
43
45
|
log_entry.partition(/\A(\S+)\s/)
|
44
|
-
|
45
|
-
|
46
|
+
.map(&:strip)
|
47
|
+
.reject(&:empty?)
|
46
48
|
end
|
47
49
|
end
|
48
50
|
end
|
data/lib/attractor/cli.rb
CHANGED
@@ -1,95 +1,84 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "thor"
|
4
4
|
|
5
|
-
require
|
5
|
+
require "attractor"
|
6
6
|
|
7
7
|
module Attractor
|
8
8
|
# contains methods implementing the CLI
|
9
9
|
class CLI < Thor
|
10
10
|
shared_options = [[:file_prefix, aliases: :p],
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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]]
|
15
16
|
|
16
|
-
advanced_options = [[:format, aliases: :f, default:
|
17
|
-
|
18
|
-
|
17
|
+
advanced_options = [[:format, aliases: :f, default: "html"],
|
18
|
+
[:no_open_browser, type: :boolean],
|
19
|
+
[:ci, type: :boolean]]
|
19
20
|
|
20
21
|
desc "version", "Prints Attractor's version information"
|
21
|
-
map %w
|
22
|
+
map %w[-v --version] => :version
|
22
23
|
def version
|
23
24
|
puts "Attractor version #{Attractor::VERSION}"
|
24
25
|
rescue RuntimeError => e
|
25
26
|
puts "Runtime error: #{e.message}"
|
26
27
|
end
|
27
28
|
|
28
|
-
desc
|
29
|
+
desc "calc", "Calculates churn and complexity for all ruby files in current directory"
|
29
30
|
shared_options.each do |shared_option|
|
30
31
|
option(*shared_option)
|
31
32
|
end
|
32
33
|
def calc
|
33
34
|
file_prefix = options[:file_prefix]
|
34
|
-
|
35
|
-
|
36
|
-
Attractor::ConsoleReporter.new(file_prefix: file_prefix, calculators: calculators(options)).watch
|
37
|
-
else
|
38
|
-
Attractor::ConsoleReporter.new(file_prefix: file_prefix, calculators: calculators(options)).report
|
39
|
-
end
|
35
|
+
|
36
|
+
report! Attractor::ConsoleReporter.new(file_prefix: file_prefix, ignores: options[:ignore], calculators: calculators(options))
|
40
37
|
rescue RuntimeError => e
|
41
38
|
puts "Runtime error: #{e.message}"
|
42
39
|
end
|
43
40
|
|
44
|
-
desc
|
41
|
+
desc "report", "Generates an HTML report"
|
45
42
|
(shared_options + advanced_options).each do |option|
|
46
43
|
option(*option)
|
47
44
|
end
|
48
45
|
def report
|
49
46
|
file_prefix = options[:file_prefix]
|
50
47
|
open_browser = !(options[:no_open_browser] || options[:ci])
|
51
|
-
|
52
|
-
|
53
|
-
Attractor::HtmlReporter.new(file_prefix: file_prefix, calculators: calculators(options), open_browser: open_browser).watch
|
54
|
-
else
|
55
|
-
case options[:format]
|
56
|
-
when 'html'
|
57
|
-
Attractor::HtmlReporter.new(file_prefix: file_prefix, calculators: calculators(options), open_browser: open_browser).report
|
58
|
-
else
|
59
|
-
Attractor::HtmlReporter.new(file_prefix: file_prefix, calculators: calculators(options), open_browser: open_browser).report
|
60
|
-
end
|
61
|
-
end
|
48
|
+
|
49
|
+
report! Attractor::HtmlReporter.new(file_prefix: file_prefix, ignores: options[:ignore], calculators: calculators(options), open_browser: open_browser)
|
62
50
|
rescue RuntimeError => e
|
63
51
|
puts "Runtime error: #{e.message}"
|
64
52
|
end
|
65
53
|
|
66
|
-
desc
|
54
|
+
desc "serve", "Serves the report on localhost"
|
67
55
|
(shared_options + advanced_options).each do |option|
|
68
56
|
option(*option)
|
69
57
|
end
|
70
58
|
def serve
|
71
59
|
file_prefix = options[:file_prefix]
|
72
60
|
open_browser = !(options[:no_open_browser] || options[:ci])
|
73
|
-
|
74
|
-
|
75
|
-
Attractor::SinatraReporter.new(file_prefix: file_prefix, calculators: calculators(options), open_browser: open_browser).watch
|
76
|
-
else
|
77
|
-
case options[:format]
|
78
|
-
when 'html'
|
79
|
-
Attractor::SinatraReporter.new(file_prefix: file_prefix, calculators: calculators(options), open_browser: open_browser).report
|
80
|
-
else
|
81
|
-
Attractor::SinatraReporter.new(file_prefix: file_prefix, calculators: calculators(options), open_browser: open_browser).report
|
82
|
-
end
|
83
|
-
end
|
61
|
+
|
62
|
+
report! Attractor::SinatraReporter.new(file_prefix: file_prefix, ignores: options[:ignore], calculators: calculators(options), open_browser: open_browser)
|
84
63
|
end
|
85
64
|
|
86
65
|
private
|
87
66
|
|
88
67
|
def calculators(options)
|
89
68
|
Attractor.calculators_for_type(options[:type],
|
90
|
-
|
91
|
-
|
92
|
-
|
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
|
93
82
|
end
|
94
83
|
end
|
95
84
|
end
|
data/lib/attractor/gem_names.rb
CHANGED
@@ -2,7 +2,7 @@ module Attractor
|
|
2
2
|
# from https://github.com/prontolabs/pronto/blob/master/lib/pronto/gem_names.rb
|
3
3
|
class GemNames
|
4
4
|
def to_a
|
5
|
-
gems.map { |gem| gem.name.sub(/^attractor-/,
|
5
|
+
gems.map { |gem| gem.name.sub(/^attractor-/, "") }.uniq.sort
|
6
6
|
end
|
7
7
|
|
8
8
|
private
|
@@ -1,10 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
7
|
-
require
|
3
|
+
require "descriptive_statistics/safe"
|
4
|
+
require "fileutils"
|
5
|
+
require "forwardable"
|
6
|
+
require "launchy"
|
7
|
+
require "tilt"
|
8
8
|
|
9
9
|
module Attractor
|
10
10
|
# base reporter
|
@@ -15,21 +15,21 @@ module Attractor
|
|
15
15
|
attr_writer :values
|
16
16
|
def_delegator :@watcher, :watch
|
17
17
|
|
18
|
-
def initialize(
|
18
|
+
def initialize(calculators:, file_prefix: "", ignores: "", open_browser: true)
|
19
19
|
@file_prefix = file_prefix || ""
|
20
20
|
@calculators = calculators
|
21
21
|
@open_browser = open_browser
|
22
22
|
@values = @calculators.first.last.calculate
|
23
23
|
@suggester = Suggester.new(values)
|
24
24
|
|
25
|
-
@watcher = Watcher.new(@file_prefix, lambda do
|
25
|
+
@watcher = Watcher.new(@file_prefix, ignores, lambda do
|
26
26
|
report
|
27
27
|
end)
|
28
|
-
rescue NoMethodError =>
|
29
|
-
raise
|
28
|
+
rescue NoMethodError => _e
|
29
|
+
raise "There was a problem gathering churn changes"
|
30
30
|
end
|
31
31
|
|
32
|
-
def suggestions(quantile:, type:
|
32
|
+
def suggestions(quantile:, type: "rb")
|
33
33
|
@suggester.values = values(type: type)
|
34
34
|
@suggestions = @suggester.suggest(quantile)
|
35
35
|
@suggestions
|
@@ -41,13 +41,13 @@ module Attractor
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def render
|
44
|
-
|
44
|
+
"Attractor"
|
45
45
|
end
|
46
46
|
|
47
|
-
def values(type:
|
47
|
+
def values(type: "rb")
|
48
48
|
@values = @calculators[type].calculate
|
49
49
|
@values
|
50
|
-
rescue NoMethodError =>
|
50
|
+
rescue NoMethodError => _e
|
51
51
|
puts "No calculator for type #{type}"
|
52
52
|
end
|
53
53
|
end
|
@@ -5,10 +5,10 @@ module Attractor
|
|
5
5
|
class ConsoleReporter < BaseReporter
|
6
6
|
def report
|
7
7
|
super
|
8
|
-
puts
|
8
|
+
puts "Calculated churn and complexity"
|
9
9
|
puts
|
10
|
-
puts "file_path#{
|
11
|
-
puts
|
10
|
+
puts "file_path#{" " * 53}complexity churn"
|
11
|
+
puts "-" * 80
|
12
12
|
|
13
13
|
@calculators.each do |calc|
|
14
14
|
# e.g. ['js', JsCalculator']
|
@@ -19,7 +19,7 @@ module Attractor
|
|
19
19
|
|
20
20
|
puts values&.map(&:to_s)
|
21
21
|
puts
|
22
|
-
puts
|
22
|
+
puts "Suggestions for refactorings:"
|
23
23
|
suggester.suggest&.each { |sug| puts sug.file_path }
|
24
24
|
puts
|
25
25
|
end
|
@@ -6,18 +6,18 @@ module Attractor
|
|
6
6
|
def report
|
7
7
|
super
|
8
8
|
|
9
|
-
puts
|
9
|
+
puts "Generating an HTML report"
|
10
10
|
@serve_static = true
|
11
11
|
|
12
|
-
FileUtils.mkdir_p
|
13
|
-
FileUtils.mkdir_p
|
14
|
-
FileUtils.mkdir_p
|
15
|
-
FileUtils.mkdir_p
|
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(
|
18
|
-
File.open(
|
19
|
-
File.open(
|
20
|
-
File.open(
|
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",
|
29
|
-
File.open("./attractor_output/index.#{@short_type}.html",
|
30
|
-
puts "Generated HTML report at #{File.expand_path
|
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(
|
39
|
-
File.open(
|
40
|
-
puts "Generated HTML report at #{File.expand_path
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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(
|
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
|
4
|
-
require
|
5
|
-
require
|
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(
|
16
|
+
set :public_folder, File.expand_path("../../../app/assets", __dir__)
|
17
17
|
set :show_exceptions, :after_handler
|
18
18
|
|
19
|
-
get
|
19
|
+
get "/" do
|
20
20
|
@types = @reporter.types
|
21
|
-
erb File.read(File.expand_path(
|
21
|
+
erb File.read(File.expand_path("../../../app/views/index.html.erb", __dir__))
|
22
22
|
end
|
23
23
|
|
24
|
-
get
|
25
|
-
{
|
24
|
+
get "/file_prefix" do
|
25
|
+
{file_prefix: @reporter.file_prefix}.to_json
|
26
26
|
end
|
27
27
|
|
28
|
-
get
|
29
|
-
type = params[:type] ||
|
28
|
+
get "/values" do
|
29
|
+
type = params[:type] || "rb"
|
30
30
|
@reporter.values(type: type).to_json
|
31
31
|
end
|
32
32
|
|
33
|
-
get
|
33
|
+
get "/suggestions" do
|
34
34
|
threshold = params[:t] || 95
|
35
|
-
type = params[:type] ||
|
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
|
-
{
|
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
|
51
|
+
puts "Serving attractor at http://localhost:7890"
|
52
52
|
|
53
53
|
if @open_browser
|
54
|
-
Launchy.open(
|
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
|
66
|
+
puts "Serving attractor at http://localhost:7890"
|
67
67
|
if @open_browser
|
68
|
-
Launchy.open(
|
68
|
+
Launchy.open("http://localhost:7890")
|
69
69
|
puts "Opening browser window..."
|
70
70
|
end
|
71
71
|
|
data/lib/attractor/suggester.rb
CHANGED
@@ -4,7 +4,7 @@ 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
|
@@ -15,7 +15,7 @@ module Attractor
|
|
15
15
|
quantile = products.percentile(threshold.to_i)
|
16
16
|
|
17
17
|
@values.select { |val| val.churn * val.complexity > quantile }
|
18
|
-
|
18
|
+
.sort_by { |val| val.churn * val.complexity }.reverse
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
data/lib/attractor/value.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
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:
|
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
|
@@ -16,11 +16,11 @@ module Attractor
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def to_s
|
19
|
-
format(
|
19
|
+
format("%-64s%8.1f%8i", @file_path, @complexity, @churn)
|
20
20
|
end
|
21
21
|
|
22
22
|
def to_h
|
23
|
-
{
|
23
|
+
{file_path: file_path, x: churn, y: complexity, details: details, history: history}
|
24
24
|
end
|
25
25
|
|
26
26
|
def to_json(_opt)
|
data/lib/attractor/version.rb
CHANGED
data/lib/attractor/watcher.rb
CHANGED
@@ -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:
|
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(
|
20
|
+
puts "#{modified.map(&:to_s).join(", ")} modified, recalculating..."
|
19
21
|
@callback.call
|
20
22
|
end
|
21
23
|
end
|
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
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julian Rubisch
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-04-01 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:
|
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:
|
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:
|
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:
|
180
|
+
version: 0.2.0
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: autoprefixer-rails
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|