attractor 2.4.0 → 2.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/lib/attractor/calculators/base_calculator.rb +5 -4
- data/lib/attractor/calculators/base_calculator.rb~ +73 -0
- data/lib/attractor/cli.rb +3 -1
- data/lib/attractor/cli.rb~ +101 -0
- data/lib/attractor/reporters/base_reporter.rb +1 -1
- data/lib/attractor/reporters/base_reporter.rb~ +53 -0
- data/lib/attractor/reporters/console_reporter.rb +31 -4
- data/lib/attractor/reporters/console_reporter.rb~ +67 -0
- data/lib/attractor/reporters/html_reporter.rb +8 -8
- data/lib/attractor/suggester.rb +2 -2
- data/lib/attractor/suggester.rb~ +21 -0
- data/lib/attractor/version.rb +1 -1
- data/lib/attractor/version.rb~ +0 -4
- metadata +15 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1eef3d6e8104428fdc8240ae5161654990b53d5351962bc474f11e450db9cbc2
|
4
|
+
data.tar.gz: 6ec7109f7c6aa6e4b5b594863e5bfeff08652f2fdf6c8c2a86a208357c084713
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 244a2d549ba546424c7a4c25aaa59c17b4bd1a8fed73cbdd09851c4296631c4b42d907d4b31a76a8a4f6c584143d8f086764299e00e690bce1f0f19cc69d8bcb
|
7
|
+
data.tar.gz: d508623821df269d803f3fdb0440fbd76f14a5d24cbd169c23cfabf01e1423171b201b1c3ee2c92a986ada20700c790c67ff75d3928bfbf9e4e1d2419e60be65
|
data/Rakefile
CHANGED
@@ -25,7 +25,7 @@ task :assets do
|
|
25
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.
|
28
|
+
File.write(File.expand_path("./app/assets/stylesheets/main.css"), prefixed)
|
29
29
|
|
30
30
|
npm_output = `npm run build`
|
31
31
|
puts npm_output
|
@@ -9,12 +9,13 @@ module Attractor
|
|
9
9
|
class BaseCalculator
|
10
10
|
attr_reader :type
|
11
11
|
|
12
|
-
def initialize(file_prefix: "", ignores: "", file_extension: "rb", minimum_churn_count: 3, start_ago: "5y")
|
12
|
+
def initialize(file_prefix: "", ignores: "", file_extension: "rb", minimum_churn_count: 3, start_ago: "5y", verbose: false)
|
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
17
|
@ignores = ignores
|
18
|
+
@verbose = verbose
|
18
19
|
end
|
19
20
|
|
20
21
|
def calculate
|
@@ -26,7 +27,7 @@ module Attractor
|
|
26
27
|
ignores: @ignores
|
27
28
|
).report(false)
|
28
29
|
|
29
|
-
puts "Calculating churn and complexity values for #{churn[:churn][:changes].size} #{type} files"
|
30
|
+
puts "Calculating churn and complexity values for #{churn[:churn][:changes].size} #{type} files" if @verbose
|
30
31
|
|
31
32
|
values = churn[:churn][:changes].map do |change|
|
32
33
|
history = git_history_for_file(file_path: change[:file_path])
|
@@ -47,13 +48,13 @@ module Attractor
|
|
47
48
|
Cache.write(file_path: change[:file_path], value: value)
|
48
49
|
end
|
49
50
|
|
50
|
-
print "."
|
51
|
+
print "." if @verbose
|
51
52
|
value
|
52
53
|
end
|
53
54
|
|
54
55
|
Cache.persist!
|
55
56
|
|
56
|
-
print "\n\n"
|
57
|
+
print "\n\n" if @verbose
|
57
58
|
|
58
59
|
values
|
59
60
|
end
|
@@ -0,0 +1,73 @@
|
|
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
|
+
puts "Calculating churn and complexity values for #{churn[:churn][:changes].size} #{type} files"
|
30
|
+
|
31
|
+
values = churn[:churn][:changes].map do |change|
|
32
|
+
history = git_history_for_file(file_path: change[:file_path])
|
33
|
+
commit = history&.first&.first
|
34
|
+
|
35
|
+
cached_value = Cache.read(file_path: change[:file_path])
|
36
|
+
|
37
|
+
if !cached_value.nil? && !cached_value.current_commit.nil? && cached_value.current_commit == commit
|
38
|
+
value = cached_value
|
39
|
+
else
|
40
|
+
complexity, details = yield(change)
|
41
|
+
|
42
|
+
value = Value.new(file_path: change[:file_path],
|
43
|
+
churn: change[:times_changed],
|
44
|
+
complexity: complexity,
|
45
|
+
details: details,
|
46
|
+
history: history)
|
47
|
+
Cache.write(file_path: change[:file_path], value: value)
|
48
|
+
end
|
49
|
+
|
50
|
+
print "."
|
51
|
+
value
|
52
|
+
end
|
53
|
+
|
54
|
+
Cache.persist!
|
55
|
+
|
56
|
+
print "\n\n"
|
57
|
+
|
58
|
+
values
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def git_history_for_file(file_path:, limit: 10)
|
64
|
+
history = `git log --oneline -n #{limit} -- #{file_path}`
|
65
|
+
history.split("\n")
|
66
|
+
.map do |log_entry|
|
67
|
+
log_entry.partition(/\A(\S+)\s/)
|
68
|
+
.map(&:strip)
|
69
|
+
.reject(&:empty?)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/attractor/cli.rb
CHANGED
@@ -8,6 +8,7 @@ module Attractor
|
|
8
8
|
# contains methods implementing the CLI
|
9
9
|
class CLI < Thor
|
10
10
|
shared_options = [[:file_prefix, aliases: :p],
|
11
|
+
[:verbose, aliases: :v, type: :boolean],
|
11
12
|
[:ignore, aliases: :i, default: ""],
|
12
13
|
[:watch, aliases: :w, type: :boolean],
|
13
14
|
[:minimum_churn, aliases: :c, type: :numeric, default: 3],
|
@@ -86,7 +87,8 @@ module Attractor
|
|
86
87
|
file_prefix: options[:file_prefix],
|
87
88
|
minimum_churn_count: options[:minimum_churn],
|
88
89
|
ignores: options[:ignore],
|
89
|
-
start_ago: options[:start_ago]
|
90
|
+
start_ago: options[:start_ago],
|
91
|
+
verbose: options[:verbose])
|
90
92
|
end
|
91
93
|
|
92
94
|
def report!(reporter)
|
@@ -0,0 +1,101 @@
|
|
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 "clean", "Clears attractor's cache"
|
30
|
+
def clean
|
31
|
+
puts "Clearing attractor cache"
|
32
|
+
Attractor.clear
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "init", "Initializes attractor's cache"
|
36
|
+
shared_options.each do |shared_option|
|
37
|
+
option(*shared_option)
|
38
|
+
end
|
39
|
+
def init
|
40
|
+
puts "Warming attractor cache"
|
41
|
+
Attractor.init(calculators(options))
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "calc", "Calculates churn and complexity for all ruby files in current directory"
|
45
|
+
shared_options.each do |shared_option|
|
46
|
+
option(*shared_option)
|
47
|
+
end
|
48
|
+
option(:format, aliases: :f, default: :table)
|
49
|
+
def calc
|
50
|
+
file_prefix = options[:file_prefix]
|
51
|
+
output_format = options[:format]
|
52
|
+
|
53
|
+
report! Attractor::ConsoleReporter.new(file_prefix: file_prefix, ignores: options[:ignore], calculators: calculators(options), format: output_format)
|
54
|
+
rescue RuntimeError => e
|
55
|
+
puts "Runtime error: #{e.message}"
|
56
|
+
end
|
57
|
+
|
58
|
+
desc "report", "Generates an HTML report"
|
59
|
+
(shared_options + advanced_options).each do |option|
|
60
|
+
option(*option)
|
61
|
+
end
|
62
|
+
def report
|
63
|
+
file_prefix = options[:file_prefix]
|
64
|
+
open_browser = !(options[:no_open_browser] || options[:ci])
|
65
|
+
|
66
|
+
report! Attractor::HtmlReporter.new(file_prefix: file_prefix, ignores: options[:ignore], calculators: calculators(options), open_browser: open_browser)
|
67
|
+
rescue RuntimeError => e
|
68
|
+
puts "Runtime error: #{e.message}"
|
69
|
+
end
|
70
|
+
|
71
|
+
desc "serve", "Serves the report on localhost"
|
72
|
+
(shared_options + advanced_options).each do |option|
|
73
|
+
option(*option)
|
74
|
+
end
|
75
|
+
def serve
|
76
|
+
file_prefix = options[:file_prefix]
|
77
|
+
open_browser = !(options[:no_open_browser] || options[:ci])
|
78
|
+
|
79
|
+
report! Attractor::SinatraReporter.new(file_prefix: file_prefix, ignores: options[:ignore], calculators: calculators(options), open_browser: open_browser)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def calculators(options)
|
85
|
+
Attractor.calculators_for_type(options[:type],
|
86
|
+
file_prefix: options[:file_prefix],
|
87
|
+
minimum_churn_count: options[:minimum_churn],
|
88
|
+
ignores: options[:ignore],
|
89
|
+
start_ago: options[:start_ago])
|
90
|
+
end
|
91
|
+
|
92
|
+
def report!(reporter)
|
93
|
+
if options[:watch]
|
94
|
+
puts "Listening for file changes..."
|
95
|
+
reporter.watch
|
96
|
+
else
|
97
|
+
reporter.report
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,53 @@
|
|
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
|
+
@suggester = Suggester.new(values)
|
23
|
+
|
24
|
+
@watcher = Watcher.new(@file_prefix, ignores, lambda do
|
25
|
+
report
|
26
|
+
end)
|
27
|
+
rescue NoMethodError => _e
|
28
|
+
raise "There was a problem gathering churn changes"
|
29
|
+
end
|
30
|
+
|
31
|
+
def suggestions(quantile:, type: "rb")
|
32
|
+
@suggester.values = values(type: type)
|
33
|
+
@suggestions = @suggester.suggest(quantile)
|
34
|
+
@suggestions
|
35
|
+
end
|
36
|
+
|
37
|
+
def report
|
38
|
+
@suggestions = @suggester.suggest
|
39
|
+
@types = @calculators.map { |calc| [calc.first, calc.last.type] }.to_h
|
40
|
+
end
|
41
|
+
|
42
|
+
def render
|
43
|
+
"Attractor"
|
44
|
+
end
|
45
|
+
|
46
|
+
def values(type: "rb")
|
47
|
+
@values = @calculators[type].calculate
|
48
|
+
@values
|
49
|
+
rescue NoMethodError => _e
|
50
|
+
puts "No calculator for type #{type}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -49,13 +49,40 @@ module Attractor
|
|
49
49
|
end
|
50
50
|
end
|
51
51
|
|
52
|
+
class JSONFormatter
|
53
|
+
def call(calculators)
|
54
|
+
result = calculators.map do |calc|
|
55
|
+
type = calc.last.type
|
56
|
+
values = calc.last.calculate
|
57
|
+
suggester = Suggester.new(values)
|
58
|
+
to_be_refactored = suggester.suggest.map(&:file_path)
|
59
|
+
|
60
|
+
[
|
61
|
+
type, values.map do |value|
|
62
|
+
{
|
63
|
+
file_path: value.file_path,
|
64
|
+
score: value.score,
|
65
|
+
complexity: value.complexity,
|
66
|
+
churn: value.churn,
|
67
|
+
refactor: to_be_refactored.include?(value.file_path)
|
68
|
+
}
|
69
|
+
end
|
70
|
+
]
|
71
|
+
end
|
72
|
+
|
73
|
+
puts result.to_h.to_json
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
52
77
|
def initialize(format:, **other)
|
53
78
|
super(**other)
|
54
79
|
@formatter = case format.to_sym
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
80
|
+
when :csv
|
81
|
+
CSVFormatter.new
|
82
|
+
when :json
|
83
|
+
JSONFormatter.new
|
84
|
+
else
|
85
|
+
TableFormatter.new
|
59
86
|
end
|
60
87
|
end
|
61
88
|
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Attractor
|
4
|
+
# console reporter
|
5
|
+
class ConsoleReporter < BaseReporter
|
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
|
+
|
13
|
+
calculators.each do |calc|
|
14
|
+
# e.g. ['js', JsCalculator']
|
15
|
+
puts calc.last.type
|
16
|
+
|
17
|
+
values = calc.last.calculate
|
18
|
+
suggester = Suggester.new(values)
|
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
|
25
|
+
end
|
26
|
+
end
|
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
|
66
|
+
end
|
67
|
+
end
|
@@ -14,10 +14,10 @@ module Attractor
|
|
14
14
|
FileUtils.mkdir_p "./attractor_output/images"
|
15
15
|
FileUtils.mkdir_p "./attractor_output/javascripts"
|
16
16
|
|
17
|
-
File.
|
18
|
-
File.
|
19
|
-
File.
|
20
|
-
File.
|
17
|
+
File.write("./attractor_output/images/attractor_logo.svg", logo)
|
18
|
+
File.write("./attractor_output/images/attractor_favicon.png", favicon)
|
19
|
+
File.write("./attractor_output/stylesheets/main.css", css)
|
20
|
+
File.write("./attractor_output/javascripts/index.pack.js", javascript_pack)
|
21
21
|
|
22
22
|
if @calculators.size > 1
|
23
23
|
@calculators.each do |calc|
|
@@ -25,8 +25,8 @@ module Attractor
|
|
25
25
|
suggester = Suggester.new(values(type: @short_type))
|
26
26
|
@suggestions = suggester.suggest
|
27
27
|
|
28
|
-
File.
|
29
|
-
File.
|
28
|
+
File.write("./attractor_output/javascripts/index.#{@short_type}.js", javascript)
|
29
|
+
File.write("./attractor_output/index.#{@short_type}.html", render)
|
30
30
|
puts "Generated HTML report at #{File.expand_path "./attractor_output/"}/index.#{@short_type}.html"
|
31
31
|
end
|
32
32
|
|
@@ -35,8 +35,8 @@ module Attractor
|
|
35
35
|
puts "Opening browser window..."
|
36
36
|
end
|
37
37
|
else
|
38
|
-
File.
|
39
|
-
File.
|
38
|
+
File.write("./attractor_output/javascripts/index.js", javascript)
|
39
|
+
File.write("./attractor_output/index.html", render)
|
40
40
|
puts "Generated HTML report at #{File.expand_path "./attractor_output/index.html"}"
|
41
41
|
|
42
42
|
if @open_browser
|
data/lib/attractor/suggester.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Attractor
|
4
|
+
# makes suggestions for refactorings
|
5
|
+
class Suggester
|
6
|
+
attr_accessor :values
|
7
|
+
|
8
|
+
def initialize(values)
|
9
|
+
@values = values || []
|
10
|
+
end
|
11
|
+
|
12
|
+
def suggest(threshold = 95)
|
13
|
+
products = @values.map(&:score)
|
14
|
+
products.extend(DescriptiveStatistics)
|
15
|
+
quantile = products.percentile(threshold.to_i)
|
16
|
+
|
17
|
+
@values.select { |val| val.score > quantile }
|
18
|
+
.sort_by { |val| val.score }.reverse
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/attractor/version.rb
CHANGED
data/lib/attractor/version.rb~
CHANGED
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.
|
4
|
+
version: 2.5.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:
|
11
|
+
date: 2023-04-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: churn
|
@@ -156,28 +156,28 @@ dependencies:
|
|
156
156
|
requirements:
|
157
157
|
- - "~>"
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: 0.
|
159
|
+
version: 0.3.0
|
160
160
|
type: :development
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version: 0.
|
166
|
+
version: 0.3.0
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
168
|
name: attractor-ruby
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
170
170
|
requirements:
|
171
171
|
- - "~>"
|
172
172
|
- !ruby/object:Gem::Version
|
173
|
-
version: 0.
|
173
|
+
version: 0.3.0
|
174
174
|
type: :development
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
178
|
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
|
-
version: 0.
|
180
|
+
version: 0.3.0
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: autoprefixer-rails
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -373,16 +373,21 @@ files:
|
|
373
373
|
- lib/attractor.rb
|
374
374
|
- lib/attractor/cache.rb
|
375
375
|
- lib/attractor/calculators/base_calculator.rb
|
376
|
+
- lib/attractor/calculators/base_calculator.rb~
|
376
377
|
- lib/attractor/cli.rb
|
378
|
+
- lib/attractor/cli.rb~
|
377
379
|
- lib/attractor/detectors/base_detector.rb
|
378
380
|
- lib/attractor/duration_parser.rb
|
379
381
|
- lib/attractor/gem_names.rb
|
380
382
|
- lib/attractor/registry_entry.rb
|
381
383
|
- lib/attractor/reporters/base_reporter.rb
|
384
|
+
- lib/attractor/reporters/base_reporter.rb~
|
382
385
|
- lib/attractor/reporters/console_reporter.rb
|
386
|
+
- lib/attractor/reporters/console_reporter.rb~
|
383
387
|
- lib/attractor/reporters/html_reporter.rb
|
384
388
|
- lib/attractor/reporters/sinatra_reporter.rb
|
385
389
|
- lib/attractor/suggester.rb
|
390
|
+
- lib/attractor/suggester.rb~
|
386
391
|
- lib/attractor/value.rb
|
387
392
|
- lib/attractor/version.rb
|
388
393
|
- lib/attractor/version.rb~
|
@@ -395,7 +400,7 @@ metadata:
|
|
395
400
|
source_code_uri: https://github.com/julianrubisch/attractor
|
396
401
|
bug_tracker_uri: https://github.com/julianrubisch/attractor/issues
|
397
402
|
changelog_uri: https://github.com/julianrubisch/attractor/CHANGELOG.md
|
398
|
-
post_install_message:
|
403
|
+
post_install_message:
|
399
404
|
rdoc_options: []
|
400
405
|
require_paths:
|
401
406
|
- lib
|
@@ -410,8 +415,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
410
415
|
- !ruby/object:Gem::Version
|
411
416
|
version: '0'
|
412
417
|
requirements: []
|
413
|
-
rubygems_version: 3.
|
414
|
-
signing_key:
|
418
|
+
rubygems_version: 3.4.12
|
419
|
+
signing_key:
|
415
420
|
specification_version: 4
|
416
421
|
summary: Churn vs Complexity Chart Generator
|
417
422
|
test_files: []
|