leftovers 0.11.1 → 0.11.2

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.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +1 -0
  4. data/docs/Configuration.md +7 -0
  5. data/exe/leftovers +3 -1
  6. data/leftovers.gemspec +3 -4
  7. data/lib/config/activesupport.yml +1 -1
  8. data/lib/config/rspec.yml +21 -0
  9. data/lib/leftovers/ast/array_node.rb +2 -2
  10. data/lib/leftovers/ast/block_node.rb +1 -1
  11. data/lib/leftovers/ast/builder.rb +19 -18
  12. data/lib/leftovers/ast/casgn_node.rb +2 -2
  13. data/lib/leftovers/ast/const_node.rb +1 -1
  14. data/lib/leftovers/ast/def_node.rb +1 -1
  15. data/lib/leftovers/ast/defs_node.rb +1 -1
  16. data/lib/leftovers/ast/false_node.rb +1 -1
  17. data/lib/leftovers/ast/hash_node.rb +2 -2
  18. data/lib/leftovers/ast/module_node.rb +1 -1
  19. data/lib/leftovers/ast/nil_node.rb +1 -1
  20. data/lib/leftovers/ast/node.rb +13 -1
  21. data/lib/leftovers/ast/numeric_node.rb +1 -1
  22. data/lib/leftovers/ast/send_node.rb +16 -3
  23. data/lib/leftovers/ast/str_node.rb +1 -1
  24. data/lib/leftovers/ast/sym_node.rb +1 -1
  25. data/lib/leftovers/ast/true_node.rb +1 -1
  26. data/lib/leftovers/ast/var_node.rb +1 -1
  27. data/lib/leftovers/ast/vasgn_node.rb +2 -2
  28. data/lib/leftovers/ast.rb +2 -21
  29. data/lib/leftovers/autoloader.rb +36 -0
  30. data/lib/leftovers/cli.rb +58 -42
  31. data/lib/leftovers/collection.rb +66 -0
  32. data/lib/leftovers/collector.rb +17 -27
  33. data/lib/leftovers/config.rb +17 -5
  34. data/lib/leftovers/config_loader/attribute.rb +2 -2
  35. data/lib/leftovers/config_loader/bool_schema.rb +21 -0
  36. data/lib/leftovers/config_loader/document_schema.rb +2 -2
  37. data/lib/leftovers/config_loader/inherit_schema_attributes.rb +1 -1
  38. data/lib/leftovers/config_loader/node.rb +8 -8
  39. data/lib/leftovers/config_loader/regexp_schema.rb +1 -1
  40. data/lib/leftovers/config_loader/rule_pattern_schema.rb +1 -0
  41. data/lib/leftovers/config_loader/schema.rb +1 -1
  42. data/lib/leftovers/config_loader/string_enum_schema.rb +1 -1
  43. data/lib/leftovers/config_loader/value_or_array_schema.rb +1 -1
  44. data/lib/leftovers/config_loader.rb +8 -48
  45. data/lib/leftovers/definition.rb +4 -4
  46. data/lib/leftovers/definition_collection.rb +3 -3
  47. data/lib/leftovers/definition_node.rb +2 -2
  48. data/lib/leftovers/definition_node_set.rb +1 -1
  49. data/lib/leftovers/definition_set.rb +4 -4
  50. data/lib/leftovers/definition_to_add.rb +2 -2
  51. data/lib/leftovers/error.rb +6 -0
  52. data/lib/leftovers/file.rb +4 -4
  53. data/lib/leftovers/file_collector/comments_processor.rb +23 -18
  54. data/lib/leftovers/file_collector/node_processor.rb +8 -1
  55. data/lib/leftovers/file_collector.rb +12 -15
  56. data/lib/leftovers/file_list.rb +4 -6
  57. data/lib/leftovers/matcher_builders/and.rb +5 -5
  58. data/lib/leftovers/matcher_builders/document.rb +1 -3
  59. data/lib/leftovers/matcher_builders/name.rb +4 -7
  60. data/lib/leftovers/matcher_builders/node.rb +21 -35
  61. data/lib/leftovers/matcher_builders/node_has_argument.rb +17 -29
  62. data/lib/leftovers/matcher_builders/node_has_block.rb +17 -0
  63. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +7 -9
  64. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +10 -10
  65. data/lib/leftovers/matcher_builders/node_has_receiver.rb +6 -8
  66. data/lib/leftovers/matcher_builders/node_name.rb +3 -5
  67. data/lib/leftovers/matcher_builders/node_pair_key.rb +4 -4
  68. data/lib/leftovers/matcher_builders/node_pair_value.rb +4 -4
  69. data/lib/leftovers/matcher_builders/node_path.rb +3 -4
  70. data/lib/leftovers/matcher_builders/node_privacy.rb +3 -3
  71. data/lib/leftovers/matcher_builders/node_type.rb +13 -14
  72. data/lib/leftovers/matcher_builders/node_value.rb +18 -31
  73. data/lib/leftovers/matcher_builders/or.rb +10 -10
  74. data/lib/leftovers/matcher_builders/path.rb +3 -3
  75. data/lib/leftovers/matcher_builders/string_pattern.rb +2 -0
  76. data/lib/leftovers/matcher_builders/unless.rb +1 -3
  77. data/lib/leftovers/matcher_builders.rb +2 -22
  78. data/lib/leftovers/matchers/node_has_block.rb +13 -0
  79. data/lib/leftovers/matchers/node_scalar_value.rb +1 -1
  80. data/lib/leftovers/matchers.rb +2 -27
  81. data/lib/leftovers/merged_config.rb +16 -17
  82. data/lib/leftovers/parser.rb +1 -1
  83. data/lib/leftovers/precompile_error.rb +31 -0
  84. data/lib/leftovers/precompilers/haml.rb +23 -3
  85. data/lib/leftovers/precompilers/json.rb +1 -1
  86. data/lib/leftovers/precompilers/precompiler.rb +3 -3
  87. data/lib/leftovers/precompilers/slim.rb +1 -1
  88. data/lib/leftovers/precompilers/yaml/builder.rb +62 -0
  89. data/lib/leftovers/precompilers/yaml.rb +3 -56
  90. data/lib/leftovers/precompilers.rb +11 -16
  91. data/lib/leftovers/processor_builders/action.rb +15 -19
  92. data/lib/leftovers/processor_builders/add_prefix.rb +4 -6
  93. data/lib/leftovers/processor_builders/add_suffix.rb +4 -6
  94. data/lib/leftovers/processor_builders/argument.rb +10 -15
  95. data/lib/leftovers/processor_builders/dynamic.rb +12 -30
  96. data/lib/leftovers/processor_builders/each.rb +63 -76
  97. data/lib/leftovers/processor_builders/each_for_definition_set.rb +15 -0
  98. data/lib/leftovers/processor_builders/itself.rb +2 -4
  99. data/lib/leftovers/processor_builders/keyword.rb +4 -4
  100. data/lib/leftovers/processor_builders/keyword_argument.rb +4 -4
  101. data/lib/leftovers/processor_builders/receiver.rb +2 -4
  102. data/lib/leftovers/processor_builders/transform.rb +26 -49
  103. data/lib/leftovers/processor_builders/transform_chain.rb +4 -7
  104. data/lib/leftovers/processor_builders/transform_set.rb +6 -7
  105. data/lib/leftovers/processor_builders/value.rb +2 -2
  106. data/lib/leftovers/processor_builders.rb +2 -15
  107. data/lib/leftovers/processors/add_definition_node.rb +2 -2
  108. data/lib/leftovers/processors/camelize.rb +3 -3
  109. data/lib/leftovers/processors/deconstantize.rb +3 -3
  110. data/lib/leftovers/processors/demodulize.rb +3 -3
  111. data/lib/leftovers/processors/each_for_definition_set.rb +2 -2
  112. data/lib/leftovers/processors/eval.rb +1 -1
  113. data/lib/leftovers/processors/parameterize.rb +3 -3
  114. data/lib/leftovers/processors/placeholder.rb +1 -1
  115. data/lib/leftovers/processors/pluralize.rb +3 -3
  116. data/lib/leftovers/processors/set_default_privacy.rb +1 -1
  117. data/lib/leftovers/processors/set_privacy.rb +1 -1
  118. data/lib/leftovers/processors/singularize.rb +3 -3
  119. data/lib/leftovers/processors/titleize.rb +3 -3
  120. data/lib/leftovers/processors/underscore.rb +3 -3
  121. data/lib/leftovers/processors.rb +2 -44
  122. data/lib/leftovers/rake_task.rb +2 -2
  123. data/lib/leftovers/reporter.rb +44 -42
  124. data/lib/leftovers/runner.rb +40 -0
  125. data/lib/leftovers/todo_reporter.rb +96 -94
  126. data/lib/leftovers/unexpected_case.rb +8 -0
  127. data/lib/leftovers/version.rb +1 -1
  128. data/lib/leftovers.rb +17 -110
  129. metadata +13 -17
  130. data/lib/leftovers/matcher_builders/and_not.rb +0 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 99d72b44b74c747074583f8c9254872a175563d0f25135b7798c5e76f42c19ef
4
- data.tar.gz: 6b4bd9219256b8734df956978892da7ffe028e0539367a1f98d46c73912ae79e
3
+ metadata.gz: 315c6cd9bf74247b3a2833ab260854e397d8cc24bee3c12f3bc56d6d63e1c126
4
+ data.tar.gz: 8f2c20446893d35ca268b7506f34e164038c86860c1ffa3bce5e94b83058a188
5
5
  SHA512:
6
- metadata.gz: d51c93c652bdd0aa55a176c1600e9d557fd29e7e9726411d7ac6eb086178a655e17e96e8d7530c97945f169d32961649358dd712daf9e50cb82b30caa1b55c10
7
- data.tar.gz: b8ca04321b17c7d9c9b831f3fb2fab47554d859f910d38f08a04d41f344c4585a1008019af12d13b3e2807027fe6ba7d6fd6a4d1eca3fb947d68d6812249bc39
6
+ metadata.gz: 8e9461b01555758b8f7f5de3c15e262fff559aaffc1045d9cfb0c121e68822a8ad4187599eae19154758f1418ec8fd859b2ccf47839b4831d4caab5f26662d53
7
+ data.tar.gz: 81ee36d822947afbb3b626b9b09363b1ae9528aead85ac0312f80e7f07cc6867a0ef575255c02d723fa0f0dc46042b161d337cd3f5ee6a71e9075dc5eaec19f8
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # v0.11.2
2
+
3
+ - add `has_block: true/false` for matching method calls with a block.
4
+ - fix block_pass (`call(&block)`) being considered a regular argument, which meant the keyword arguments was a hash in the second-last position instead of the last position, so weren't keyword arguments, and also inflated how many positional arguments there were.
5
+ - Fixed integration with Haml 6.x
6
+ - Noted the with_options limitation in readme
7
+ - Add more rspec config: `RSpec::Matchers.define`, `matcher {}`, `alias_matcher`
8
+
1
9
  # v0.11.1
2
10
  - Fixed an issue with parsing files that have `MyConstant ||= value` patterns #19 (thanks for the pr - @kamoh)
3
11
 
data/README.md CHANGED
@@ -185,6 +185,7 @@ see the [built in config files](https://github.com/robotdana/leftovers/tree/main
185
185
  Add the method/pattern to the `dynamic:` list with `skip: true` in the `.leftovers.yml`, or add an inline comment with the list of possibilities `# leftovers:call my_method_1, my_method_2`.
186
186
  - Leftovers compares by name only, so multiple definitions with the same name will count as used even if only one is.
187
187
  - haml, slim & erb line and column numbers will be wrong as the files have to be precompiled before checking.
188
+ - dynamic calls & definitions based on values copied by rails `with_options` method aren't captured by leftovers.
188
189
 
189
190
  ## Other tools
190
191
 
@@ -250,6 +250,7 @@ Each entry must have at least one of the following properties to restrict which
250
250
  - [`paths:`](#paths)
251
251
  - [`has_arguments:`](#has_arguments)
252
252
  - [`has_receiver:`](#has_receiver)
253
+ - [`has_block:`](#has_block)
253
254
  - [`type:`](#type)
254
255
  - [`privacy:`](#privacy)
255
256
  - [`unless:`](#unless)
@@ -528,6 +529,12 @@ Arrays are not necessary for single values and if the rule contains only `at:` i
528
529
 
529
530
  Positional arguments are zero indexed
530
531
 
532
+ ## `has_block:`
533
+
534
+ Use `has_block: true` or `has_block: false` filter by whether they have a block or not
535
+
536
+ This will match either `this { syntax }` or `this(&syntax)`
537
+
531
538
  ## `keywords:`
532
539
  When the keyword argument **keywords** are the thing being called.
533
540
 
data/exe/leftovers CHANGED
@@ -3,4 +3,6 @@
3
3
 
4
4
  require_relative '../lib/leftovers'
5
5
 
6
- exit Leftovers::CLI.new(argv: ARGV).run
6
+ Leftovers.stderr = $stderr
7
+ Leftovers.stdout = $stdout
8
+ exit ::Leftovers::CLI.new(argv: ::ARGV).run
data/leftovers.gemspec CHANGED
@@ -4,9 +4,9 @@ lib = ::File.expand_path('lib', __dir__)
4
4
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
5
  require 'leftovers/version'
6
6
 
7
- Gem::Specification.new do |spec|
7
+ ::Gem::Specification.new do |spec|
8
8
  spec.name = 'leftovers'
9
- spec.version = Leftovers::VERSION
9
+ spec.version = ::Leftovers::VERSION
10
10
  spec.authors = ['Dana Sherson']
11
11
  spec.email = ['robot@dana.sh']
12
12
 
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
  spec.metadata['rubygems_mfa_required'] = 'true'
22
22
  spec.required_ruby_version = '>= 2.5.0'
23
23
 
24
- spec.files = Dir.glob('{lib,exe,docs}/**/{*,.*}') + %w{
24
+ spec.files = ::Dir.glob('{lib,exe,docs}/**/{*,.*}') + %w{
25
25
  CHANGELOG.md
26
26
  Gemfile
27
27
  LICENSE.txt
@@ -35,7 +35,6 @@ Gem::Specification.new do |spec|
35
35
  spec.add_development_dependency 'activesupport'
36
36
  spec.add_development_dependency 'benchmark-ips'
37
37
  spec.add_development_dependency 'bundler', '~> 2.0'
38
- spec.add_development_dependency 'did_you_mean'
39
38
  spec.add_development_dependency 'haml'
40
39
  spec.add_development_dependency 'pry', '~> 0.1'
41
40
  spec.add_development_dependency 'rake', '>= 13'
@@ -156,7 +156,7 @@ dynamic:
156
156
  calls: 1
157
157
  unless:
158
158
  - has_argument: 2
159
- # - has_block_argument: true
159
+ - has_block: true
160
160
 
161
161
  # https://api.rubyonrails.org/classes/ActiveSupport/Callbacks/ClassMethods.html#method-i-skip_callback
162
162
  - name: skip_callback
data/lib/config/rspec.yml CHANGED
@@ -62,3 +62,24 @@ dynamic:
62
62
  has_argument: 1
63
63
  defines: 0
64
64
  path: /spec/
65
+
66
+ - name: define
67
+ has_receiver:
68
+ match: Matchers
69
+ has_receiver: RSpec
70
+ defines:
71
+ argument: 0
72
+ path: /spec/
73
+
74
+ - name: matcher
75
+ has_block: true
76
+ defines:
77
+ argument: 0
78
+ path: /spec/
79
+
80
+ - name: alias_matcher
81
+ defines:
82
+ argument: 0
83
+ calls:
84
+ argument: 1
85
+ path: /spec/
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class ArrayNode < ::Leftovers::AST::Node
6
- include Leftovers::AST::HasArguments
5
+ class ArrayNode < Node
6
+ include HasArguments
7
7
 
8
8
  alias_method :arguments, :children
9
9
  alias_method :as_arguments_list, :arguments
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class BlockNode < ::Leftovers::AST::Node
5
+ class BlockNode < Node
6
6
  def proc?
7
7
  name = first.name
8
8
  name == :lambda || name == :proc
@@ -11,28 +11,29 @@ module Leftovers
11
11
 
12
12
  def self.node_class(type) # rubocop:disable Metrics
13
13
  case type
14
- when :array then ::Leftovers::AST::ArrayNode
15
- when :block then ::Leftovers::AST::BlockNode
16
- when :casgn then ::Leftovers::AST::CasgnNode
17
- when :const then ::Leftovers::AST::ConstNode
18
- when :def then ::Leftovers::AST::DefNode
19
- when :defs then ::Leftovers::AST::DefsNode
20
- when :false then ::Leftovers::AST::FalseNode
21
- when :hash then ::Leftovers::AST::HashNode
22
- when :int, :float then ::Leftovers::AST::NumericNode
23
- when :lvar, :ivar, :gvar, :cvar then ::Leftovers::AST::VarNode
24
- when :ivasgn, :cvasgn, :gvasgn then ::Leftovers::AST::VasgnNode
25
- when :module, :class then ::Leftovers::AST::ModuleNode
26
- when :nil then ::Leftovers::AST::NilNode
27
- when :send, :csend then ::Leftovers::AST::SendNode
28
- when :str then ::Leftovers::AST::StrNode
29
- when :sym then ::Leftovers::AST::SymNode
30
- when :true then ::Leftovers::AST::TrueNode
31
- else ::Leftovers::AST::Node
14
+ when :array then ArrayNode
15
+ when :block then BlockNode
16
+ when :casgn then CasgnNode
17
+ when :const then ConstNode
18
+ when :def then DefNode
19
+ when :defs then DefsNode
20
+ when :false then FalseNode
21
+ when :hash then HashNode
22
+ when :int, :float then NumericNode
23
+ when :lvar, :ivar, :gvar, :cvar then VarNode
24
+ when :ivasgn, :cvasgn, :gvasgn then VasgnNode
25
+ when :module, :class then ModuleNode
26
+ when :nil then NilNode
27
+ when :send, :csend then SendNode
28
+ when :str then StrNode
29
+ when :sym then SymNode
30
+ when :true then TrueNode
31
+ else Node
32
32
  end
33
33
  end
34
34
 
35
35
  # Don't complain about invalid strings
36
+ # This is called by ::Parser::AST internals
36
37
  def string_value(token) # leftovers:keep
37
38
  value(token)
38
39
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class CasgnNode < ::Leftovers::AST::Node
6
- include Leftovers::AST::HasArguments
5
+ class CasgnNode < Node
6
+ include HasArguments
7
7
 
8
8
  alias_method :name, :second
9
9
  alias_method :to_sym, :second
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class ConstNode < ::Leftovers::AST::Node
5
+ class ConstNode < Node
6
6
  alias_method :receiver, :first
7
7
  alias_method :name, :second
8
8
  alias_method :to_sym, :second
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class DefNode < ::Leftovers::AST::Node
5
+ class DefNode < Node
6
6
  alias_method :name, :first
7
7
  alias_method :to_sym, :first
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class DefsNode < ::Leftovers::AST::Node
5
+ class DefsNode < Node
6
6
  alias_method :name, :second
7
7
  alias_method :to_sym, :second
8
8
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class FalseNode < ::Leftovers::AST::Node
5
+ class FalseNode < Node
6
6
  def to_scalar_value
7
7
  false
8
8
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class HashNode < ::Leftovers::AST::Node
6
- include Leftovers::AST::HasArguments
5
+ class HashNode < Node
6
+ include HasArguments
7
7
 
8
8
  def arguments
9
9
  @memo[:arguments] ||= [self]
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class ModuleNode < ::Leftovers::AST::Node
5
+ class ModuleNode < Node
6
6
  def name
7
7
  first.name
8
8
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class NilNode < ::Leftovers::AST::Node
5
+ class NilNode < Node
6
6
  def to_scalar_value
7
7
  nil
8
8
  end
@@ -17,7 +17,7 @@ module Leftovers
17
17
  def updated(type = nil, children = nil, properties = nil) # leftovers:keep
18
18
  maybe_copy = super
19
19
 
20
- class_for_type = Leftovers::AST::Builder.node_class(maybe_copy.type)
20
+ class_for_type = Builder.node_class(maybe_copy.type)
21
21
  return maybe_copy if maybe_copy.instance_of?(class_for_type)
22
22
 
23
23
  class_for_type.new(maybe_copy.type, maybe_copy.children, location: maybe_copy.loc)
@@ -43,6 +43,14 @@ module Leftovers
43
43
  @memo[:privacy] || :public
44
44
  end
45
45
 
46
+ def parent
47
+ @memo[:parent]
48
+ end
49
+
50
+ def parent=(value)
51
+ @memo[:parent] = value
52
+ end
53
+
46
54
  def to_scalar_value
47
55
  nil
48
56
  end
@@ -98,6 +106,10 @@ module Leftovers
98
106
  def name
99
107
  nil
100
108
  end
109
+
110
+ def block_given?
111
+ false
112
+ end
101
113
  end
102
114
  end
103
115
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class NumericNode < ::Leftovers::AST::Node
5
+ class NumericNode < Node
6
6
  alias_method :to_scalar_value, :first
7
7
 
8
8
  def scalar?
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class SendNode < ::Leftovers::AST::Node
6
- include Leftovers::AST::HasArguments
5
+ class SendNode < Node
6
+ include HasArguments
7
7
 
8
8
  alias_method :receiver, :first
9
9
  alias_method :name, :second
@@ -14,12 +14,25 @@ module Leftovers
14
14
  end
15
15
 
16
16
  def arguments
17
- @memo[:arguments] ||= children.drop(2)
17
+ @memo[:arguments] ||= if block_pass_argument?
18
+ children[2...-1]
19
+ else
20
+ children.drop(2)
21
+ end
18
22
  end
19
23
 
20
24
  def as_arguments_list
21
25
  first.as_arguments_list if name == :freeze
22
26
  end
27
+
28
+ def block_pass_argument?
29
+ last_child = children.last
30
+ last_child.respond_to?(:type) && last_child.type == :block_pass
31
+ end
32
+
33
+ def block_given?
34
+ block_pass_argument? || parent&.type == :block
35
+ end
23
36
  end
24
37
  end
25
38
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class StrNode < ::Leftovers::AST::Node
5
+ class StrNode < Node
6
6
  alias_method :to_scalar_value, :first
7
7
 
8
8
  def name
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class SymNode < ::Leftovers::AST::Node
5
+ class SymNode < Node
6
6
  alias_method :name, :first
7
7
  alias_method :to_scalar_value, :first
8
8
  alias_method :to_sym, :first
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class TrueNode < ::Leftovers::AST::Node
5
+ class TrueNode < Node
6
6
  def to_scalar_value
7
7
  true
8
8
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class VarNode < ::Leftovers::AST::Node
5
+ class VarNode < Node
6
6
  alias_method :name, :first
7
7
  alias_method :to_sym, :first
8
8
 
@@ -2,8 +2,8 @@
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- class VasgnNode < ::Leftovers::AST::Node
6
- include Leftovers::AST::HasArguments
5
+ class VasgnNode < Node
6
+ include HasArguments
7
7
 
8
8
  alias_method :name, :first
9
9
  alias_method :to_sym, :first
data/lib/leftovers/ast.rb CHANGED
@@ -1,26 +1,7 @@
1
- # frozen-string-literal: true
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Leftovers
4
4
  module AST
5
- autoload(:ArrayNode, "#{__dir__}/ast/array_node")
6
- autoload(:BlockNode, "#{__dir__}/ast/block_node")
7
- autoload(:Builder, "#{__dir__}/ast/builder")
8
- autoload(:CasgnNode, "#{__dir__}/ast/casgn_node")
9
- autoload(:ConstNode, "#{__dir__}/ast/const_node")
10
- autoload(:DefNode, "#{__dir__}/ast/def_node")
11
- autoload(:DefsNode, "#{__dir__}/ast/defs_node")
12
- autoload(:FalseNode, "#{__dir__}/ast/false_node")
13
- autoload(:HashNode, "#{__dir__}/ast/hash_node")
14
- autoload(:HasArguments, "#{__dir__}/ast/has_arguments")
15
- autoload(:ModuleNode, "#{__dir__}/ast/module_node")
16
- autoload(:NilNode, "#{__dir__}/ast/nil_node")
17
- autoload(:Node, "#{__dir__}/ast/node")
18
- autoload(:NumericNode, "#{__dir__}/ast/numeric_node")
19
- autoload(:SendNode, "#{__dir__}/ast/send_node")
20
- autoload(:StrNode, "#{__dir__}/ast/str_node")
21
- autoload(:SymNode, "#{__dir__}/ast/sym_node")
22
- autoload(:TrueNode, "#{__dir__}/ast/true_node")
23
- autoload(:VasgnNode, "#{__dir__}/ast/vasgn_node")
24
- autoload(:VarNode, "#{__dir__}/ast/var_node")
5
+ include Autoloader
25
6
  end
26
7
  end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ # zero dependency zeitwerk
5
+ module Autoloader
6
+ ALL_CAPS_NAMES = %w{ast cli version erb json yaml}.freeze
7
+
8
+ def self.included(klass)
9
+ ::Dir[glob_children(klass)].each_entry do |path|
10
+ klass.autoload(class_from_path(path), path)
11
+ end
12
+ end
13
+
14
+ def self.class_from_path(path)
15
+ name = ::File.basename(path).delete_suffix('.rb')
16
+ if ALL_CAPS_NAMES.include?(name)
17
+ name.upcase
18
+ else
19
+ name.gsub(/(?:^|_)(\w)/, &:upcase).delete('_')
20
+ end
21
+ end
22
+
23
+ def self.dir_path_from_class(klass)
24
+ klass.name.gsub(/::/, '/')
25
+ .gsub(/(?<=[a-z])([A-Z])/, '_\1').downcase
26
+ end
27
+
28
+ def self.glob_children(klass)
29
+ "#{root}/#{dir_path_from_class(klass)}/*.rb"
30
+ end
31
+
32
+ def self.root
33
+ ::File.dirname(__dir__)
34
+ end
35
+ end
36
+ end
data/lib/leftovers/cli.rb CHANGED
@@ -1,73 +1,89 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'optparse'
4
+
4
5
  module Leftovers
5
6
  class CLI
6
- def initialize(argv: [], stdout: $stdout, stderr: $stderr)
7
+ def initialize(argv: [])
7
8
  @argv = argv
8
- @stdout = stdout
9
- @stderr = stderr
10
9
  end
11
10
 
12
11
  def run
13
12
  catch(:leftovers_exit) do
14
- Leftovers.reset
15
13
  parse_options
16
14
 
17
- Leftovers.run(stdout: stdout, stderr: stderr)
15
+ runner.run
18
16
  end
19
17
  end
20
18
 
21
19
  private
22
20
 
23
- attr_reader :argv, :stdout, :stderr
24
-
25
- def parse_options # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
26
- opts = OptionParser.new
27
- Leftovers.parallel = true
28
- Leftovers.progress = true
21
+ attr_reader :argv
29
22
 
30
- opts.banner = 'Usage: leftovers [options]'
23
+ def option_parser
24
+ @option_parser ||= ::OptionParser.new do |o|
25
+ o.banner = 'Usage: leftovers [options]'
31
26
 
32
- opts.on('--[no-]parallel', 'Run in parallel or not, default --parallel') do |p|
33
- Leftovers.parallel = p
27
+ o.on('--[no-]parallel', 'Run in parallel or not, default --parallel') { |p| parallel(p) }
28
+ o.on('--[no-]progress', 'Show live counts or not, default --progress') { |p| progress(p) }
29
+ o.on('--dry-run', 'Print a list of files that would be looked at') { dry_run }
30
+ o.on('--view-compiled', 'Print the compiled content of the files') { view_compiled }
31
+ o.on('--write-todo', 'Create a config file with the existing unused items') { write_todo }
32
+ o.on('-v', '--version', 'Print the current version') { print_version }
33
+ o.on('-h', '--help', 'Print this message') { print_help }
34
34
  end
35
+ end
35
36
 
36
- opts.on('--[no-]progress', 'Show progress counts or not, default --progress') do |p|
37
- Leftovers.progress = p
38
- end
37
+ def parse_options
38
+ option_parser.parse!(argv)
39
+ rescue ::OptionParser::ParseError => e
40
+ ::Leftovers.error("CLI Error: #{e.message}", option_parser.help)
41
+ end
39
42
 
40
- opts.on('--dry-run', 'Output files that will be looked at') do
41
- Leftovers::FileList.new.each { |f| stdout.puts f.relative_path }
42
- Leftovers.exit
43
- end
43
+ def runner
44
+ @runner ||= Runner.new
45
+ end
44
46
 
45
- opts.on('--view-compiled', 'Output the compiled content of the files') do
46
- Leftovers::FileList.new(argv_rules: argv)
47
- .each { |f| stdout.puts "\e[0;2m#{f.relative_path}\e[0m\n#{f.ruby}" }
48
- Leftovers.exit
49
- end
47
+ def exit(status = 0)
48
+ ::Leftovers.exit status
49
+ end
50
50
 
51
- opts.on('--write-todo', 'Outputs the unused items in a todo file to gradually fix') do
52
- Leftovers.reporter = Leftovers::TodoReporter.new
53
- end
51
+ def dry_run
52
+ FileList.new.each { |file| ::Leftovers.puts file.relative_path }
54
53
 
55
- opts.on('-v', '--version', 'Returns the current version') do
56
- stdout.puts(Leftovers::VERSION)
57
- Leftovers.exit
58
- end
54
+ exit
55
+ end
59
56
 
60
- opts.on('-h', '--help', 'Shows this message') do
61
- stdout.puts(opts.help)
62
- Leftovers.exit
57
+ def view_compiled
58
+ FileList.new(argv_rules: argv).each do |file|
59
+ ::Leftovers.puts "\e[0;2m#{file.relative_path}\e[0m\n#{file.ruby}"
63
60
  end
64
61
 
65
- opts.parse!(argv)
66
- rescue OptionParser::InvalidOption => e
67
- stderr.puts("\e[31mCLI Error: #{e.message}\e[0m")
68
- stderr.puts ''
69
- stderr.puts(opts.help)
70
- Leftovers.exit 1
62
+ exit
63
+ end
64
+
65
+ def print_version
66
+ ::Leftovers.puts(VERSION)
67
+
68
+ exit
69
+ end
70
+
71
+ def print_help
72
+ ::Leftovers.puts(option_parser.help)
73
+
74
+ exit
75
+ end
76
+
77
+ def parallel(value)
78
+ runner.parallel = value
79
+ end
80
+
81
+ def progress(value)
82
+ runner.progress = value
83
+ end
84
+
85
+ def write_todo
86
+ runner.reporter = TodoReporter
71
87
  end
72
88
  end
73
89
  end