factory_trace 0.2.2 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/factory_trace +4 -4
- data/lib/factory_trace/helpers/converter.rb +29 -0
- data/lib/factory_trace/preprocessors/extract_defined.rb +20 -0
- data/lib/factory_trace/preprocessors/extract_used.rb +20 -0
- data/lib/factory_trace/processors/find_unused.rb +118 -0
- data/lib/factory_trace/readers/trace_reader.rb +46 -39
- data/lib/factory_trace/structures/collection.rb +82 -0
- data/lib/factory_trace/structures/factory.rb +41 -0
- data/lib/factory_trace/structures/trait.rb +29 -0
- data/lib/factory_trace/tracker.rb +2 -4
- data/lib/factory_trace/version.rb +1 -1
- data/lib/factory_trace/writers/report_writer.rb +58 -32
- data/lib/factory_trace/writers/trace_writer.rb +6 -16
- data/lib/factory_trace/writers/writer.rb +8 -19
- data/lib/factory_trace.rb +20 -15
- metadata +9 -4
- data/lib/factory_trace/find_unused.rb +0 -36
- data/lib/factory_trace/storage_handler.rb +0 -61
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb1219bf45bfd040c463c2c49694f615bad866afe0042a1036feb02cd2a09d46
|
4
|
+
data.tar.gz: 326e1995408175cd60bbdf36a0e091b9111b3a3566034d920e42d04bf3eb5baf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18d6d00e731569b979c8158927a8ee42d1177c8ada0da28173d48253d4185fc00aa957f258d06ad6c2b3a55ec581527aeadc176ea2ded9e3f3a5449c88bbf710
|
7
|
+
data.tar.gz: 1996554340f1aec3c1c997706679dce4ca5d4a43d6bdc3c45e3001d52d5ee26894201960cb5d6b1ae4dc78f93106aff2b43da12aabe91b1195c2b73d09f081e3
|
data/exe/factory_trace
CHANGED
@@ -6,9 +6,9 @@ require 'factory_trace'
|
|
6
6
|
fail "You should pass at least one file with traced information.\nYou can generate it using only_trace mode." if ARGV.empty?
|
7
7
|
|
8
8
|
config = FactoryTrace.configuration
|
9
|
-
|
10
|
-
|
11
|
-
code =
|
9
|
+
hash = FactoryTrace::Readers::TraceReader.read_from_files(*ARGV)
|
10
|
+
reports = FactoryTrace::Processors::FindUnused.call(hash[:defined], hash[:used])
|
11
|
+
code = reports.any? { |report| report[:code] == :unused } ? 1 : 0
|
12
12
|
|
13
|
-
FactoryTrace::ReportWriter.new(config.out, config
|
13
|
+
FactoryTrace::Writers::ReportWriter.new(config.out, config).write(reports)
|
14
14
|
exit(code)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module FactoryTrace
|
2
|
+
module Helpers
|
3
|
+
module Converter
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# @param [FactoryBot::Trait] trait
|
7
|
+
# @param [FactoryBot::Factory] owner
|
8
|
+
#
|
9
|
+
# @return [FactoryTrace::Structures::Trait]
|
10
|
+
def trait(trait, owner = nil)
|
11
|
+
FactoryTrace::Structures::Trait.new(
|
12
|
+
trait.name.to_s,
|
13
|
+
owner && owner.name.to_s
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param [FactoryBot::Factory] factory
|
18
|
+
#
|
19
|
+
# @return [FactoryTrace::Structures::Factory]
|
20
|
+
def factory(factory)
|
21
|
+
FactoryTrace::Structures::Factory.new(
|
22
|
+
factory.name.to_s,
|
23
|
+
factory.send(:parent).respond_to?(:name) ? factory.send(:parent).name.to_s : nil,
|
24
|
+
factory.defined_traits.map(&:name).map(&:to_s)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module FactoryTrace
|
2
|
+
module Preprocessors
|
3
|
+
class ExtractDefined
|
4
|
+
# @return [FactoryTrace::Structures::Collection]
|
5
|
+
def self.call
|
6
|
+
collection = FactoryTrace::Structures::Collection.new
|
7
|
+
|
8
|
+
FactoryBot.traits.each do |trait|
|
9
|
+
collection.add(FactoryTrace::Helpers::Converter.trait(trait))
|
10
|
+
end
|
11
|
+
|
12
|
+
FactoryBot.factories.each do |factory|
|
13
|
+
collection.add(FactoryTrace::Helpers::Converter.factory(factory))
|
14
|
+
end
|
15
|
+
|
16
|
+
collection
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module FactoryTrace
|
2
|
+
module Preprocessors
|
3
|
+
class ExtractUsed
|
4
|
+
# Returns a collection with used factories and traits gathered from trace
|
5
|
+
#
|
6
|
+
# @param [Hash<String, Set<String>>]
|
7
|
+
#
|
8
|
+
# @return [FactoryTrace::Structures::Collection]
|
9
|
+
def self.call(trace)
|
10
|
+
collection = FactoryTrace::Structures::Collection.new
|
11
|
+
|
12
|
+
trace.each do |factory_name, trait_names|
|
13
|
+
collection.add(FactoryTrace::Structures::Factory.new(factory_name, nil, trait_names.to_a))
|
14
|
+
end
|
15
|
+
|
16
|
+
collection
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module FactoryTrace
|
2
|
+
module Processors
|
3
|
+
class FindUnused
|
4
|
+
# Finds unused factories and traits
|
5
|
+
#
|
6
|
+
# @param [FactoryTrace::Structures::Collection] defined
|
7
|
+
# @param [FactoryTrace::Structures::Collection] used
|
8
|
+
#
|
9
|
+
# @return [Array<Hash>]
|
10
|
+
def self.call(defined, used)
|
11
|
+
used_inherited_traits = used_inherited_traits(defined, used)
|
12
|
+
used_child_factories = used_child_factories(defined, used)
|
13
|
+
|
14
|
+
output = []
|
15
|
+
|
16
|
+
defined.factories.each_value do |factory|
|
17
|
+
unless used.factories[factory.name]
|
18
|
+
if used_child_factories[factory.name]
|
19
|
+
output << {code: :used_indirectly, factory_name: factory.name, child_factories_names: used_child_factories[factory.name]}
|
20
|
+
else
|
21
|
+
output << {code: :unused, factory_name: factory.name}
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
factory.trait_names.each do |trait_name|
|
26
|
+
unless trait_used?(used, factory.name, trait_name) || trait_used?(used_inherited_traits, factory.name, trait_name)
|
27
|
+
output << {code: :unused, factory_name: factory.name, trait_name: trait_name}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
defined.traits.each_value do |trait|
|
33
|
+
unless used_inherited_traits.traits[trait.name]
|
34
|
+
output << {code: :unused, trait_name: trait.name}
|
35
|
+
next
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
unused_count = output.count { |result| result[:code] == :unused }
|
40
|
+
used_indirectly_count = output.count { |result| result[:code] == :used_indirectly }
|
41
|
+
|
42
|
+
output.unshift(code: :unused, value: unused_count)
|
43
|
+
output.unshift(code: :used_indirectly, value: used_indirectly_count)
|
44
|
+
output.unshift(code: :used, value: defined.total - unused_count - used_indirectly_count)
|
45
|
+
|
46
|
+
output
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# Checks if factory of the collection contains a trait
|
52
|
+
#
|
53
|
+
# @param [FactoryTrace::Structures::Collection] collection
|
54
|
+
# @param [String] factory_name
|
55
|
+
# @param [String] trait_name
|
56
|
+
#
|
57
|
+
# @return [Boolean]
|
58
|
+
def self.trait_used?(collection, factory_name, trait_name)
|
59
|
+
collection.factories[factory_name] && collection.factories[factory_name].trait_names.include?(trait_name)
|
60
|
+
end
|
61
|
+
|
62
|
+
# Returns a new collection where traits which were used moved to their owner factory
|
63
|
+
#
|
64
|
+
# @param [FactoryTrace::Structures::Collection] defined
|
65
|
+
# @param [FactoryTrace::Structures::Collection] used
|
66
|
+
#
|
67
|
+
# @return [FactoryTrace::Structures::Collection]
|
68
|
+
def self.used_inherited_traits(defined, used)
|
69
|
+
collection = FactoryTrace::Structures::Collection.new
|
70
|
+
|
71
|
+
used.factories.each_value do |factory|
|
72
|
+
factory.trait_names.each do |trait_name|
|
73
|
+
possible_owner_name = factory.name
|
74
|
+
|
75
|
+
while possible_owner_name
|
76
|
+
break if defined.factories[possible_owner_name].trait_names.include?(trait_name)
|
77
|
+
possible_owner_name = defined.factories[possible_owner_name].parent_name
|
78
|
+
end
|
79
|
+
|
80
|
+
if possible_owner_name
|
81
|
+
factory = collection.factories[possible_owner_name]
|
82
|
+
factory ||= collection.add(FactoryTrace::Structures::Factory.new(possible_owner_name, nil, []))
|
83
|
+
|
84
|
+
factory.trait_names << trait_name unless factory.trait_names.include?(trait_name)
|
85
|
+
else
|
86
|
+
collection.add(FactoryTrace::Structures::Trait.new(trait_name, nil))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
collection
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns a hash:
|
95
|
+
# - key is factory name
|
96
|
+
# - value is factory names which where used and are children of the factory
|
97
|
+
#
|
98
|
+
# @param [FactoryTrace::Structures::Collection] defined
|
99
|
+
# @param [FactoryTrace::Structures::Collection] used
|
100
|
+
#
|
101
|
+
# @return [Hash<String, Array<String>]
|
102
|
+
def self.used_child_factories(defined, used)
|
103
|
+
hash = {}
|
104
|
+
|
105
|
+
used.factories.each_value do |factory|
|
106
|
+
parent_name = defined.factories[factory.name].parent_name
|
107
|
+
|
108
|
+
if parent_name
|
109
|
+
hash[parent_name] ||= []
|
110
|
+
hash[parent_name] << factory.name
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
hash
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -1,52 +1,59 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
1
|
module FactoryTrace
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
2
|
+
module Readers
|
3
|
+
class TraceReader
|
4
|
+
attr_reader :io, :configuration
|
5
|
+
|
6
|
+
# Read the data from files and merge it
|
7
|
+
#
|
8
|
+
# @return [Hash<Symbol, FactoryTrace::Structures::Collection>]
|
9
|
+
def self.read_from_files(*file_names, configuration: Configuration.new)
|
10
|
+
result = {defined: FactoryTrace::Structures::Collection.new, used: FactoryTrace::Structures::Collection.new}
|
11
|
+
|
12
|
+
file_names.each do |file_name|
|
13
|
+
File.open(file_name, 'r') do |file|
|
14
|
+
data = new(file, configuration: configuration).read
|
15
|
+
|
16
|
+
result.each do |key, collection|
|
17
|
+
collection.merge!(data[key])
|
18
|
+
end
|
19
|
+
end
|
16
20
|
end
|
21
|
+
|
22
|
+
result
|
17
23
|
end
|
18
|
-
end
|
19
24
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
25
|
+
def initialize(io, configuration: Configuration.new)
|
26
|
+
@io = io
|
27
|
+
@configuration = configuration
|
28
|
+
end
|
24
29
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
def read
|
31
|
-
data = [{}, {}]
|
32
|
-
point = -1
|
30
|
+
# Read the data from file
|
31
|
+
#
|
32
|
+
# @return [Hash<Symbol, FactoryTrace::Structures::Collection>]
|
33
|
+
def read
|
34
|
+
hash = JSON.parse(io.read)
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
+
{
|
37
|
+
defined: parse_collection(hash['defined']),
|
38
|
+
used: parse_collection(hash['used'])
|
39
|
+
}
|
40
|
+
end
|
36
41
|
|
37
|
-
|
42
|
+
private
|
38
43
|
|
39
|
-
|
40
|
-
|
41
|
-
data[point][factory] |= traits
|
42
|
-
end
|
43
|
-
end
|
44
|
+
def parse_collection(hash)
|
45
|
+
collection = FactoryTrace::Structures::Collection.new
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
+
hash['factories'].each do |h|
|
48
|
+
collection.add(FactoryTrace::Structures::Factory.new(h['name'], h['parent_name'], h['trait_names']))
|
49
|
+
end
|
47
50
|
|
48
|
-
|
51
|
+
hash['traits'].each do |h|
|
52
|
+
collection.add(FactoryTrace::Structures::Trait.new(h['name'], h['owner_name']))
|
53
|
+
end
|
49
54
|
|
50
|
-
|
55
|
+
collection
|
56
|
+
end
|
57
|
+
end
|
51
58
|
end
|
52
59
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module FactoryTrace
|
2
|
+
module Structures
|
3
|
+
class Collection
|
4
|
+
attr_reader :factories, :traits
|
5
|
+
|
6
|
+
# @param [Hash<String, FactoryTrace::Structures::Factory>]
|
7
|
+
# @param [Hash<String, FactoryTrace::Structures::Trait>]
|
8
|
+
def initialize(factories = {}, traits = {})
|
9
|
+
@factories = factories
|
10
|
+
@traits = traits
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param [FactoryTrace::Structures::Factory, FactoryTrace::Structures::Trait] element
|
14
|
+
#
|
15
|
+
# @return [FactoryTrace::Structures::Factory, FactoryTrace::Structures::Trait]
|
16
|
+
def add(element)
|
17
|
+
case element
|
18
|
+
when FactoryTrace::Structures::Factory then store(factories, element)
|
19
|
+
when FactoryTrace::Structures::Trait then store(traits, element)
|
20
|
+
else
|
21
|
+
fail "Unknown element: #{element.inspect}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Merge passed collection into self
|
26
|
+
#
|
27
|
+
# @param [FactoryTrace::Structures::Collection]
|
28
|
+
#
|
29
|
+
# @return [FactoryTrace::Structures::Collection]
|
30
|
+
def merge!(collection)
|
31
|
+
collection.factories.each_value do |factory|
|
32
|
+
if factories[factory.name]
|
33
|
+
factories[factory.name].merge!(factory)
|
34
|
+
else
|
35
|
+
add(FactoryTrace::Structures::Factory.new(factory.name, factory.parent_name, factory.trait_names))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
collection.traits.each_value do |trait|
|
40
|
+
add(FactoryTrace::Structures::Trait.new(trait.name, trait.owner_name)) unless traits[trait.name]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [Hash]
|
45
|
+
def to_h
|
46
|
+
{
|
47
|
+
factories: convert(factories),
|
48
|
+
traits: convert(traits)
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
# Total number of factories and traits
|
53
|
+
#
|
54
|
+
# @return [Integer]
|
55
|
+
def total
|
56
|
+
traits.size + factories.size + factories.values.sum { |factory| factory.trait_names.size }
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [Boolean]
|
60
|
+
def ==(collection)
|
61
|
+
return false unless collection.is_a?(FactoryTrace::Structures::Collection)
|
62
|
+
|
63
|
+
factories == collection.factories && traits == collection.traits
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# @param [Hash] hash
|
69
|
+
# @param [FactoryTrace::Structures::Factory, FactoryTrace::Structures::Trait] element
|
70
|
+
#
|
71
|
+
# @return [FactoryTrace::Structures::Factory, FactoryTrace::Structures::Trait] element
|
72
|
+
def store(hash, element)
|
73
|
+
hash[element.name] = element
|
74
|
+
end
|
75
|
+
|
76
|
+
# @return [Hash]
|
77
|
+
def convert(hash)
|
78
|
+
hash.each_value.map(&:to_h)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module FactoryTrace
|
2
|
+
module Structures
|
3
|
+
class Factory
|
4
|
+
attr_reader :name, :parent_name, :trait_names
|
5
|
+
|
6
|
+
# @param [String] name
|
7
|
+
# @param [String, nil] parent_name
|
8
|
+
# @param [Array<String>] trait_names
|
9
|
+
def initialize(name, parent_name, trait_names)
|
10
|
+
@name = name
|
11
|
+
@parent_name = parent_name
|
12
|
+
@trait_names = trait_names
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [Hash<Symbol, String>]
|
16
|
+
def to_h
|
17
|
+
{
|
18
|
+
name: name,
|
19
|
+
parent_name: parent_name,
|
20
|
+
trait_names: trait_names
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
# Merge passed factory into self
|
25
|
+
#
|
26
|
+
# @param [FactoryTrace::Structures::Factory]
|
27
|
+
#
|
28
|
+
# @return [FactoryTrace::Structures::Factory]
|
29
|
+
def merge!(factory)
|
30
|
+
@trait_names = (trait_names + factory.trait_names).uniq
|
31
|
+
end
|
32
|
+
|
33
|
+
# @return [Boolean]
|
34
|
+
def ==(factory)
|
35
|
+
return false unless factory.is_a?(FactoryTrace::Structures::Factory)
|
36
|
+
|
37
|
+
name == factory.name && parent_name == factory.parent_name && trait_names == factory.trait_names
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module FactoryTrace
|
2
|
+
module Structures
|
3
|
+
class Trait
|
4
|
+
attr_reader :name, :owner_name
|
5
|
+
|
6
|
+
# @param [String] name
|
7
|
+
# @param [String, nil] owner_name
|
8
|
+
def initialize(name, owner_name)
|
9
|
+
@name = name
|
10
|
+
@owner_name = owner_name
|
11
|
+
end
|
12
|
+
|
13
|
+
# @return [Hash<Symbol, String>]
|
14
|
+
def to_h
|
15
|
+
{
|
16
|
+
name: name,
|
17
|
+
owner_name: owner_name
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Boolean]
|
22
|
+
def ==(trait)
|
23
|
+
return false unless trait.is_a?(FactoryTrace::Structures::Trait)
|
24
|
+
|
25
|
+
name == trait.name && owner_name == trait.owner_name
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
1
|
module FactoryTrace
|
4
2
|
class Tracker
|
5
3
|
attr_reader :storage
|
@@ -10,8 +8,8 @@ module FactoryTrace
|
|
10
8
|
|
11
9
|
def track!
|
12
10
|
ActiveSupport::Notifications.subscribe('factory_bot.run_factory') do |_name, _start, _finish, _id, payload|
|
13
|
-
name = payload[:name]
|
14
|
-
traits = payload[:traits]
|
11
|
+
name = payload[:name].to_s
|
12
|
+
traits = payload[:traits].map(&:to_s)
|
15
13
|
|
16
14
|
storage[name] ||= Set.new
|
17
15
|
storage[name] |= traits
|
@@ -1,41 +1,67 @@
|
|
1
1
|
module FactoryTrace
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
2
|
+
module Writers
|
3
|
+
class ReportWriter < Writer
|
4
|
+
COLORS = {
|
5
|
+
blue: "\e[34m",
|
6
|
+
yellow: "\e[33m",
|
7
|
+
green: "\e[32m",
|
8
|
+
red: "\e[31m"
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
CODES = {
|
12
|
+
used: 'used',
|
13
|
+
unused: 'unused',
|
14
|
+
used_indirectly: 'used only indirectly'
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
# @param [Array<Hash>] results
|
18
|
+
def write(results)
|
19
|
+
total_color =
|
20
|
+
if results.any? { |result| result[:code] == :unused }
|
21
|
+
:red
|
22
|
+
elsif results.any? { |result| result[:code] == :used_indirectly }
|
23
|
+
:yellow
|
24
|
+
else
|
25
|
+
:green
|
26
|
+
end
|
27
|
+
|
28
|
+
results.each do |result|
|
29
|
+
io.puts(convert(result, total_color: total_color))
|
30
|
+
end
|
15
31
|
end
|
16
|
-
end
|
17
32
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
33
|
+
private
|
34
|
+
|
35
|
+
# @param [Hash<Symbol, Object>] result
|
36
|
+
# @param [Symbol] total_color
|
37
|
+
def convert(result, total_color:)
|
38
|
+
case
|
39
|
+
when result[:value]
|
40
|
+
colorize(total_color, "total number of unique #{humanize_code(result[:code])} factories & traits: #{result[:value]}")
|
41
|
+
when result[:factory_name] && result[:trait_name]
|
42
|
+
"#{humanize_code(result[:code])} trait #{colorize(:blue, result[:trait_name])} of factory #{colorize(:blue, result[:factory_name])}"
|
43
|
+
when result[:factory_name] && result[:child_factories_names]
|
44
|
+
"#{humanize_code(result[:code])} factory #{colorize(:blue, result[:factory_name])} as parent for #{list(result[:child_factories_names])}"
|
45
|
+
when result[:factory_name]
|
46
|
+
"#{humanize_code(result[:code])} factory #{colorize(:blue, result[:factory_name])}"
|
47
|
+
else
|
48
|
+
"#{humanize_code(result[:code])} global trait #{colorize(:blue, result[:trait_name])}"
|
49
|
+
end
|
32
50
|
end
|
33
|
-
end
|
34
51
|
|
35
|
-
|
36
|
-
|
52
|
+
def colorize(color, msg)
|
53
|
+
return msg unless configuration.color
|
37
54
|
|
38
|
-
|
55
|
+
"#{COLORS[color]}#{msg}\e[0m"
|
56
|
+
end
|
57
|
+
|
58
|
+
def humanize_code(code)
|
59
|
+
CODES[code]
|
60
|
+
end
|
61
|
+
|
62
|
+
def list(elements)
|
63
|
+
elements.map { |element| colorize(:blue, element) }.join(', ')
|
64
|
+
end
|
39
65
|
end
|
40
66
|
end
|
41
67
|
end
|
@@ -1,20 +1,10 @@
|
|
1
1
|
module FactoryTrace
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
output(results[1])
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
# @param [Hash<Symbol, Set<Hash>>] data
|
14
|
-
def output(data)
|
15
|
-
data.each do |key, set|
|
16
|
-
line = [key, set.to_a.join(',')].join(',')
|
17
|
-
io.puts(line)
|
2
|
+
module Writers
|
3
|
+
class TraceWriter < Writer
|
4
|
+
# @param [FactoryTrace::Structures::Collection] defined
|
5
|
+
# @param [FactoryTrace::Structures::Collection] used
|
6
|
+
def write(defined, used)
|
7
|
+
io.puts(JSON.pretty_generate(defined: defined.to_h, used: used.to_h))
|
18
8
|
end
|
19
9
|
end
|
20
10
|
end
|
@@ -1,23 +1,12 @@
|
|
1
1
|
module FactoryTrace
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
writer.new(io, config: config)
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(io, config: Configuration.new)
|
15
|
-
@io = io
|
16
|
-
@config = config
|
2
|
+
module Writers
|
3
|
+
class Writer
|
4
|
+
attr_reader :io, :configuration
|
5
|
+
|
6
|
+
def initialize(io, configuration = Configuration.new)
|
7
|
+
@io = io
|
8
|
+
@configuration = configuration
|
9
|
+
end
|
17
10
|
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
attr_reader :io, :config
|
22
11
|
end
|
23
12
|
end
|
data/lib/factory_trace.rb
CHANGED
@@ -1,12 +1,21 @@
|
|
1
1
|
# External dependencies
|
2
2
|
require 'factory_bot'
|
3
|
+
require 'json'
|
4
|
+
require 'set'
|
3
5
|
# Library
|
4
6
|
require 'factory_trace/configuration'
|
5
7
|
require 'factory_trace/version'
|
8
|
+
require 'factory_trace/helpers/converter'
|
6
9
|
require 'factory_trace/tracker'
|
7
10
|
|
8
|
-
require 'factory_trace/
|
9
|
-
require 'factory_trace/
|
11
|
+
require 'factory_trace/structures/factory'
|
12
|
+
require 'factory_trace/structures/trait'
|
13
|
+
require 'factory_trace/structures/collection'
|
14
|
+
|
15
|
+
require 'factory_trace/preprocessors/extract_defined'
|
16
|
+
require 'factory_trace/preprocessors/extract_used'
|
17
|
+
|
18
|
+
require 'factory_trace/processors/find_unused'
|
10
19
|
|
11
20
|
require 'factory_trace/readers/trace_reader'
|
12
21
|
require 'factory_trace/writers/writer'
|
@@ -29,7 +38,11 @@ module FactoryTrace
|
|
29
38
|
# This is required to exclude parent traits from +defined_traits+
|
30
39
|
FactoryBot.reload
|
31
40
|
|
32
|
-
|
41
|
+
if configuration.mode?(:full)
|
42
|
+
Writers::ReportWriter.new(configuration.out, configuration).write(Processors::FindUnused.call(defined, used))
|
43
|
+
elsif configuration.mode?(:trace_only)
|
44
|
+
Writers::TraceWriter.new(configuration.out, configuration).write(defined, used)
|
45
|
+
end
|
33
46
|
end
|
34
47
|
|
35
48
|
def configure
|
@@ -42,24 +55,16 @@ module FactoryTrace
|
|
42
55
|
|
43
56
|
private
|
44
57
|
|
45
|
-
def
|
46
|
-
|
47
|
-
FindUnused.call(preprocessed)
|
48
|
-
elsif configuration.mode?(:trace_only)
|
49
|
-
preprocessed
|
50
|
-
end
|
58
|
+
def used
|
59
|
+
@used ||= Preprocessors::ExtractUsed.call(tracker.storage)
|
51
60
|
end
|
52
61
|
|
53
|
-
def
|
54
|
-
@
|
62
|
+
def defined
|
63
|
+
@defined ||= Preprocessors::ExtractDefined.call
|
55
64
|
end
|
56
65
|
|
57
66
|
def tracker
|
58
67
|
@tracker ||= Tracker.new
|
59
68
|
end
|
60
|
-
|
61
|
-
def writer
|
62
|
-
@writer ||= Writer.factory(configuration.out, config: configuration)
|
63
|
-
end
|
64
69
|
end
|
65
70
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factory_trace
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- djezzzl
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-05-
|
11
|
+
date: 2019-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: factory_bot
|
@@ -77,9 +77,14 @@ files:
|
|
77
77
|
- exe/factory_trace
|
78
78
|
- lib/factory_trace.rb
|
79
79
|
- lib/factory_trace/configuration.rb
|
80
|
-
- lib/factory_trace/
|
80
|
+
- lib/factory_trace/helpers/converter.rb
|
81
|
+
- lib/factory_trace/preprocessors/extract_defined.rb
|
82
|
+
- lib/factory_trace/preprocessors/extract_used.rb
|
83
|
+
- lib/factory_trace/processors/find_unused.rb
|
81
84
|
- lib/factory_trace/readers/trace_reader.rb
|
82
|
-
- lib/factory_trace/
|
85
|
+
- lib/factory_trace/structures/collection.rb
|
86
|
+
- lib/factory_trace/structures/factory.rb
|
87
|
+
- lib/factory_trace/structures/trait.rb
|
83
88
|
- lib/factory_trace/tracker.rb
|
84
89
|
- lib/factory_trace/version.rb
|
85
90
|
- lib/factory_trace/writers/report_writer.rb
|
@@ -1,36 +0,0 @@
|
|
1
|
-
module FactoryTrace
|
2
|
-
class FindUnused
|
3
|
-
# @param [Array<Hash>] initial_data
|
4
|
-
# @return [Array<Hash>]
|
5
|
-
def self.call(initial_data)
|
6
|
-
all, used = initial_data
|
7
|
-
|
8
|
-
output = []
|
9
|
-
|
10
|
-
all.each do |factory_name, trait_names|
|
11
|
-
unless used.key?(factory_name)
|
12
|
-
output << {code: :unused, factory_name: factory_name}
|
13
|
-
next
|
14
|
-
end
|
15
|
-
|
16
|
-
trait_names.each do |trait_name|
|
17
|
-
unless used[factory_name].include?(trait_name)
|
18
|
-
output << {code: :unused, trait_name: trait_name}.tap { |h| h[:factory_name] = factory_name unless factory_name == '_traits' }
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
output.unshift(code: :unused, value: output.size)
|
24
|
-
output.unshift(code: :used, value: count_total(used))
|
25
|
-
|
26
|
-
output
|
27
|
-
end
|
28
|
-
|
29
|
-
private
|
30
|
-
|
31
|
-
# @param [Hash<Symbol, Set<Symbol>>]
|
32
|
-
def self.count_total(data)
|
33
|
-
data.reduce(0) { |result, (factory_name, trait_names)| result + (factory_name != '_traits' ? 1 : 0) + trait_names.size }
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,61 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
module FactoryTrace
|
4
|
-
class StorageHandler
|
5
|
-
# @param [Hash<Symbol, Set<Symbol>>] initial_data
|
6
|
-
#
|
7
|
-
# First hash - all factories
|
8
|
-
# Second hash - used factories
|
9
|
-
#
|
10
|
-
# @return [Array<Hash>]
|
11
|
-
def self.prepare(initial_data)
|
12
|
-
[collect_all, convert(initial_data)]
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def self.collect_all
|
18
|
-
FactoryBot.factories.reduce({'_traits' => Set.new(FactoryBot.traits.map(&:name).map(&:to_s))}) do |hash, factory|
|
19
|
-
hash[factory.name.to_s] = Set.new(factory.defined_traits.map(&:name).map(&:to_s))
|
20
|
-
hash
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
# Return new structure where each trait is moved to its own factory
|
25
|
-
#
|
26
|
-
# @param [Hash<Symbol, Set<Symbol>>]
|
27
|
-
# @return [Hash<String, Set<String>>]
|
28
|
-
def self.convert(data)
|
29
|
-
# +_traits+ is for global traits
|
30
|
-
output = {'_traits' => Set.new}
|
31
|
-
|
32
|
-
data.each do |factory_name, trait_names|
|
33
|
-
factory_name = factory_name.to_s
|
34
|
-
|
35
|
-
output[factory_name] ||= Set.new
|
36
|
-
|
37
|
-
trait_names.each do |trait_name|
|
38
|
-
trait_name = trait_name.to_s
|
39
|
-
|
40
|
-
factory = FactoryBot.factories[factory_name]
|
41
|
-
trait_found = false
|
42
|
-
|
43
|
-
until factory.is_a?(FactoryBot::NullFactory)
|
44
|
-
if factory.defined_traits.any? { |trait| trait.name.to_s == trait_name }
|
45
|
-
trait_found = true
|
46
|
-
output[factory.name.to_s] ||= Set.new
|
47
|
-
output[factory.name.to_s] << trait_name
|
48
|
-
break
|
49
|
-
end
|
50
|
-
factory = factory.send(:parent)
|
51
|
-
end
|
52
|
-
|
53
|
-
# Belongs to global traits
|
54
|
-
output['_traits'] << trait_name unless trait_found
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
output
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|