leftovers 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
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