factory_sloth 1.2.2 β 1.3.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/CHANGELOG.md +7 -0
- data/README.md +17 -11
- data/lib/factory_sloth/cli.rb +12 -8
- data/lib/factory_sloth/code_mod.rb +100 -99
- data/lib/factory_sloth/color.rb +21 -0
- data/lib/factory_sloth/create_call.rb +1 -1
- data/lib/factory_sloth/execution_check.rb +39 -0
- data/lib/factory_sloth/file_processor.rb +9 -25
- data/lib/factory_sloth/spec_runner.rb +8 -2
- data/lib/factory_sloth/version.rb +1 -1
- data/lib/factory_sloth.rb +5 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9032b54abec61f25adcfd938a503f312017667f64b4aa1f303ede50a346a62be
|
4
|
+
data.tar.gz: 901d358d3572a708ec8190c2d2e59dbdab3bce42f894301284dc285895d48f19
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b1aa29c8c7dd007c5e82ee4cfbc164df1550ace4c2d7880e0471b4a892a2dad33a8e03469c56ec5620f99e7c2dc8c6c47f0d7256102910385acea9a3f97f4b74
|
7
|
+
data.tar.gz: bace623884d7e447200af29fb216f8814f86a7bae4deda093105bb9df716c8151332136a473c31cd6c9e51bc07ded9f2306e9eda29b536b7b4aa130384f0059a
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -27,6 +27,7 @@ Examples:
|
|
27
27
|
Options:
|
28
28
|
-f, --force Ignore ./.factory_sloth_done
|
29
29
|
-l, --lint Dont fix, just list bad create calls
|
30
|
+
-V, --verbose Verbose output, useful for debugging
|
30
31
|
-v, --version Show gem version
|
31
32
|
-h, --help Show this help
|
32
33
|
```
|
@@ -36,20 +37,25 @@ Options:
|
|
36
37
|
While running, `factory_sloth` produces output like this:
|
37
38
|
|
38
39
|
```
|
39
|
-
|
40
|
-
π‘ 2 create calls found, 0 replaced
|
40
|
+
π‘ spec/features/sign_up_spec.rb: 2 create calls found, 0 replaced
|
41
41
|
|
42
|
-
|
43
|
-
βͺοΈ 0 create calls found, 0 replaced
|
42
|
+
βͺοΈ spec/lib/string_ext_spec.rb: 0 create calls found, 0 replaced
|
44
43
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
π’ 3 create calls found, 2 replaced
|
44
|
+
spec/models/user_spec.rb:3:2: create replaced with build
|
45
|
+
expect(create(:user)).not_to be_nil
|
46
|
+
^^^^^^
|
49
47
|
|
50
|
-
|
51
|
-
|
52
|
-
|
48
|
+
spec/models/user_spec.rb:4:2: create_list replaced with build_list
|
49
|
+
expect(create_list(:user, 2).count).to eq 2
|
50
|
+
^^^^^^^^^^^
|
51
|
+
|
52
|
+
π’ spec/models/user_spec.rb: 3 create calls found, 2 replaced
|
53
|
+
|
54
|
+
spec/weird_dir/crazy_spec.rb:8:4: create replaced with build_stubbed
|
55
|
+
expect(create(:user)).not_to be_nil
|
56
|
+
^^^^^^
|
57
|
+
|
58
|
+
π΄ spec/weird_dir/crazy_spec.rb: 33 create calls found, 0 replaced (conflict)
|
53
59
|
|
54
60
|
Scanned 4 files, found 2 unnecessary create calls across 1 files and 1 broken specs
|
55
61
|
```
|
data/lib/factory_sloth/cli.rb
CHANGED
@@ -7,8 +7,7 @@ module FactorySloth
|
|
7
7
|
def call(argv = ARGV)
|
8
8
|
args = option_parser.parse!(argv)
|
9
9
|
specs = SpecPicker.call(paths: args)
|
10
|
-
|
11
|
-
results = FileProcessor.call(files: specs, forced_files: forced_files, dry_run: @lint)
|
10
|
+
results = FileProcessor.call(files: specs, forced_files: args)
|
12
11
|
print_summary(results)
|
13
12
|
end
|
14
13
|
|
@@ -29,11 +28,16 @@ module FactorySloth
|
|
29
28
|
opts.separator 'Options:'
|
30
29
|
|
31
30
|
opts.on('-f', '--force', "Ignore #{DoneTracker.file}") do
|
32
|
-
|
31
|
+
FactorySloth.force = true
|
33
32
|
end
|
34
33
|
|
35
34
|
opts.on('-l', '--lint', 'Dont fix, just list bad create calls') do
|
36
|
-
|
35
|
+
FactorySloth.dry_run = true
|
36
|
+
FactorySloth.lint = true
|
37
|
+
end
|
38
|
+
|
39
|
+
opts.on('-V', '--verbose', 'Verbose output, useful for debugging') do
|
40
|
+
FactorySloth.verbose = true
|
37
41
|
end
|
38
42
|
|
39
43
|
opts.on('-v', '--version', 'Show gem version') do
|
@@ -49,14 +53,14 @@ module FactorySloth
|
|
49
53
|
end
|
50
54
|
|
51
55
|
def print_summary(results)
|
52
|
-
|
53
|
-
changed_specs = results.keys.select { |path| results[path][:
|
56
|
+
change_sum = results.values.sum { |v| v[:change_count] }
|
57
|
+
changed_specs = results.keys.select { |path| results[path][:change_count] > 0 }
|
54
58
|
broken_specs = results.keys.select { |path| !results[path][:ok] }
|
55
|
-
stats = "Scanned #{results.count} files, found #{
|
59
|
+
stats = "Scanned #{results.count} files, found #{change_sum}"\
|
56
60
|
" unnecessary create calls across #{changed_specs.count} files"\
|
57
61
|
"#{" and #{broken_specs.count} broken specs" if broken_specs.any?}"
|
58
62
|
|
59
|
-
if
|
63
|
+
if FactorySloth.lint && change_sum > 0
|
60
64
|
warn "#{stats}:\n#{(changed_specs + broken_specs).join("\n")}"
|
61
65
|
exit 1
|
62
66
|
else
|
@@ -1,116 +1,117 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
module FactorySloth
|
2
|
+
class CodeMod
|
3
|
+
attr_reader :create_calls, :changed_create_calls, :path, :original_code, :patched_code
|
3
4
|
|
4
|
-
|
5
|
-
|
6
|
-
end
|
5
|
+
require 'forwardable'
|
6
|
+
extend Forwardable
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
def_delegator :changed_create_calls, :any?, :changed?
|
9
|
+
def_delegator :changed_create_calls, :count, :change_count
|
10
|
+
def_delegator :create_calls, :count, :create_count
|
11
|
+
|
12
|
+
def self.call(path, code)
|
13
|
+
new(path, code).tap(&:call)
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(path, code)
|
17
|
+
self.path = path
|
18
|
+
self.original_code = code
|
19
|
+
self.patched_code = code
|
20
|
+
end
|
21
|
+
|
22
|
+
def call
|
23
|
+
self.create_calls = CreateCallFinder.call(code: original_code)
|
13
24
|
|
14
|
-
|
15
|
-
|
25
|
+
# Performance note: it might be faster to write ALL possible patches for a
|
26
|
+
# given spec file to tempfiles first, and then run them all in a single
|
27
|
+
# rspec call. However, this would make it impossible to use `--fail-fast`,
|
28
|
+
# and might make examples fail that are not as idempotent as they should be.
|
29
|
+
self.changed_create_calls =
|
30
|
+
create_calls.sort_by { |call| [-call.line, -call.column] }.select do |call|
|
31
|
+
build_result = try_patch(call, 'build')
|
32
|
+
next if build_result == ABORT
|
16
33
|
|
17
|
-
|
18
|
-
|
19
|
-
# rspec call. However, this would make it impossible to use `--fail-fast`,
|
20
|
-
# and might make examples fail that are not as idempotent as they should be.
|
21
|
-
self.changed_create_calls =
|
22
|
-
create_calls.sort_by { |call| [-call.line, -call.column] }.select do |call|
|
23
|
-
build_result = try_patch(call, 'build')
|
24
|
-
next if build_result == ABORT
|
34
|
+
build_result == SUCCESS || try_patch(call, 'build_stubbed') == SUCCESS
|
35
|
+
end
|
25
36
|
|
26
|
-
|
37
|
+
# validate whole spec after changes, e.g. to detect side-effects
|
38
|
+
self.ok = changed_create_calls.none? || begin
|
39
|
+
FactorySloth.verbose && puts("Checking whole file after changes")
|
40
|
+
run(patched_code).success?
|
27
41
|
end
|
42
|
+
ok? || changed_create_calls.clear && patched_code.replace(original_code)
|
43
|
+
end
|
28
44
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
changed_create_calls.clear unless ok?
|
33
|
-
patched_code.replace(original_code) unless ok?
|
34
|
-
end
|
45
|
+
def ok?
|
46
|
+
@ok
|
47
|
+
end
|
35
48
|
|
36
|
-
|
37
|
-
|
38
|
-
|
49
|
+
def message
|
50
|
+
stats = "#{path}: #{create_count} create calls found, #{change_count} "\
|
51
|
+
"#{FactorySloth.dry_run ? 'replaceable' : 'replaced'}"
|
39
52
|
|
40
|
-
|
41
|
-
change_count > 0
|
42
|
-
end
|
53
|
+
return "π΄ #{stats} (conflict)" unless ok?
|
43
54
|
|
44
|
-
|
45
|
-
|
46
|
-
|
55
|
+
if create_count == 0
|
56
|
+
"βͺοΈ #{stats}"
|
57
|
+
elsif change_count == 0
|
58
|
+
"π‘ #{stats}"
|
59
|
+
else
|
60
|
+
"π’ #{stats}"
|
61
|
+
end
|
62
|
+
end
|
47
63
|
|
48
|
-
|
49
|
-
|
50
|
-
|
64
|
+
private
|
65
|
+
|
66
|
+
attr_writer :create_calls, :changed_create_calls, :ok, :path, :original_code, :patched_code
|
67
|
+
|
68
|
+
def try_patch(call, base_variant)
|
69
|
+
variant = call.name.sub('create', base_variant)
|
70
|
+
FactorySloth.verbose && puts("#{link_to_call(call)}: trying #{variant} ...")
|
71
|
+
|
72
|
+
new_patched_code = patched_code.sub(
|
73
|
+
/\A(?:.*\R){#{call.line - 1}}.{#{call.column}}\K#{call.name}/,
|
74
|
+
variant
|
75
|
+
)
|
76
|
+
checked_patched_code = new_patched_code + ExecutionCheck.for(call.line, variant)
|
77
|
+
|
78
|
+
result = run(checked_patched_code, line: call.line)
|
79
|
+
|
80
|
+
if result.success?
|
81
|
+
info = FactorySloth.dry_run ? 'can be replaced' : 'replaced'
|
82
|
+
puts call_message(call, "#{info} with #{variant}"), ''
|
83
|
+
self.patched_code = new_patched_code
|
84
|
+
SUCCESS
|
85
|
+
elsif result.exitstatus == ExecutionCheck::FACTORY_UNUSED_CODE
|
86
|
+
puts call_message(call, "is never executed, skipping"), ''
|
87
|
+
ABORT
|
88
|
+
elsif result.exitstatus == ExecutionCheck::FACTORY_PERSISTED_LATER_CODE
|
89
|
+
FactorySloth.verbose && puts("Record is persisted later, skipping")
|
90
|
+
ABORT
|
91
|
+
end
|
92
|
+
end
|
51
93
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
def try_patch(call, base_variant)
|
57
|
-
variant = call.name.sub('create', base_variant)
|
58
|
-
new_patched_code = patched_code.sub(
|
59
|
-
/\A(?:.*\n){#{call.line - 1}}.{#{call.column}}\K#{call.name}/,
|
60
|
-
variant
|
61
|
-
)
|
62
|
-
checked_patched_code = new_patched_code + checks(call.line, variant)
|
63
|
-
|
64
|
-
result = FactorySloth::SpecRunner.call(path, checked_patched_code, line: call.line)
|
65
|
-
if result.success?
|
66
|
-
puts "- #{call.name} in line #{call.line} can be replaced with #{variant}"
|
67
|
-
self.patched_code = new_patched_code
|
68
|
-
SUCCESS
|
69
|
-
elsif result.exitstatus == FACTORY_UNUSED_CODE
|
70
|
-
puts "- #{call.name} in line #{call.line} is never executed, skipping"
|
71
|
-
ABORT
|
72
|
-
elsif result.exitstatus == FACTORY_PERSISTED_LATER_CODE
|
73
|
-
ABORT
|
94
|
+
def run(code, line: nil)
|
95
|
+
result = SpecRunner.call(path, code, line: line)
|
96
|
+
FactorySloth.verbose && puts(' RSpec output:', result.output.gsub(/^/, ' '))
|
97
|
+
result
|
74
98
|
end
|
75
|
-
end
|
76
99
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
FACTORY_UNUSED_CODE = 77
|
81
|
-
FACTORY_PERSISTED_LATER_CODE = 78
|
82
|
-
|
83
|
-
# This adds code that makes a spec run fail and thus prevents changes if:
|
84
|
-
# a) the patched factory in the given line is never called
|
85
|
-
# b) the built record was persisted later anyway
|
86
|
-
# The rationale behind a) is that things like skipped examples should not
|
87
|
-
# be broken. The rationale behind b) is that not much DB work would be saved,
|
88
|
-
# but diff noise would be increased and ease of editing the example reduced.
|
89
|
-
def checks(line, variant)
|
90
|
-
<<~RUBY
|
91
|
-
; defined?(FactoryBot) && defined?(RSpec) && RSpec.configure do |config|
|
92
|
-
records_by_line = {} # track records initialized through factories per line
|
93
|
-
|
94
|
-
FactoryBot::Syntax::Methods.class_eval do
|
95
|
-
alias ___original_#{variant} #{variant} # e.g. ___original_build build
|
96
|
-
|
97
|
-
define_method("#{variant}") do |*args, **kwargs, &blk| # e.g. build
|
98
|
-
result = ___original_#{variant}(*args, **kwargs, &blk)
|
99
|
-
list = records_by_line[caller_locations(1, 1)&.first&.lineno] ||= []
|
100
|
-
list.concat([result].flatten) # to work with single, list, and pair
|
101
|
-
result
|
102
|
-
end
|
103
|
-
end
|
100
|
+
ABORT = :ABORT # returned if there is no need to try other variants
|
101
|
+
SUCCESS = :SUCCESS
|
104
102
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
103
|
+
def call_message(call, message)
|
104
|
+
line_content = original_code[/\A(?:.*\R){#{call.line - 1}}\K.*/]
|
105
|
+
indent = line_content[/^\s*/]
|
106
|
+
|
107
|
+
"#{link_to_call(call)}: #{call.name} #{message}\n"\
|
108
|
+
" #{line_content.delete_prefix(indent)}\n"\
|
109
|
+
" #{' ' * (call.column - indent.size)}#{Color.yellow('^' * call.name.size)}"
|
110
|
+
end
|
111
|
+
|
112
|
+
def link_to_call(call)
|
113
|
+
# note: column from Ripper is 0-indexed, editors expect 1-indexed columns
|
114
|
+
Color.light_blue("#{path}:#{call.line}:#{call.column + 1}")
|
115
|
+
end
|
115
116
|
end
|
116
117
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FactorySloth::Color
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def yellow(str)
|
7
|
+
colorize(str, 33)
|
8
|
+
end
|
9
|
+
|
10
|
+
def light_blue(str)
|
11
|
+
colorize(str, 36)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def colorize(str, color_code)
|
17
|
+
return str unless $stdout.is_a?(IO) && $stdout.tty?
|
18
|
+
|
19
|
+
"\e[#{color_code}m#{str}\e[0m"
|
20
|
+
end
|
21
|
+
end
|
@@ -1 +1 @@
|
|
1
|
-
FactorySloth::CreateCall = Struct.new(:
|
1
|
+
FactorySloth::CreateCall = Struct.new(:column, :line, :name, keyword_init: true)
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# This adds code that makes a spec run fail and thus prevents changes if:
|
2
|
+
# a) the patched factory in the given line is never called
|
3
|
+
# b) the built record was persisted later anyway
|
4
|
+
# The rationale behind a) is that things like skipped examples should not
|
5
|
+
# be broken. The rationale behind b) is that not much DB work would be saved,
|
6
|
+
# but diff noise would be increased and ease of editing the example reduced.
|
7
|
+
|
8
|
+
module FactorySloth::ExecutionCheck
|
9
|
+
FACTORY_UNUSED_CODE = 77
|
10
|
+
FACTORY_PERSISTED_LATER_CODE = 78
|
11
|
+
|
12
|
+
def self.for(line, variant)
|
13
|
+
<<~RUBY
|
14
|
+
; defined?(FactoryBot) && defined?(RSpec) && RSpec.configure do |config|
|
15
|
+
records_by_line = {} # track records initialized through factories per line
|
16
|
+
|
17
|
+
FactoryBot::Syntax::Methods.class_eval do
|
18
|
+
alias ___original_#{variant} #{variant} # e.g. ___original_build build
|
19
|
+
|
20
|
+
define_method("#{variant}") do |*args, **kwargs, &blk| # e.g. build
|
21
|
+
result = ___original_#{variant}(*args, **kwargs, &blk)
|
22
|
+
list = records_by_line[caller_locations(1, 1)&.first&.lineno] ||= []
|
23
|
+
list.concat([result].flatten) # to work with single, list, and pair
|
24
|
+
result
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
config.after(:suite) do
|
29
|
+
records = records_by_line[#{line}]
|
30
|
+
records&.any? || exit!(#{FACTORY_UNUSED_CODE})
|
31
|
+
unless "#{variant}".include?('stub') # factory_bot stub stubs persisted? as true
|
32
|
+
records.any? { |r| r.respond_to?(:persisted?) && r.persisted? } &&
|
33
|
+
exit!(#{FACTORY_PERSISTED_LATER_CODE})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
RUBY
|
38
|
+
end
|
39
|
+
end
|
@@ -2,46 +2,30 @@ module FactorySloth
|
|
2
2
|
module FileProcessor
|
3
3
|
extend self
|
4
4
|
|
5
|
-
def call(files:, forced_files: []
|
5
|
+
def call(files:, forced_files: [])
|
6
6
|
files.each_with_object({}) do |path, acc|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
puts "π΅ Skipped (marked as done in #{DoneTracker.file})", ''
|
7
|
+
if DoneTracker.done?(path) &&
|
8
|
+
!(FactorySloth.force || forced_files.include?(path))
|
9
|
+
puts "π΅ #{path}: skipped (marked as done in #{DoneTracker.file})", ''
|
11
10
|
next
|
12
11
|
end
|
13
12
|
|
14
|
-
result = process(path
|
15
|
-
acc[path] = { ok: result.ok?,
|
13
|
+
result = process(path)
|
14
|
+
acc[path] = { ok: result.ok?, change_count: result.change_count }
|
16
15
|
DoneTracker.mark_as_done(path)
|
17
16
|
end
|
18
17
|
end
|
19
18
|
|
20
19
|
private
|
21
20
|
|
22
|
-
def process(path
|
21
|
+
def process(path)
|
23
22
|
code = File.read(path)
|
24
23
|
result = CodeMod.call(path, code)
|
25
|
-
unless dry_run
|
24
|
+
unless FactorySloth.dry_run
|
26
25
|
File.write(path, result.patched_code) if result.changed?
|
27
26
|
end
|
28
|
-
puts
|
27
|
+
puts result.message, ''
|
29
28
|
result
|
30
29
|
end
|
31
|
-
|
32
|
-
def result_message(result, dry_run)
|
33
|
-
stats = "#{result.create_count} create calls found, "\
|
34
|
-
"#{result.change_count} #{dry_run ? 'replaceable' : 'replaced'}"
|
35
|
-
|
36
|
-
return "π΄ #{stats} (conflict)" unless result.ok?
|
37
|
-
|
38
|
-
if result.create_count == 0
|
39
|
-
"βͺοΈ #{stats}"
|
40
|
-
elsif result.change_count == 0
|
41
|
-
"π‘ #{stats}"
|
42
|
-
else
|
43
|
-
"π’ #{stats}"
|
44
|
-
end
|
45
|
-
end
|
46
30
|
end
|
47
31
|
end
|
@@ -8,8 +8,14 @@ module FactorySloth::SpecRunner
|
|
8
8
|
File.write(path, spec_code)
|
9
9
|
path_arg = [path, line].compact.map(&:to_s).join(':')
|
10
10
|
command = "bundle exec rspec #{path_arg} --fail-fast --order defined 2>&1"
|
11
|
-
|
12
|
-
|
11
|
+
output, process_status = Open3.capture2(command)
|
12
|
+
Result.new(output: output, process_status: process_status)
|
13
|
+
end
|
14
|
+
|
15
|
+
Result = Struct.new(:output, :process_status, keyword_init: true) do
|
16
|
+
require 'forwardable'
|
17
|
+
extend Forwardable
|
18
|
+
def_delegators :process_status, :exitstatus, :success?
|
13
19
|
end
|
14
20
|
|
15
21
|
def self.tmpdir
|
data/lib/factory_sloth.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
-
module FactorySloth
|
1
|
+
module FactorySloth
|
2
|
+
singleton_class.attr_accessor :dry_run, :force, :lint, :verbose
|
3
|
+
end
|
2
4
|
|
3
5
|
require_relative 'factory_sloth/cli'
|
4
6
|
require_relative 'factory_sloth/code_mod'
|
7
|
+
require_relative 'factory_sloth/color'
|
5
8
|
require_relative 'factory_sloth/create_call'
|
6
9
|
require_relative 'factory_sloth/create_call_finder'
|
7
10
|
require_relative 'factory_sloth/done_tracker'
|
11
|
+
require_relative 'factory_sloth/execution_check'
|
8
12
|
require_relative 'factory_sloth/file_processor'
|
9
13
|
require_relative 'factory_sloth/spec_picker'
|
10
14
|
require_relative 'factory_sloth/spec_runner'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factory_sloth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Janosch MuΜller
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-05-
|
11
|
+
date: 2023-05-22 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -28,9 +28,11 @@ files:
|
|
28
28
|
- lib/factory_sloth.rb
|
29
29
|
- lib/factory_sloth/cli.rb
|
30
30
|
- lib/factory_sloth/code_mod.rb
|
31
|
+
- lib/factory_sloth/color.rb
|
31
32
|
- lib/factory_sloth/create_call.rb
|
32
33
|
- lib/factory_sloth/create_call_finder.rb
|
33
34
|
- lib/factory_sloth/done_tracker.rb
|
35
|
+
- lib/factory_sloth/execution_check.rb
|
34
36
|
- lib/factory_sloth/file_processor.rb
|
35
37
|
- lib/factory_sloth/spec_picker.rb
|
36
38
|
- lib/factory_sloth/spec_runner.rb
|