leftovers 0.4.2 → 0.4.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/CHANGELOG.md +4 -0
- data/README.md +30 -0
- data/leftovers.gemspec +1 -0
- data/lib/leftovers.rb +9 -15
- data/lib/leftovers/cli.rb +13 -4
- data/lib/leftovers/collector.rb +1 -0
- data/lib/leftovers/definition.rb +4 -4
- data/lib/leftovers/merged_config.rb +5 -0
- data/lib/leftovers/reporter.rb +56 -4
- data/lib/leftovers/todo_reporter.rb +124 -0
- data/lib/leftovers/version.rb +1 -1
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa735d4aa3320b0225d0d256c296b5b3b284593f285d1257a4b8e6bd74a0dd74
|
4
|
+
data.tar.gz: ebaaa2f4c2e93780788e36d961a623a015b1f8d11c0a9799882e5a21a45552f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88cf80851cdb71a94a3d5497fa80ab4b020447e6aa23b1a9074ef19789bcdc77b576275aad066ac23170b1d2d18687f0b07322b24792cd31a163f2e70f3d637e
|
7
|
+
data.tar.gz: '0167915df5ad01dcf2368e72a98171cad57b22e4df7d6c8e5bc29b1e8e053b8a9e522746836102d769ca80745105021bbeb297d038ab8cd58410a2d797c34d04'
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -56,8 +56,38 @@ lib/hello_world.rb:18:6 another_tested_unused_method def another_tested_unused_m
|
|
56
56
|
Not directly called at all:
|
57
57
|
lib/hello_world.rb:6:6 generated_method= attr_accessor :generated_method
|
58
58
|
lib/hello_world.rb:6:6 generated_method attr_accessor :generated_method
|
59
|
+
|
60
|
+
how to resolve: https://github.com/robotdana/leftovers/tree/main/Readme.md#how_to_resolve
|
59
61
|
```
|
60
62
|
|
63
|
+
if there is an overwhelming number of results, try using [`--write-todo`](#write-todo)
|
64
|
+
|
65
|
+
## How to resolve
|
66
|
+
|
67
|
+
When running `leftovers` you'll be given a list of method, constant, and variable definitions it thinks are unused. Now what?
|
68
|
+
|
69
|
+
they were unintentionally left when removing their calls:
|
70
|
+
- remove their definitions. (they're still there in your git etc history if you want them back)
|
71
|
+
|
72
|
+
they are called dynamically:
|
73
|
+
- define how they're called dynamically in the [.leftovers.yml](#configuration-file); or
|
74
|
+
- mark the calls with [`# leftovers:call my_unused_method`](#leftovers-call); or
|
75
|
+
- mark the definition with [`# leftovers:keep`](#leftovers-keep)
|
76
|
+
|
77
|
+
they're defined intentionally to only be used by tests:
|
78
|
+
- add [`# leftovers:test_only`](#leftovers-test-only)
|
79
|
+
|
80
|
+
they're from a file that shouldn't be checked by leftovers:
|
81
|
+
- add the paths to the [`exclude_paths:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#exclude_paths) list in the [.leftovers.yml](#configuration-file) file
|
82
|
+
|
83
|
+
if there are too many to address when first adding leftovers to your project, try running [`leftovers --write-todo`](#write-todo),
|
84
|
+
|
85
|
+
### --write-todo
|
86
|
+
|
87
|
+
running `leftovers --write-todo` will generate a supplemental configuration file allowing all the currently detected uncalled definitions, which will be read on subsequent runs of `leftovers` without alerting any of the items mentioned in it.
|
88
|
+
|
89
|
+
commit this file so you/your team can gradually address these items while still having leftovers alert you to any newly unused items.
|
90
|
+
|
61
91
|
## Magic comments
|
62
92
|
|
63
93
|
### `# leftovers:keep`
|
data/leftovers.gemspec
CHANGED
@@ -42,6 +42,7 @@ Gem::Specification.new do |spec|
|
|
42
42
|
spec.add_development_dependency 'rubocop-rspec', '~> 1.44.1'
|
43
43
|
spec.add_development_dependency 'simplecov', '>= 0.18.5'
|
44
44
|
spec.add_development_dependency 'simplecov-console'
|
45
|
+
spec.add_development_dependency 'timecop'
|
45
46
|
spec.add_development_dependency 'tty_string', '>= 0.2.1'
|
46
47
|
|
47
48
|
spec.add_development_dependency 'spellr', '>= 0.8.1'
|
data/lib/leftovers.rb
CHANGED
@@ -26,14 +26,14 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
|
|
26
26
|
autoload(:ProcessorBuilders, "#{__dir__}/leftovers/processor_builders")
|
27
27
|
autoload(:RakeTask, "#{__dir__}/leftovers/rake_task")
|
28
28
|
autoload(:Reporter, "#{__dir__}/leftovers/reporter")
|
29
|
+
autoload(:TodoReporter, "#{__dir__}/leftovers/todo_reporter")
|
29
30
|
autoload(:DynamicProcessors, "#{__dir__}/leftovers/dynamic_processors")
|
30
31
|
autoload(:ValueProcessors, "#{__dir__}/leftovers/value_processors")
|
31
32
|
autoload(:VERSION, "#{__dir__}/leftovers/version")
|
32
33
|
|
33
34
|
class << self
|
34
|
-
attr_accessor :parallel, :progress
|
35
|
+
attr_accessor :parallel, :progress, :reporter
|
35
36
|
alias_method :parallel?, :parallel
|
36
|
-
|
37
37
|
alias_method :progress?, :progress
|
38
38
|
end
|
39
39
|
|
@@ -64,10 +64,10 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
-
def run(stdout: StringIO.new, stderr: StringIO.new) # rubocop:disable Metrics/MethodLength
|
67
|
+
def run(stdout: StringIO.new, stderr: StringIO.new) # rubocop:disable Metrics/MethodLength
|
68
68
|
@stdout = stdout
|
69
69
|
@stderr = stderr
|
70
|
-
return
|
70
|
+
return reporter.report_success if leftovers.empty?
|
71
71
|
|
72
72
|
only_test = []
|
73
73
|
none = []
|
@@ -79,17 +79,7 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
|
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
82
|
-
|
83
|
-
puts "\e[31mOnly directly called in tests:\e[0m"
|
84
|
-
only_test.each { |definition| reporter.call(definition) }
|
85
|
-
end
|
86
|
-
|
87
|
-
unless none.empty?
|
88
|
-
puts "\e[31mNot directly called at all:\e[0m"
|
89
|
-
none.each { |definition| reporter.call(definition) }
|
90
|
-
end
|
91
|
-
|
92
|
-
1
|
82
|
+
reporter.report(only_test: only_test, none: none)
|
93
83
|
end
|
94
84
|
|
95
85
|
def reset # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
@@ -104,6 +94,10 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
|
|
104
94
|
remove_instance_variable(:@pwd) if defined?(@pwd)
|
105
95
|
end
|
106
96
|
|
97
|
+
def resolution_instructions_link
|
98
|
+
"https://github.com/robotdana/leftovers/tree/v#{Leftovers::VERSION}/README.md#how_to_resolve"
|
99
|
+
end
|
100
|
+
|
107
101
|
def warn(message)
|
108
102
|
stderr.puts("\e[2K#{message}")
|
109
103
|
end
|
data/lib/leftovers/cli.rb
CHANGED
@@ -28,20 +28,29 @@ module Leftovers
|
|
28
28
|
Leftovers.progress = true
|
29
29
|
|
30
30
|
opts.banner = 'Usage: leftovers [options]'
|
31
|
+
|
31
32
|
opts.on('--[no-]parallel', 'Run in parallel or not, default --parallel') do |p|
|
32
33
|
Leftovers.parallel = p
|
33
34
|
end
|
35
|
+
|
34
36
|
opts.on('--[no-]progress', 'Show progress counts or not, default --progress') do |p|
|
35
37
|
Leftovers.progress = p
|
36
38
|
end
|
37
|
-
|
38
|
-
stdout.puts(Leftovers::VERSION)
|
39
|
-
Leftovers.exit
|
40
|
-
end
|
39
|
+
|
41
40
|
opts.on('--dry-run', 'Output files that will be looked at') do
|
42
41
|
Leftovers::FileList.new.each { |f| stdout.puts f.relative_path }
|
43
42
|
Leftovers.exit
|
44
43
|
end
|
44
|
+
|
45
|
+
opts.on('--write-todo', 'Outputs the unused items in a todo file to gradually fix') do
|
46
|
+
Leftovers.reporter = Leftovers::TodoReporter.new
|
47
|
+
end
|
48
|
+
|
49
|
+
opts.on('-v', '--version', 'Returns the current version') do
|
50
|
+
stdout.puts(Leftovers::VERSION)
|
51
|
+
Leftovers.exit
|
52
|
+
end
|
53
|
+
|
45
54
|
opts.on('-h', '--help', 'Shows this message') do
|
46
55
|
stdout.puts(opts.help)
|
47
56
|
Leftovers.exit
|
data/lib/leftovers/collector.rb
CHANGED
data/lib/leftovers/definition.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Leftovers
|
4
4
|
class Definition
|
5
|
-
attr_reader :name, :test, :location_s
|
5
|
+
attr_reader :name, :test, :location_s, :source_line
|
6
6
|
alias_method :names, :name
|
7
7
|
|
8
8
|
alias_method :test?, :test
|
@@ -14,7 +14,7 @@ module Leftovers
|
|
14
14
|
)
|
15
15
|
@name = name
|
16
16
|
@path = location.source_buffer.name.to_s
|
17
|
-
@
|
17
|
+
@source_line = location.source_line.to_s
|
18
18
|
@location_column_range_begin = location.column_range.begin.to_i
|
19
19
|
@location_column_range_end = location.column_range.end.to_i
|
20
20
|
@location_source = location.source.to_s
|
@@ -29,9 +29,9 @@ module Leftovers
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def highlighted_source(highlight = "\e[31m", normal = "\e[0m")
|
32
|
-
@
|
32
|
+
@source_line[0...@location_column_range_begin].lstrip +
|
33
33
|
highlight + @location_source + normal +
|
34
|
-
@
|
34
|
+
@source_line[@location_column_range_end..-1].rstrip
|
35
35
|
end
|
36
36
|
|
37
37
|
def in_collection?
|
@@ -12,6 +12,7 @@ module Leftovers
|
|
12
12
|
|
13
13
|
self << :ruby
|
14
14
|
self << project_config
|
15
|
+
self << project_todo
|
15
16
|
load_bundled_gem_config
|
16
17
|
end
|
17
18
|
|
@@ -32,6 +33,10 @@ module Leftovers
|
|
32
33
|
Leftovers::Config.new(:'.leftovers.yml', path: Leftovers.pwd + '.leftovers.yml')
|
33
34
|
end
|
34
35
|
|
36
|
+
def project_todo
|
37
|
+
Leftovers::Config.new(:'.leftovers_todo.yml', path: Leftovers.pwd + '.leftovers_todo.yml')
|
38
|
+
end
|
39
|
+
|
35
40
|
def unmemoize
|
36
41
|
remove_instance_variable(:@exclude_paths) if defined?(@exclude_paths)
|
37
42
|
remove_instance_variable(:@include_paths) if defined?(@include_paths)
|
data/lib/leftovers/reporter.rb
CHANGED
@@ -2,10 +2,62 @@
|
|
2
2
|
|
3
3
|
module Leftovers
|
4
4
|
class Reporter
|
5
|
-
def
|
6
|
-
|
7
|
-
|
8
|
-
)
|
5
|
+
def prepare; end
|
6
|
+
|
7
|
+
def report(only_test:, none:)
|
8
|
+
report_list('Only directly called in tests:', only_test)
|
9
|
+
report_list('Not directly called at all:', none)
|
10
|
+
report_instructions
|
11
|
+
|
12
|
+
1
|
13
|
+
end
|
14
|
+
|
15
|
+
def report_success
|
16
|
+
puts green('Everything is used')
|
17
|
+
|
18
|
+
0
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def report_instructions
|
24
|
+
puts <<~HELP
|
25
|
+
|
26
|
+
how to resolve: #{green Leftovers.resolution_instructions_link}
|
27
|
+
HELP
|
28
|
+
end
|
29
|
+
|
30
|
+
def report_list(title, list)
|
31
|
+
return if list.empty?
|
32
|
+
|
33
|
+
puts red(title)
|
34
|
+
list.each { |d| print_definition(d) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def print_definition(definition)
|
38
|
+
puts "#{aqua definition.location_s} "\
|
39
|
+
"#{definition} "\
|
40
|
+
"#{grey definition.highlighted_source("\e[33m", "\e[0;2m")}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def puts(string)
|
44
|
+
Leftovers.puts(string)
|
45
|
+
end
|
46
|
+
|
47
|
+
def red(string)
|
48
|
+
"\e[31m#{string}\e[0m"
|
49
|
+
end
|
50
|
+
|
51
|
+
def green(string)
|
52
|
+
"\e[32m#{string}\e[0m"
|
53
|
+
end
|
54
|
+
|
55
|
+
def aqua(string)
|
56
|
+
"\e[36m#{string}\e[0m"
|
57
|
+
end
|
58
|
+
|
59
|
+
def grey(string)
|
60
|
+
"\e[2m#{string}\e[0m"
|
9
61
|
end
|
10
62
|
end
|
11
63
|
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module Leftovers
|
6
|
+
class TodoReporter
|
7
|
+
def prepare
|
8
|
+
return unless path.exist?
|
9
|
+
|
10
|
+
puts "Removing previous #{path.basename} file"
|
11
|
+
puts ''
|
12
|
+
path.delete
|
13
|
+
end
|
14
|
+
|
15
|
+
def report(only_test:, none:)
|
16
|
+
path.write(generate_file_body(only_test, none))
|
17
|
+
report_instructions
|
18
|
+
|
19
|
+
0
|
20
|
+
end
|
21
|
+
|
22
|
+
def report_success
|
23
|
+
puts "No #{path.basename} file generated, everything is used"
|
24
|
+
|
25
|
+
0
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def report_instructions
|
31
|
+
puts <<~MESSAGE
|
32
|
+
generated #{path.basename}.
|
33
|
+
running leftovers again will read this file and
|
34
|
+
not alert you to any unused items mentioned in it.
|
35
|
+
|
36
|
+
commit this file so you/your team can gradually
|
37
|
+
address these items while still having leftovers
|
38
|
+
alert you to any newly unused items.
|
39
|
+
MESSAGE
|
40
|
+
end
|
41
|
+
|
42
|
+
def path
|
43
|
+
Leftovers.pwd.join('.leftovers_todo.yml')
|
44
|
+
end
|
45
|
+
|
46
|
+
def generate_file_body(only_test, none)
|
47
|
+
<<~YML.chomp
|
48
|
+
#{generation_message.chomp}
|
49
|
+
#
|
50
|
+
#{resolution_instructions}
|
51
|
+
#{todo_data(only_test, none).chomp}
|
52
|
+
YML
|
53
|
+
end
|
54
|
+
|
55
|
+
def generation_message
|
56
|
+
<<~YML
|
57
|
+
# This file was generated by `leftovers --write-todo`
|
58
|
+
# Generated at: #{Time.now.utc.strftime('%F %T')} UTC
|
59
|
+
YML
|
60
|
+
end
|
61
|
+
|
62
|
+
def resolution_instructions
|
63
|
+
<<~YML
|
64
|
+
# for instructions on how to address these
|
65
|
+
# see #{Leftovers.resolution_instructions_link}
|
66
|
+
YML
|
67
|
+
end
|
68
|
+
|
69
|
+
def todo_data(only_test, none)
|
70
|
+
none_test = none.select(&:test?)
|
71
|
+
none_non_test = none.reject(&:test?)
|
72
|
+
[
|
73
|
+
test_only_data(none_test),
|
74
|
+
keep_data(only_test, none_non_test)
|
75
|
+
].compact.join
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_only_data(list)
|
79
|
+
return if list.empty?
|
80
|
+
|
81
|
+
<<~YML
|
82
|
+
test_only:
|
83
|
+
#{generate_list('Defined in tests:', list).chomp}
|
84
|
+
YML
|
85
|
+
end
|
86
|
+
|
87
|
+
def keep_data(only_test, none_non_test)
|
88
|
+
return if only_test.empty? && none_non_test.empty?
|
89
|
+
|
90
|
+
<<~YML.chomp
|
91
|
+
keep:
|
92
|
+
#{keep_test_called_data(only_test)}#{keep_never_called_data(none_non_test)}
|
93
|
+
YML
|
94
|
+
end
|
95
|
+
|
96
|
+
def keep_test_called_data(list)
|
97
|
+
return if list.empty?
|
98
|
+
|
99
|
+
generate_list('Only directly called in tests:', list)
|
100
|
+
end
|
101
|
+
|
102
|
+
def keep_never_called_data(list)
|
103
|
+
return if list.empty?
|
104
|
+
|
105
|
+
generate_list('Not directly called at all:', list)
|
106
|
+
end
|
107
|
+
|
108
|
+
def generate_list(title, list)
|
109
|
+
<<~YML
|
110
|
+
# #{title}
|
111
|
+
#{list.map { |d| print_definition(d) }.join("\n")}
|
112
|
+
|
113
|
+
YML
|
114
|
+
end
|
115
|
+
|
116
|
+
def print_definition(definition)
|
117
|
+
" - #{definition.to_s.inspect} # #{definition.location_s} #{definition.source_line.strip}"
|
118
|
+
end
|
119
|
+
|
120
|
+
def puts(string)
|
121
|
+
Leftovers.puts(string)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
data/lib/leftovers/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: leftovers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dana Sherson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -178,6 +178,20 @@ dependencies:
|
|
178
178
|
- - ">="
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: timecop
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :development
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
181
195
|
- !ruby/object:Gem::Dependency
|
182
196
|
name: tty_string
|
183
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -381,6 +395,7 @@ files:
|
|
381
395
|
- lib/leftovers/processor_builders/value.rb
|
382
396
|
- lib/leftovers/rake_task.rb
|
383
397
|
- lib/leftovers/reporter.rb
|
398
|
+
- lib/leftovers/todo_reporter.rb
|
384
399
|
- lib/leftovers/value_processors.rb
|
385
400
|
- lib/leftovers/value_processors/add_dynamic_prefix.rb
|
386
401
|
- lib/leftovers/value_processors/add_dynamic_suffix.rb
|
@@ -439,7 +454,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
439
454
|
- !ruby/object:Gem::Version
|
440
455
|
version: '0'
|
441
456
|
requirements: []
|
442
|
-
rubygems_version: 3.1.
|
457
|
+
rubygems_version: 3.1.6
|
443
458
|
signing_key:
|
444
459
|
specification_version: 4
|
445
460
|
summary: Find unused methods and classes/modules
|