leftovers 0.11.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +12 -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 +64 -45
  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/error.rb +16 -0
  55. data/lib/leftovers/file_collector/node_processor.rb +19 -2
  56. data/lib/leftovers/file_collector.rb +28 -20
  57. data/lib/leftovers/file_list.rb +4 -6
  58. data/lib/leftovers/matcher_builders/and.rb +5 -5
  59. data/lib/leftovers/matcher_builders/document.rb +1 -3
  60. data/lib/leftovers/matcher_builders/name.rb +4 -7
  61. data/lib/leftovers/matcher_builders/node.rb +21 -35
  62. data/lib/leftovers/matcher_builders/node_has_argument.rb +17 -29
  63. data/lib/leftovers/matcher_builders/node_has_block.rb +17 -0
  64. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +7 -9
  65. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +10 -10
  66. data/lib/leftovers/matcher_builders/node_has_receiver.rb +6 -8
  67. data/lib/leftovers/matcher_builders/node_name.rb +3 -5
  68. data/lib/leftovers/matcher_builders/node_pair_key.rb +4 -4
  69. data/lib/leftovers/matcher_builders/node_pair_value.rb +4 -4
  70. data/lib/leftovers/matcher_builders/node_path.rb +3 -4
  71. data/lib/leftovers/matcher_builders/node_privacy.rb +3 -3
  72. data/lib/leftovers/matcher_builders/node_type.rb +18 -13
  73. data/lib/leftovers/matcher_builders/node_value.rb +18 -31
  74. data/lib/leftovers/matcher_builders/or.rb +10 -10
  75. data/lib/leftovers/matcher_builders/path.rb +3 -3
  76. data/lib/leftovers/matcher_builders/string_pattern.rb +2 -0
  77. data/lib/leftovers/matcher_builders/unless.rb +1 -3
  78. data/lib/leftovers/matcher_builders.rb +2 -22
  79. data/lib/leftovers/matchers/node_has_block.rb +13 -0
  80. data/lib/leftovers/matchers/node_scalar_value.rb +1 -1
  81. data/lib/leftovers/matchers.rb +2 -27
  82. data/lib/leftovers/merged_config.rb +16 -17
  83. data/lib/leftovers/parser.rb +1 -1
  84. data/lib/leftovers/precompile_error.rb +31 -0
  85. data/lib/leftovers/precompilers/haml.rb +23 -3
  86. data/lib/leftovers/precompilers/json.rb +1 -1
  87. data/lib/leftovers/precompilers/precompiler.rb +3 -3
  88. data/lib/leftovers/precompilers/slim.rb +1 -1
  89. data/lib/leftovers/precompilers/yaml/builder.rb +62 -0
  90. data/lib/leftovers/precompilers/yaml.rb +3 -56
  91. data/lib/leftovers/precompilers.rb +11 -16
  92. data/lib/leftovers/processor_builders/action.rb +15 -19
  93. data/lib/leftovers/processor_builders/add_prefix.rb +4 -6
  94. data/lib/leftovers/processor_builders/add_suffix.rb +4 -6
  95. data/lib/leftovers/processor_builders/argument.rb +10 -15
  96. data/lib/leftovers/processor_builders/dynamic.rb +12 -30
  97. data/lib/leftovers/processor_builders/each.rb +63 -76
  98. data/lib/leftovers/processor_builders/each_for_definition_set.rb +15 -0
  99. data/lib/leftovers/processor_builders/itself.rb +2 -4
  100. data/lib/leftovers/processor_builders/keyword.rb +4 -4
  101. data/lib/leftovers/processor_builders/keyword_argument.rb +4 -4
  102. data/lib/leftovers/processor_builders/receiver.rb +2 -4
  103. data/lib/leftovers/processor_builders/transform.rb +26 -49
  104. data/lib/leftovers/processor_builders/transform_chain.rb +4 -7
  105. data/lib/leftovers/processor_builders/transform_set.rb +6 -7
  106. data/lib/leftovers/processor_builders/value.rb +2 -2
  107. data/lib/leftovers/processor_builders.rb +2 -15
  108. data/lib/leftovers/processors/add_definition_node.rb +2 -2
  109. data/lib/leftovers/processors/camelize.rb +3 -3
  110. data/lib/leftovers/processors/deconstantize.rb +3 -3
  111. data/lib/leftovers/processors/demodulize.rb +3 -3
  112. data/lib/leftovers/processors/each_for_definition_set.rb +2 -2
  113. data/lib/leftovers/processors/eval.rb +1 -1
  114. data/lib/leftovers/processors/parameterize.rb +3 -3
  115. data/lib/leftovers/processors/placeholder.rb +1 -1
  116. data/lib/leftovers/processors/pluralize.rb +3 -3
  117. data/lib/leftovers/processors/set_default_privacy.rb +1 -1
  118. data/lib/leftovers/processors/set_privacy.rb +1 -1
  119. data/lib/leftovers/processors/singularize.rb +3 -3
  120. data/lib/leftovers/processors/titleize.rb +3 -3
  121. data/lib/leftovers/processors/underscore.rb +3 -3
  122. data/lib/leftovers/processors.rb +2 -44
  123. data/lib/leftovers/rake_task.rb +2 -2
  124. data/lib/leftovers/reporter.rb +44 -42
  125. data/lib/leftovers/runner.rb +40 -0
  126. data/lib/leftovers/todo_reporter.rb +96 -94
  127. data/lib/leftovers/unexpected_case.rb +8 -0
  128. data/lib/leftovers/version.rb +1 -1
  129. data/lib/leftovers.rb +23 -108
  130. metadata +15 -18
  131. 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: 7094671fa508c2a3af0cfdc0b64dfc41346c88a16a9203d901628fe40af66a86
4
+ data.tar.gz: 35ae640a73003aaf96a362ca08e3c92b51b46e93184b1c3641a5427a1dce31d4
5
5
  SHA512:
6
- metadata.gz: d51c93c652bdd0aa55a176c1600e9d557fd29e7e9726411d7ac6eb086178a655e17e96e8d7530c97945f169d32961649358dd712daf9e50cb82b30caa1b55c10
7
- data.tar.gz: b8ca04321b17c7d9c9b831f3fb2fab47554d859f910d38f08a04d41f344c4585a1008019af12d13b3e2807027fe6ba7d6fd6a4d1eca3fb947d68d6812249bc39
6
+ metadata.gz: 4da3eb08e61869a3d5a82c8a0ecdfb7217872299cee46d1ec7ac0234c892c10a0afa5ca3786e23939d893302cf83e2d91e4cb33939c02e4f6b856c51aef22cdc
7
+ data.tar.gz: 29f81218dfad69a62ea35032cc4149eff849a363067b67aa9175a568674e473e6a28f2b0eeb5d6de36246917efb911a527163aab45e7382ff0d915a843777b99
data/CHANGELOG.md CHANGED
@@ -1,3 +1,15 @@
1
+ # v0.12.0
2
+ - improve error handling when a file can't be processed
3
+ - fail rather than warn when encountering a syntax error in a file being processed
4
+
5
+ # v0.11.2
6
+
7
+ - add `has_block: true/false` for matching method calls with a block.
8
+ - 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.
9
+ - Fixed integration with Haml 6.x
10
+ - Noted the with_options limitation in readme
11
+ - Add more rspec config: `RSpec::Matchers.define`, `matcher {}`, `alias_matcher`
12
+
1
13
  # v0.11.1
2
14
  - Fixed an issue with parsing files that have `MyConstant ||= value` patterns #19 (thanks for the pr - @kamoh)
3
15
 
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,92 @@
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
- catch(:leftovers_exit) do
14
- Leftovers.reset
15
- parse_options
12
+ parse_options
16
13
 
17
- Leftovers.run(stdout: stdout, stderr: stderr)
18
- end
14
+ runner.run
15
+ rescue ::Leftovers::Error => e
16
+ Leftovers.warn("\e[31m#{e.class}: #{e.message}\e[0m\n\n#{e.backtrace.join("\n")}")
17
+ 1
18
+ rescue ::Leftovers::Exit => e
19
+ e.status # what why?
19
20
  end
20
21
 
21
22
  private
22
23
 
23
- attr_reader :argv, :stdout, :stderr
24
+ attr_reader :argv
24
25
 
25
- def parse_options # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
26
- opts = OptionParser.new
27
- Leftovers.parallel = true
28
- Leftovers.progress = true
26
+ def option_parser
27
+ @option_parser ||= ::OptionParser.new do |o|
28
+ o.banner = 'Usage: leftovers [options]'
29
29
 
30
- opts.banner = 'Usage: leftovers [options]'
31
-
32
- opts.on('--[no-]parallel', 'Run in parallel or not, default --parallel') do |p|
33
- Leftovers.parallel = p
30
+ o.on('--[no-]parallel', 'Run in parallel or not, default --parallel') { |p| parallel(p) }
31
+ o.on('--[no-]progress', 'Show live counts or not, default --progress') { |p| progress(p) }
32
+ o.on('--dry-run', 'Print a list of files that would be looked at') { dry_run }
33
+ o.on('--view-compiled', 'Print the compiled content of the files') { view_compiled }
34
+ o.on('--write-todo', 'Create a config file with the existing unused items') { write_todo }
35
+ o.on('-v', '--version', 'Print the current version') { print_version }
36
+ o.on('-h', '--help', 'Print this message') { print_help }
34
37
  end
38
+ end
35
39
 
36
- opts.on('--[no-]progress', 'Show progress counts or not, default --progress') do |p|
37
- Leftovers.progress = p
38
- end
40
+ def parse_options
41
+ option_parser.parse!(argv)
42
+ rescue ::OptionParser::ParseError => e
43
+ ::Leftovers.error("CLI Error: #{e.message}", option_parser.help)
44
+ end
39
45
 
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
46
+ def runner
47
+ @runner ||= Runner.new
48
+ end
44
49
 
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
50
+ def exit(status = 0)
51
+ ::Leftovers.exit status
52
+ end
50
53
 
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
54
+ def dry_run
55
+ FileList.new.each { |file| ::Leftovers.puts file.relative_path }
54
56
 
55
- opts.on('-v', '--version', 'Returns the current version') do
56
- stdout.puts(Leftovers::VERSION)
57
- Leftovers.exit
58
- end
57
+ exit
58
+ end
59
59
 
60
- opts.on('-h', '--help', 'Shows this message') do
61
- stdout.puts(opts.help)
62
- Leftovers.exit
60
+ def view_compiled
61
+ FileList.new(argv_rules: argv).each do |file|
62
+ ::Leftovers.puts "\e[0;2m#{file.relative_path}\e[0m\n#{file.ruby}"
63
63
  end
64
64
 
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
65
+ exit
66
+ end
67
+
68
+ def print_version
69
+ ::Leftovers.puts(VERSION)
70
+
71
+ exit
72
+ end
73
+
74
+ def print_help
75
+ ::Leftovers.puts(option_parser.help)
76
+
77
+ exit
78
+ end
79
+
80
+ def parallel(value)
81
+ runner.parallel = value
82
+ end
83
+
84
+ def progress(value)
85
+ runner.progress = value
86
+ end
87
+
88
+ def write_todo
89
+ runner.reporter = TodoReporter
71
90
  end
72
91
  end
73
92
  end