attractor 2.6.0 → 2.7.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 +35 -0
- data/app/assets/javascripts/index.pack.js +5 -5
- data/lib/attractor/cache.rb +36 -5
- data/lib/attractor/calculators/base_calculator.rb +51 -19
- data/lib/attractor/cli.rb +89 -16
- data/lib/attractor/config.rb +53 -0
- data/lib/attractor/diff_calculator.rb +127 -0
- data/lib/attractor/formatters/format_strategy.rb +20 -0
- data/lib/attractor/formatters/formats/csv.rb +20 -0
- data/lib/attractor/formatters/formats/json.rb +27 -0
- data/lib/attractor/formatters/formats/markdown.rb +40 -0
- data/lib/attractor/formatters/formats/table.rb +55 -0
- data/lib/attractor/formatters/formatter.rb +16 -0
- data/lib/attractor/formatters/report.rb +19 -0
- data/lib/attractor/formatters/targets/console.rb +47 -0
- data/lib/attractor/formatters/targets/diff.rb +25 -0
- data/lib/attractor/git.rb +51 -0
- data/lib/attractor/reporters/base_reporter.rb +1 -0
- data/lib/attractor/reporters/console_reporter.rb +13 -81
- data/lib/attractor/reporters/diff_reporter.rb +26 -0
- data/lib/attractor/suggester.rb +5 -2
- data/lib/attractor/value.rb +4 -1
- data/lib/attractor/version.rb +1 -1
- data/lib/attractor/watcher.rb +1 -1
- data/lib/attractor.rb +12 -8
- metadata +74 -8
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Attractor
|
|
4
|
+
module Formatters
|
|
5
|
+
class Formatter
|
|
6
|
+
def initialize(target:, format:)
|
|
7
|
+
@target = target
|
|
8
|
+
@format = format
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call(data)
|
|
12
|
+
@format.call(@target.call(data))
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Attractor
|
|
4
|
+
module Formatters
|
|
5
|
+
class Report
|
|
6
|
+
attr_reader :title, :metadata, :columns, :rows, :footer, :group_by, :rows_key
|
|
7
|
+
|
|
8
|
+
def initialize(title:, columns:, rows:, metadata: {}, footer: nil, group_by: nil, rows_key: :rows)
|
|
9
|
+
@title = title
|
|
10
|
+
@metadata = metadata
|
|
11
|
+
@columns = columns
|
|
12
|
+
@rows = rows
|
|
13
|
+
@footer = footer
|
|
14
|
+
@group_by = group_by
|
|
15
|
+
@rows_key = rows_key
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "attractor/formatters/report"
|
|
4
|
+
|
|
5
|
+
module Attractor
|
|
6
|
+
module Formatters
|
|
7
|
+
module Targets
|
|
8
|
+
class Console
|
|
9
|
+
def call(calculators)
|
|
10
|
+
rows = []
|
|
11
|
+
footer_lines = []
|
|
12
|
+
|
|
13
|
+
calculators.each do |type, calc|
|
|
14
|
+
values = calc.calculate
|
|
15
|
+
suggester = Suggester.new(values)
|
|
16
|
+
refactor_files = suggester.suggest.map(&:file_path)
|
|
17
|
+
|
|
18
|
+
values.each do |value|
|
|
19
|
+
rows << {
|
|
20
|
+
type: type,
|
|
21
|
+
file_path: value.file_path,
|
|
22
|
+
score: value.score,
|
|
23
|
+
complexity: value.complexity,
|
|
24
|
+
churn: value.churn,
|
|
25
|
+
refactor: refactor_files.include?(value.file_path),
|
|
26
|
+
details: value.details,
|
|
27
|
+
history: value.history
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
footer_lines << "Suggestions for refactorings:"
|
|
32
|
+
footer_lines += refactor_files unless refactor_files.empty?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
Report.new(
|
|
36
|
+
title: "Calculated churn and complexity",
|
|
37
|
+
metadata: {schema: 2},
|
|
38
|
+
columns: %i[file_path score complexity churn type refactor],
|
|
39
|
+
rows: rows,
|
|
40
|
+
footer: footer_lines.empty? ? nil : footer_lines.join("\n"),
|
|
41
|
+
group_by: :type
|
|
42
|
+
)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "attractor/formatters/report"
|
|
4
|
+
|
|
5
|
+
module Attractor
|
|
6
|
+
module Formatters
|
|
7
|
+
module Targets
|
|
8
|
+
class Diff
|
|
9
|
+
def call(data)
|
|
10
|
+
Report.new(
|
|
11
|
+
title: "Complexity diff between #{data[:base_ref]} and #{data[:head_ref]}",
|
|
12
|
+
metadata: {
|
|
13
|
+
total_score_base: data[:total_score_base],
|
|
14
|
+
total_score_head: data[:total_score_head],
|
|
15
|
+
trend: data[:trend]
|
|
16
|
+
},
|
|
17
|
+
columns: %i[file_path complexity_base complexity_head delta churn score_head refactor_base refactor_head],
|
|
18
|
+
rows: data[:files],
|
|
19
|
+
rows_key: :files
|
|
20
|
+
)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "fileutils"
|
|
4
|
+
require "tmpdir"
|
|
5
|
+
require "rugged"
|
|
6
|
+
|
|
7
|
+
module Attractor
|
|
8
|
+
module Git
|
|
9
|
+
def self.repo
|
|
10
|
+
@repo ||= Rugged::Repository.discover(".")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.validate_ref!(ref)
|
|
14
|
+
repo.rev_parse(ref)
|
|
15
|
+
rescue Rugged::ReferenceError
|
|
16
|
+
raise ArgumentError, "Invalid git ref: #{ref}"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def self.diff_files(base_ref, head_ref)
|
|
20
|
+
base_commit = repo.merge_base(base_ref, head_ref)
|
|
21
|
+
head_commit = repo.rev_parse(head_ref)
|
|
22
|
+
|
|
23
|
+
repo.diff(base_commit, head_commit).deltas.map { |delta| delta.new_file[:path] }.uniq
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class Worktree
|
|
27
|
+
attr_reader :path
|
|
28
|
+
|
|
29
|
+
def initialize(ref)
|
|
30
|
+
@ref = ref
|
|
31
|
+
@path = Dir.mktmpdir("attractor-diff-#{ref}-")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def checkout
|
|
35
|
+
success = system("git", "worktree", "add", "-f", @path, @ref, out: File::NULL, err: File::NULL)
|
|
36
|
+
raise "Failed to create git worktree for #{@ref} at #{@path}" unless success
|
|
37
|
+
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def cleanup
|
|
42
|
+
system("git", "worktree", "remove", "-f", @path, out: File::NULL, err: File::NULL)
|
|
43
|
+
FileUtils.rm_rf(@path)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def chdir(&block)
|
|
47
|
+
Dir.chdir(@path, &block)
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -1,96 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "attractor/formatters/formatter"
|
|
4
|
+
require "attractor/formatters/targets/console"
|
|
5
|
+
require "attractor/formatters/formats/json"
|
|
6
|
+
require "attractor/formatters/formats/table"
|
|
7
|
+
require "attractor/formatters/formats/csv"
|
|
8
|
+
require "attractor/formatters/format_strategy"
|
|
9
|
+
|
|
3
10
|
module Attractor
|
|
4
11
|
# console reporter
|
|
5
12
|
class ConsoleReporter < BaseReporter
|
|
6
|
-
|
|
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
|
-
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
|
-
details: value.details,
|
|
69
|
-
history: value.history
|
|
70
|
-
}
|
|
71
|
-
end
|
|
72
|
-
]
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
puts result.to_h.to_json
|
|
76
|
-
end
|
|
77
|
-
end
|
|
13
|
+
include Attractor::Formatters::FormatStrategy
|
|
78
14
|
|
|
79
15
|
def initialize(format:, **other)
|
|
80
16
|
super(**other)
|
|
81
|
-
@formatter =
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
JSONFormatter.new
|
|
86
|
-
else
|
|
87
|
-
TableFormatter.new
|
|
88
|
-
end
|
|
17
|
+
@formatter = Attractor::Formatters::Formatter.new(
|
|
18
|
+
target: Attractor::Formatters::Targets::Console.new,
|
|
19
|
+
format: format_strategy(format)
|
|
20
|
+
)
|
|
89
21
|
end
|
|
90
22
|
|
|
91
23
|
def report
|
|
92
24
|
super
|
|
93
|
-
@formatter.call(@calculators)
|
|
25
|
+
puts @formatter.call(@calculators)
|
|
94
26
|
end
|
|
95
27
|
end
|
|
96
28
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "attractor/formatters/formatter"
|
|
4
|
+
require "attractor/formatters/targets/diff"
|
|
5
|
+
require "attractor/formatters/formats/json"
|
|
6
|
+
require "attractor/formatters/formats/table"
|
|
7
|
+
require "attractor/formatters/formats/markdown"
|
|
8
|
+
require "attractor/formatters/format_strategy"
|
|
9
|
+
|
|
10
|
+
module Attractor
|
|
11
|
+
# Reporter for complexity deltas between two git refs
|
|
12
|
+
class DiffReporter
|
|
13
|
+
include Attractor::Formatters::FormatStrategy
|
|
14
|
+
|
|
15
|
+
def initialize(format:)
|
|
16
|
+
@formatter = Attractor::Formatters::Formatter.new(
|
|
17
|
+
target: Attractor::Formatters::Targets::Diff.new,
|
|
18
|
+
format: format_strategy(format)
|
|
19
|
+
)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def report(data)
|
|
23
|
+
puts @formatter.call(data)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/attractor/suggester.rb
CHANGED
|
@@ -10,11 +10,14 @@ module Attractor
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def suggest(threshold = 95)
|
|
13
|
-
|
|
13
|
+
scored_values = @values.reject { |value| value.score.nil? }
|
|
14
|
+
return [] if scored_values.empty?
|
|
15
|
+
|
|
16
|
+
products = scored_values.map(&:score)
|
|
14
17
|
products.extend(DescriptiveStatistics)
|
|
15
18
|
quantile = products.percentile(threshold.to_i)
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
scored_values.select { |val| val.score > quantile }
|
|
18
21
|
.sort_by { |val| val.score }.reverse
|
|
19
22
|
end
|
|
20
23
|
end
|
data/lib/attractor/value.rb
CHANGED
|
@@ -20,11 +20,14 @@ module Attractor
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def score
|
|
23
|
+
return nil if @complexity.nil?
|
|
24
|
+
|
|
23
25
|
@complexity * @churn
|
|
24
26
|
end
|
|
25
27
|
|
|
26
28
|
def to_s
|
|
27
|
-
format("
|
|
29
|
+
complexity_str = @complexity.nil? ? "n/a" : format("%8.1f", @complexity)
|
|
30
|
+
format("%-64s%8s%8i", @file_path, complexity_str, @churn)
|
|
28
31
|
end
|
|
29
32
|
|
|
30
33
|
def to_h
|
data/lib/attractor/version.rb
CHANGED
data/lib/attractor/watcher.rb
CHANGED
|
@@ -17,7 +17,7 @@ module Attractor
|
|
|
17
17
|
|
|
18
18
|
listener = Listen.to(File.absolute_path(@file_prefix), ignore: ignore) do |modified, _added, _removed|
|
|
19
19
|
if modified
|
|
20
|
-
puts "#{modified.
|
|
20
|
+
puts "#{modified.join(", ")} modified, recalculating..."
|
|
21
21
|
@callback.call
|
|
22
22
|
end
|
|
23
23
|
end
|
data/lib/attractor.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
require "attractor/version"
|
|
4
4
|
require "attractor/gem_names"
|
|
5
5
|
require "attractor/duration_parser"
|
|
6
|
+
require "attractor/config"
|
|
6
7
|
require "attractor/calculators/base_calculator"
|
|
7
8
|
require "attractor/detectors/base_detector"
|
|
8
9
|
require "attractor/reporters/base_reporter"
|
|
@@ -10,12 +11,6 @@ require "attractor/suggester"
|
|
|
10
11
|
require "attractor/watcher"
|
|
11
12
|
require "attractor/cache"
|
|
12
13
|
|
|
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
14
|
module Attractor
|
|
20
15
|
class Error < StandardError; end
|
|
21
16
|
|
|
@@ -35,11 +30,20 @@ module Attractor
|
|
|
35
30
|
end
|
|
36
31
|
|
|
37
32
|
def calculators_for_type(type, **options)
|
|
33
|
+
files = options.delete(:files)
|
|
38
34
|
registry_entry_for_type = @registry_entries[type]
|
|
39
35
|
|
|
40
|
-
|
|
36
|
+
if type
|
|
37
|
+
calculator = registry_entry_for_type.calculator_class.new(**options)
|
|
38
|
+
calculator.files = files if calculator.respond_to?(:files=)
|
|
39
|
+
return {type => calculator}
|
|
40
|
+
end
|
|
41
41
|
|
|
42
|
-
all_registered_calculators(**options)
|
|
42
|
+
all_registered_calculators(**options).tap do |calculators|
|
|
43
|
+
calculators.each_value do |calculator|
|
|
44
|
+
calculator.files = files if calculator.respond_to?(:files=)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
43
47
|
end
|
|
44
48
|
|
|
45
49
|
def all_registered_calculators(options = {})
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: attractor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.7.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Julian Rubisch
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: exe
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: churn
|
|
@@ -24,6 +23,20 @@ dependencies:
|
|
|
24
23
|
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
25
|
version: 1.0.4
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: csv
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0'
|
|
27
40
|
- !ruby/object:Gem::Dependency
|
|
28
41
|
name: descriptive_statistics
|
|
29
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -38,6 +51,20 @@ dependencies:
|
|
|
38
51
|
- - ">="
|
|
39
52
|
- !ruby/object:Gem::Version
|
|
40
53
|
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: logger
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
41
68
|
- !ruby/object:Gem::Dependency
|
|
42
69
|
name: flog
|
|
43
70
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -80,6 +107,20 @@ dependencies:
|
|
|
80
107
|
- - "~>"
|
|
81
108
|
- !ruby/object:Gem::Version
|
|
82
109
|
version: '3.0'
|
|
110
|
+
- !ruby/object:Gem::Dependency
|
|
111
|
+
name: ostruct
|
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0'
|
|
117
|
+
type: :runtime
|
|
118
|
+
prerelease: false
|
|
119
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
83
124
|
- !ruby/object:Gem::Dependency
|
|
84
125
|
name: rack-livereload
|
|
85
126
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -94,6 +135,20 @@ dependencies:
|
|
|
94
135
|
- - ">="
|
|
95
136
|
- !ruby/object:Gem::Version
|
|
96
137
|
version: '0'
|
|
138
|
+
- !ruby/object:Gem::Dependency
|
|
139
|
+
name: rugged
|
|
140
|
+
requirement: !ruby/object:Gem::Requirement
|
|
141
|
+
requirements:
|
|
142
|
+
- - "~>"
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: '1.0'
|
|
145
|
+
type: :runtime
|
|
146
|
+
prerelease: false
|
|
147
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
148
|
+
requirements:
|
|
149
|
+
- - "~>"
|
|
150
|
+
- !ruby/object:Gem::Version
|
|
151
|
+
version: '1.0'
|
|
97
152
|
- !ruby/object:Gem::Dependency
|
|
98
153
|
name: sinatra
|
|
99
154
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -170,14 +225,14 @@ dependencies:
|
|
|
170
225
|
requirements:
|
|
171
226
|
- - "~>"
|
|
172
227
|
- !ruby/object:Gem::Version
|
|
173
|
-
version: 0.
|
|
228
|
+
version: 0.4.0
|
|
174
229
|
type: :development
|
|
175
230
|
prerelease: false
|
|
176
231
|
version_requirements: !ruby/object:Gem::Requirement
|
|
177
232
|
requirements:
|
|
178
233
|
- - "~>"
|
|
179
234
|
- !ruby/object:Gem::Version
|
|
180
|
-
version: 0.
|
|
235
|
+
version: 0.4.0
|
|
181
236
|
- !ruby/object:Gem::Dependency
|
|
182
237
|
name: autoprefixer-rails
|
|
183
238
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -376,14 +431,27 @@ files:
|
|
|
376
431
|
- lib/attractor/calculators/base_calculator.rb~
|
|
377
432
|
- lib/attractor/cli.rb
|
|
378
433
|
- lib/attractor/cli.rb~
|
|
434
|
+
- lib/attractor/config.rb
|
|
379
435
|
- lib/attractor/detectors/base_detector.rb
|
|
436
|
+
- lib/attractor/diff_calculator.rb
|
|
380
437
|
- lib/attractor/duration_parser.rb
|
|
438
|
+
- lib/attractor/formatters/format_strategy.rb
|
|
439
|
+
- lib/attractor/formatters/formats/csv.rb
|
|
440
|
+
- lib/attractor/formatters/formats/json.rb
|
|
441
|
+
- lib/attractor/formatters/formats/markdown.rb
|
|
442
|
+
- lib/attractor/formatters/formats/table.rb
|
|
443
|
+
- lib/attractor/formatters/formatter.rb
|
|
444
|
+
- lib/attractor/formatters/report.rb
|
|
445
|
+
- lib/attractor/formatters/targets/console.rb
|
|
446
|
+
- lib/attractor/formatters/targets/diff.rb
|
|
381
447
|
- lib/attractor/gem_names.rb
|
|
448
|
+
- lib/attractor/git.rb
|
|
382
449
|
- lib/attractor/registry_entry.rb
|
|
383
450
|
- lib/attractor/reporters/base_reporter.rb
|
|
384
451
|
- lib/attractor/reporters/base_reporter.rb~
|
|
385
452
|
- lib/attractor/reporters/console_reporter.rb
|
|
386
453
|
- lib/attractor/reporters/console_reporter.rb~
|
|
454
|
+
- lib/attractor/reporters/diff_reporter.rb
|
|
387
455
|
- lib/attractor/reporters/html_reporter.rb
|
|
388
456
|
- lib/attractor/reporters/sinatra_reporter.rb
|
|
389
457
|
- lib/attractor/suggester.rb
|
|
@@ -400,7 +468,6 @@ metadata:
|
|
|
400
468
|
source_code_uri: https://github.com/julianrubisch/attractor
|
|
401
469
|
bug_tracker_uri: https://github.com/julianrubisch/attractor/issues
|
|
402
470
|
changelog_uri: https://github.com/julianrubisch/attractor/CHANGELOG.md
|
|
403
|
-
post_install_message:
|
|
404
471
|
rdoc_options: []
|
|
405
472
|
require_paths:
|
|
406
473
|
- lib
|
|
@@ -415,8 +482,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
415
482
|
- !ruby/object:Gem::Version
|
|
416
483
|
version: '0'
|
|
417
484
|
requirements: []
|
|
418
|
-
rubygems_version:
|
|
419
|
-
signing_key:
|
|
485
|
+
rubygems_version: 4.0.10
|
|
420
486
|
specification_version: 4
|
|
421
487
|
summary: Churn vs Complexity Chart Generator
|
|
422
488
|
test_files: []
|