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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 98a1dcd328efccf139ec0cfb56a81d5a723b8a6ba62bfd0b522466aa4f8e0a82
4
- data.tar.gz: 906c53f6e6963692846639df0619c694e65c9410abc75db6dc3f5a519a2e57d0
3
+ metadata.gz: aa735d4aa3320b0225d0d256c296b5b3b284593f285d1257a4b8e6bd74a0dd74
4
+ data.tar.gz: ebaaa2f4c2e93780788e36d961a623a015b1f8d11c0a9799882e5a21a45552f4
5
5
  SHA512:
6
- metadata.gz: 2ba271c0482aca8feeb1d30e4359b262ecff4f626737ac31b3ca445b0884e52815dbffcac0967b72a903597ea530307abb00ac40fab8b40487f7fdcf0f1b2571
7
- data.tar.gz: 0b59bfb6cbfb399be40fa10ebc2c66b5633f5a4ba55da1397010e4d0e577540eff7b9e5c7ddae296fea2def2b99d2449168ef3b91cb165b9ff67d433fb43ec83
6
+ metadata.gz: 88cf80851cdb71a94a3d5497fa80ab4b020447e6aa23b1a9074ef19789bcdc77b576275aad066ac23170b1d2d18687f0b07322b24792cd31a163f2e70f3d637e
7
+ data.tar.gz: '0167915df5ad01dcf2368e72a98171cad57b22e4df7d6c8e5bc29b1e8e053b8a9e522746836102d769ca80745105021bbeb297d038ab8cd58410a2d797c34d04'
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # v0.4.3
2
+ - add --write-todo so you can add this to your project without
3
+ immediately fixing everything.
4
+
1
5
  # v0.4.2
2
6
  - Make sorbet happy with this as a dependency
3
7
  # v0.4.1
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, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
67
+ def run(stdout: StringIO.new, stderr: StringIO.new) # rubocop:disable Metrics/MethodLength
68
68
  @stdout = stdout
69
69
  @stderr = stderr
70
- return 0 if leftovers.empty?
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
- unless only_test.empty?
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
- opts.on('-v', '--version', 'Returns the current version') do
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
@@ -18,6 +18,7 @@ module Leftovers
18
18
  end
19
19
 
20
20
  def collect
21
+ Leftovers.reporter.prepare
21
22
  collect_file_list(Leftovers::FileList.new)
22
23
  print_progress
23
24
  Leftovers.newline
@@ -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
- @location_source_line = location.source_line.to_s
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
- @location_source_line[0...@location_column_range_begin].lstrip +
32
+ @source_line[0...@location_column_range_begin].lstrip +
33
33
  highlight + @location_source + normal +
34
- @location_source_line[@location_column_range_end..-1].rstrip
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)
@@ -2,10 +2,62 @@
2
2
 
3
3
  module Leftovers
4
4
  class Reporter
5
- def call(definition)
6
- Leftovers.puts(
7
- "\e[36m#{definition.location_s}\e[0m #{definition} \e[2m#{definition.highlighted_source("\e[33m", "\e[0;2m")}\e[0m" # rubocop:disable Layout/LineLength
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leftovers
4
- VERSION = '0.4.2'
4
+ VERSION = '0.4.3'
5
5
  end
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.2
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: 2020-11-20 00:00:00.000000000 Z
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.2
457
+ rubygems_version: 3.1.6
443
458
  signing_key:
444
459
  specification_version: 4
445
460
  summary: Find unused methods and classes/modules