factory_trace 0.2.2 → 0.2.3
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/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
|