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.
- checksums.yaml +4 -4
- data/README.md +29 -6
- data/Rakefile +13 -13
- data/exe/attractor +1 -1
- data/lib/attractor/cache.rb +82 -0
- data/lib/attractor/calculators/base_calculator.rb +38 -14
- data/lib/attractor/cli.rb +50 -44
- data/lib/attractor/duration_parser.rb +7 -5
- data/lib/attractor/gem_names.rb +1 -1
- data/lib/attractor/registry_entry.rb +0 -1
- data/lib/attractor/reporters/base_reporter.rb +14 -15
- data/lib/attractor/reporters/console_reporter.rb +55 -16
- data/lib/attractor/reporters/html_reporter.rb +22 -23
- data/lib/attractor/reporters/sinatra_reporter.rb +17 -17
- data/lib/attractor/suggester.rb +4 -4
- data/lib/attractor/value.rb +12 -4
- data/lib/attractor/version.rb +1 -1
- data/lib/attractor/version.rb~ +7 -0
- data/lib/attractor/watcher.rb +5 -3
- data/lib/attractor.rb +31 -15
- metadata +15 -25
- data/lib/attractor/#duration_parser.rb# +0 -24
- data/lib/attractor/calculators/base_calculator.rb~ +0 -54
- data/lib/attractor/detectors/base_detector.rb~ +0 -4
- data/lib/attractor/duration_parser.rb~ +0 -23
- data/lib/attractor/gem_names.rb~ +0 -23
- data/lib/attractor/registry_entry.rb~ +0 -2
- data/lib/attractor/reporters/base_reporter.rb~ +0 -54
- data/lib/attractor/reporters/console_reporter.rb~ +0 -21
- data/lib/attractor/reporters/html_reporter.rb~ +0 -48
- data/lib/attractor/tmp/churn/9f86bc9b7ec6bf59cbf7a111ce8b1159ae128347.json +0 -1
- data/lib/attractor/watcher.rb~ +0 -24
- data/lib/attractor.rb~ +0 -44
@@ -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,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
|
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.
|
18
|
-
|
17
|
+
@values.select { |val| val.score > quantile }
|
18
|
+
.sort_by { |val| val.score }.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
|
@@ -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(
|
27
|
+
format("%-64s%8.1f%8i", @file_path, @complexity, @churn)
|
20
28
|
end
|
21
29
|
|
22
30
|
def to_h
|
23
|
-
{
|
31
|
+
{file_path: file_path, x: churn, y: complexity, details: details, history: history}
|
24
32
|
end
|
25
33
|
|
26
34
|
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
|
data/lib/attractor.rb
CHANGED
@@ -1,16 +1,17 @@
|
|
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
|
-
|
13
|
-
|
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 {
|
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
|
-
|
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
|
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-
|
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:
|
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
|
@@ -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,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
|
data/lib/attractor/gem_names.rb~
DELETED
@@ -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,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
|