leftovers 0.4.3 → 0.5.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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/docs/Configuration.md +46 -11
  4. data/lib/.DS_Store +0 -0
  5. data/lib/config/actioncable.yml +4 -0
  6. data/lib/config/actionmailer.yml +22 -0
  7. data/lib/config/actionpack.yml +190 -0
  8. data/lib/config/actionview.yml +64 -0
  9. data/lib/config/activejob.yml +29 -0
  10. data/lib/config/activemodel.yml +74 -0
  11. data/lib/config/activerecord.yml +179 -0
  12. data/lib/config/activesupport.yml +99 -0
  13. data/lib/config/haml.yml +2 -0
  14. data/lib/config/rails.yml +11 -450
  15. data/lib/config/ruby.yml +6 -0
  16. data/lib/leftovers/ast/node.rb +14 -0
  17. data/lib/leftovers/config.rb +8 -0
  18. data/lib/leftovers/config_validator/schema_hash.rb +62 -29
  19. data/lib/leftovers/erb.rb +2 -2
  20. data/lib/leftovers/file.rb +2 -3
  21. data/lib/leftovers/matcher_builders/node.rb +2 -0
  22. data/lib/leftovers/matcher_builders/node_has_argument.rb +11 -7
  23. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +14 -10
  24. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +17 -13
  25. data/lib/leftovers/matcher_builders/node_has_receiver.rb +15 -0
  26. data/lib/leftovers/matcher_builders/node_type.rb +7 -6
  27. data/lib/leftovers/matcher_builders/node_value.rb +50 -0
  28. data/lib/leftovers/matcher_builders.rb +3 -2
  29. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +4 -1
  30. data/lib/leftovers/matchers/node_has_positional_argument.rb +0 -4
  31. data/lib/leftovers/matchers/node_has_receiver.rb +20 -0
  32. data/lib/leftovers/matchers/predicate.rb +19 -0
  33. data/lib/leftovers/matchers.rb +2 -0
  34. data/lib/leftovers/merged_config.rb +19 -1
  35. data/lib/leftovers/todo_reporter.rb +9 -6
  36. data/lib/leftovers/value_processors/camelize.rb +1 -1
  37. data/lib/leftovers/value_processors/deconstantize.rb +1 -1
  38. data/lib/leftovers/value_processors/demodulize.rb +1 -1
  39. data/lib/leftovers/value_processors/parameterize.rb +1 -1
  40. data/lib/leftovers/value_processors/pluralize.rb +1 -1
  41. data/lib/leftovers/value_processors/singularize.rb +1 -1
  42. data/lib/leftovers/value_processors/titleize.rb +1 -1
  43. data/lib/leftovers/value_processors/underscore.rb +1 -1
  44. data/lib/leftovers/version.rb +1 -1
  45. data/lib/leftovers.rb +95 -92
  46. metadata +16 -4
  47. data/lib/leftovers/matcher_builders/argument_node_value.rb +0 -21
@@ -36,8 +36,7 @@ module Leftovers
36
36
  {
37
37
  'type' => 'array',
38
38
  'items' => { '$ref' => '#/definitions/string' },
39
- 'minItems' => 1,
40
- 'uniqueItems' => true
39
+ 'minItems' => 1
41
40
  },
42
41
  { '$ref' => '#/definitions/string' }
43
42
  ]
@@ -65,8 +64,7 @@ module Leftovers
65
64
  {
66
65
  'type' => 'array',
67
66
  'items' => { '$ref' => '#/definitions/name' },
68
- 'minItems' => 1,
69
- 'uniqueItems' => true
67
+ 'minItems' => 1
70
68
  },
71
69
  { '$ref' => '#/definitions/name' }
72
70
  ]
@@ -84,14 +82,13 @@ module Leftovers
84
82
  {
85
83
  'type' => 'array',
86
84
  'items' => { '$ref' => '#/definitions/argumentPosition' },
87
- 'minItems' => 1,
88
- 'uniqueItems' => true
85
+ 'minItems' => 1
89
86
  }
90
87
  ]
91
88
  },
92
89
  'valueType' => {
93
90
  'type' => 'string',
94
- 'enum' => %w{String Symbol Integer Float}
91
+ 'enum' => %w{String Symbol Integer Float Array Hash Proc}
95
92
  },
96
93
  'valueTypeList' => {
97
94
  'anyOf' => [
@@ -99,8 +96,7 @@ module Leftovers
99
96
  {
100
97
  'type' => 'array',
101
98
  'items' => { '$ref' => '#/definitions/valueType' },
102
- 'minItems' => 1,
103
- 'uniqueItems' => true
99
+ 'minItems' => 1
104
100
  }
105
101
  ]
106
102
  },
@@ -110,7 +106,41 @@ module Leftovers
110
106
  { 'type' => 'integer' },
111
107
  { 'type' => 'number' },
112
108
  { 'type' => 'boolean' },
113
- { 'type' => 'null' }
109
+ { 'type' => 'null' },
110
+ { 'allOf' => [
111
+ { '$ref' => '#/definitions/stringPattern' },
112
+ {
113
+ 'type' => 'object',
114
+ 'properties' => {
115
+ 'match' => true, 'matches' => true,
116
+ 'has_prefix' => true, 'has_suffix' => true,
117
+ 'at' => { '$ref' => '#/definitions/argumentPositionList' },
118
+ 'has_value' => { '$ref' => '#/definitions/hasValueList' },
119
+ 'has_receiver' => { '$ref' => '#/definitions/hasValueList' },
120
+ 'type' => { '$ref' => '#/definitions/valueTypeList' },
121
+ 'unless' => { '$ref' => '#/definitions/hasValueList' }
122
+ },
123
+ 'minProperties' => 1,
124
+ 'additionalProperties' => false,
125
+ 'allOf' => [
126
+ # incompatible groups
127
+ { 'not' => { 'required' => %w{match at} } },
128
+ { 'not' => { 'required' => %w{match has_value} } },
129
+ { 'not' => { 'required' => %w{match type} } },
130
+ { 'not' => { 'required' => %w{matches at} } },
131
+ { 'not' => { 'required' => %w{matches has_value} } },
132
+ { 'not' => { 'required' => %w{matches type} } },
133
+ { 'not' => { 'required' => %w{has_prefix at} } },
134
+ { 'not' => { 'required' => %w{has_prefix has_value} } },
135
+ { 'not' => { 'required' => %w{has_prefix type} } },
136
+ { 'not' => { 'required' => %w{has_suffix at} } },
137
+ { 'not' => { 'required' => %w{has_suffix has_value} } },
138
+ { 'not' => { 'required' => %w{has_suffix type} } },
139
+ { 'not' => { 'required' => %w{at type} } },
140
+ { 'not' => { 'required' => %w{has_value type} } }
141
+ ]
142
+ }
143
+ ] }
114
144
  ]
115
145
  },
116
146
  'hasValueList' => {
@@ -119,8 +149,7 @@ module Leftovers
119
149
  {
120
150
  'type' => 'array',
121
151
  'items' => { '$ref' => '#/definitions/hasValue' },
122
- 'minItems' => 1,
123
- 'uniqueItems' => true
152
+ 'minItems' => 1
124
153
  }
125
154
  ]
126
155
  },
@@ -133,11 +162,14 @@ module Leftovers
133
162
  'properties' => {
134
163
  'at' => { '$ref' => '#/definitions/argumentPositionList' },
135
164
  'has_value' => { '$ref' => '#/definitions/hasValueList' },
136
- 'has_value_type' => { '$ref' => '#/definitions/valueTypeList' },
137
165
  'unless' => { '$ref' => '#/definitions/hasArgumentList' }
138
166
  },
139
167
  'minProperties' => 1,
140
- 'additionalProperties' => false
168
+ 'additionalProperties' => false,
169
+ 'allOf' => [
170
+ # synonyms
171
+ { 'not' => { 'required' => %w{has_argument has_arguments} } }
172
+ ]
141
173
  }
142
174
  ]
143
175
  },
@@ -147,8 +179,7 @@ module Leftovers
147
179
  {
148
180
  'type' => 'array',
149
181
  'items' => { '$ref' => '#/definitions/hasArgument' },
150
- 'minItems' => 1,
151
- 'uniqueItems' => true
182
+ 'minItems' => 1
152
183
  }
153
184
  ]
154
185
  },
@@ -160,7 +191,8 @@ module Leftovers
160
191
  'path' => { '$ref' => '#/definitions/stringList' },
161
192
  'paths' => { '$ref' => '#/definitions/stringList' },
162
193
  'has_argument' => { '$ref' => '#/definitions/hasArgumentList' },
163
- 'has_arguments' => { '$ref' => '#/definitions/hasArgumentList' }
194
+ 'has_arguments' => { '$ref' => '#/definitions/hasArgumentList' },
195
+ 'has_receiver' => { '$ref' => '#/definitions/hasValueList' }
164
196
  },
165
197
  'minProperties' => 1,
166
198
  'allOf' => [
@@ -260,8 +292,7 @@ module Leftovers
260
292
  {
261
293
  'type' => 'array',
262
294
  'items' => { '$ref' => '#/definitions/transform' },
263
- 'minItems' => 1,
264
- 'uniqueItems' => true
295
+ 'minItems' => 1
265
296
  }
266
297
  ]
267
298
  },
@@ -276,8 +307,7 @@ module Leftovers
276
307
  {
277
308
  'type' => 'array',
278
309
  'items' => { '$ref' => '#/definitions/keyword' },
279
- 'minItems' => 1,
280
- 'uniqueItems' => true
310
+ 'minItems' => 1
281
311
  }
282
312
  ]
283
313
  },
@@ -346,8 +376,7 @@ module Leftovers
346
376
  {
347
377
  'type' => 'array',
348
378
  'items' => { '$ref' => '#/definitions/action' },
349
- 'minItems' => 1,
350
- 'uniqueItems' => true
379
+ 'minItems' => 1
351
380
  }
352
381
  ]
353
382
  },
@@ -377,8 +406,7 @@ module Leftovers
377
406
  {
378
407
  'type' => 'array',
379
408
  'items' => { '$ref' => '#/definitions/ruleMatcher' },
380
- 'minItems' => 1,
381
- 'uniqueItems' => true
409
+ 'minItems' => 1
382
410
  },
383
411
  { '$ref' => '#/definitions/ruleMatcher' }
384
412
  ]
@@ -390,6 +418,7 @@ module Leftovers
390
418
  { 'required' => ['name'] }, { 'required' => ['names'] },
391
419
  { 'required' => ['path'] }, { 'required' => ['paths'] },
392
420
  { 'required' => ['has_argument'] }, { 'required' => ['has_arguments'] },
421
+ { 'required' => ['has_receiver'] },
393
422
  { 'required' => ['unless'] }
394
423
  ] },
395
424
  {
@@ -399,6 +428,7 @@ module Leftovers
399
428
  'name' => true, 'names' => true,
400
429
  'path' => true, 'paths' => true,
401
430
  'has_argument' => true, 'has_arguments' => true,
431
+ 'has_receiver' => true,
402
432
  'unless' => { '$ref' => '#/definitions/ruleMatcherList' }
403
433
 
404
434
  },
@@ -415,6 +445,7 @@ module Leftovers
415
445
  { 'required' => ['name'] }, { 'required' => ['names'] },
416
446
  { 'required' => ['path'] }, { 'required' => ['paths'] },
417
447
  { 'required' => ['has_argument'] }, { 'required' => ['has_arguments'] },
448
+ { 'required' => ['has_receiver'] },
418
449
  { 'required' => ['unless'] }
419
450
  ] },
420
451
  {
@@ -424,6 +455,7 @@ module Leftovers
424
455
  'name' => true, 'names' => true,
425
456
  'path' => true, 'paths' => true,
426
457
  'has_argument' => true, 'has_arguments' => true,
458
+ 'has_receiver' => true,
427
459
  'unless' => { '$ref' => '#/definitions/ruleMatcherList' },
428
460
 
429
461
  'call' => true, 'calls' => true,
@@ -439,8 +471,7 @@ module Leftovers
439
471
  {
440
472
  'type' => 'array',
441
473
  'items' => { '$ref' => '#/definitions/dynamic' },
442
- 'minItems' => 1,
443
- 'uniqueItems' => true
474
+ 'minItems' => 1
444
475
  },
445
476
  { '$ref' => '#/definitions/dynamic' }
446
477
  ]
@@ -460,6 +491,7 @@ module Leftovers
460
491
  'has_prefix' => true, 'has_suffix' => true, 'matches' => true,
461
492
  'path' => true, 'paths' => true,
462
493
  'has_argument' => true, 'has_arguments' => true,
494
+ 'has_receiver' => true,
463
495
  'unless' => { '$ref' => '#/definitions/keepTestOnlyList' }
464
496
  },
465
497
  'additionalProperties' => false,
@@ -474,8 +506,7 @@ module Leftovers
474
506
  {
475
507
  'type' => 'array',
476
508
  'items' => { '$ref' => '#/definitions/keepTestOnly' },
477
- 'minItems' => 1,
478
- 'uniqueItems' => true
509
+ 'minItems' => 1
479
510
  },
480
511
  { '$ref' => '#/definitions/keepTestOnly' }
481
512
  ]
@@ -485,6 +516,8 @@ module Leftovers
485
516
  'include_paths' => { '$ref' => '#/definitions/stringList' },
486
517
  'exclude_paths' => { '$ref' => '#/definitions/stringList' },
487
518
  'test_paths' => { '$ref' => '#/definitions/stringList' },
519
+ 'haml_paths' => { '$ref' => '#/definitions/stringList' },
520
+ 'erb_paths' => { '$ref' => '#/definitions/stringList' },
488
521
  'requires' => { '$ref' => '#/definitions/stringList' },
489
522
  'gems' => { '$ref' => '#/definitions/stringList' },
490
523
  'keep' => { '$ref' => '#/definitions/keepTestOnlyList' },
data/lib/leftovers/erb.rb CHANGED
@@ -10,11 +10,11 @@ module Leftovers
10
10
  end
11
11
 
12
12
  def add_insert_cmd(out, content) # leftovers:keep
13
- out.push("#{content}\n")
13
+ out.push("\n#{content}\n")
14
14
  end
15
15
 
16
16
  def add_put_cmd(out, _content) # leftovers:keep
17
- out
17
+ out.push("\n")
18
18
  end
19
19
  end
20
20
  end
@@ -15,10 +15,9 @@ module Leftovers
15
15
  end
16
16
 
17
17
  def ruby
18
- case extname
19
- when '.haml'
18
+ if Leftovers.config.haml_paths.allowed?(relative_path)
20
19
  ::Leftovers::Haml.precompile(read, self)
21
- when '.rhtml', '.rjs', '.erb'
20
+ elsif Leftovers.config.erb_paths.allowed?(relative_path)
22
21
  ::Leftovers::ERB.precompile(read)
23
22
  else
24
23
  read
@@ -21,6 +21,7 @@ module Leftovers
21
21
  names: nil, match: nil, has_prefix: nil, has_suffix: nil,
22
22
  paths: nil,
23
23
  has_arguments: nil,
24
+ has_receiver: nil,
24
25
  unless_arg: nil
25
26
  )
26
27
  ::Leftovers::MatcherBuilders::And.build([
@@ -30,6 +31,7 @@ module Leftovers
30
31
  ]),
31
32
  ::Leftovers::MatcherBuilders::NodePath.build(paths),
32
33
  ::Leftovers::MatcherBuilders::NodeHasArgument.build(has_arguments),
34
+ ::Leftovers::MatcherBuilders::NodeHasReceiver.build(has_receiver),
33
35
  ::Leftovers::MatcherBuilders::Unless.build(
34
36
  (::Leftovers::MatcherBuilders::Node.build(unless_arg) if unless_arg)
35
37
  )
@@ -26,6 +26,8 @@ module Leftovers
26
26
 
27
27
  ::Leftovers.each_or_self(at) do |k|
28
28
  case k
29
+ when '*'
30
+ positions << k
29
31
  when ::String, ::Hash
30
32
  keys << k
31
33
  when ::Integer
@@ -35,23 +37,25 @@ module Leftovers
35
37
  # :nocov:
36
38
  end
37
39
  end
40
+
38
41
  keys = nil if keys.empty?
39
42
  positions = nil if positions.empty?
40
43
 
41
44
  [keys, positions]
42
45
  end
43
46
 
44
- def self.build_from_hash(at: nil, has_value: nil, has_value_type: nil, unless_arg: nil) # rubocop:disable Metrics/MethodLength
47
+ def self.build_from_hash( # rubocop:disable Metrics/MethodLength
48
+ at: nil,
49
+ has_value: nil,
50
+ unless_arg: nil
51
+ )
45
52
  keys, positions = separate_argument_types(at)
46
53
 
47
- value_matcher = ::Leftovers::MatcherBuilders::And.build([
48
- ::Leftovers::MatcherBuilders::ArgumentNodeValue.build(has_value),
49
- ::Leftovers::MatcherBuilders::NodeType.build(has_value_type)
50
- ])
54
+ value_matcher = ::Leftovers::MatcherBuilders::NodeValue.build(has_value)
51
55
  matcher = if (keys && positions) || (!keys && !positions)
52
56
  ::Leftovers::MatcherBuilders::Or.build([
53
- ::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(keys, value_matcher),
54
- ::Leftovers::MatcherBuilders::NodeHasPositionalArgument.build(positions, value_matcher)
57
+ ::Leftovers::MatcherBuilders::NodeHasPositionalArgument.build(positions, value_matcher),
58
+ ::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(keys, value_matcher)
55
59
  ])
56
60
  elsif keys
57
61
  ::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(keys, value_matcher)
@@ -3,19 +3,23 @@
3
3
  module Leftovers
4
4
  module MatcherBuilders
5
5
  module NodeHasKeywordArgument
6
- def self.build(keywords, value_matcher)
7
- value_matcher = ::Leftovers::MatcherBuilders::NodePairValue.build(value_matcher)
8
- keyword_matcher = ::Leftovers::MatcherBuilders::NodePairName.build(keywords)
6
+ class << self
7
+ def build(keywords, value_matcher) # rubocop:disable Metrics/MethodLength
8
+ value_matcher = ::Leftovers::MatcherBuilders::NodePairValue.build(value_matcher)
9
+ keyword_matcher = if ::Leftovers.each_or_self(keywords).any? { |x| x == '**' }
10
+ ::Leftovers::Matchers::NodeType.new(:pair)
11
+ else
12
+ ::Leftovers::MatcherBuilders::NodePairName.build(keywords)
13
+ end
9
14
 
10
- pair_matcher = ::Leftovers::MatcherBuilders::And.build([
11
- keyword_matcher, value_matcher
12
- ])
13
- # :nocov:
14
- raise unless pair_matcher
15
+ pair_matcher = ::Leftovers::MatcherBuilders::And.build([
16
+ keyword_matcher, value_matcher
17
+ ])
15
18
 
16
- # :nocov:
19
+ return nil unless pair_matcher
17
20
 
18
- ::Leftovers::Matchers::NodeHasAnyKeywordArgument.new(pair_matcher)
21
+ ::Leftovers::Matchers::NodeHasAnyKeywordArgument.new(pair_matcher)
22
+ end
19
23
  end
20
24
  end
21
25
  end
@@ -3,20 +3,24 @@
3
3
  module Leftovers
4
4
  module MatcherBuilders
5
5
  module NodeHasPositionalArgument
6
- def self.build(positions, value_matcher) # rubocop:disable Metrics/MethodLength
7
- if positions && value_matcher
8
- ::Leftovers::MatcherBuilders::Or.each_or_self(positions) do |position|
9
- ::Leftovers::Matchers::NodeHasPositionalArgumentWithValue.new(position, value_matcher)
10
- end
11
- elsif positions
12
- position = positions.is_a?(Array) ? positions.min : positions
6
+ class << self
7
+ def build(positions, value_matcher) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/MethodLength
8
+ if positions && value_matcher
9
+ ::Leftovers::MatcherBuilders::Or.each_or_self(positions) do |pos|
10
+ if pos == '*'
11
+ ::Leftovers::Matchers::NodeHasAnyPositionalArgumentWithValue.new(value_matcher)
12
+ else
13
+ ::Leftovers::Matchers::NodeHasPositionalArgumentWithValue.new(pos, value_matcher)
14
+ end
15
+ end
16
+ elsif positions
17
+ pos = 0 if ::Leftovers.each_or_self(positions).any? { |x| x == '*' }
18
+ pos ||= ::Leftovers.each_or_self(positions).min
13
19
 
14
- ::Leftovers::Matchers::NodeHasPositionalArgument.new(position)
15
- elsif value_matcher
16
- ::Leftovers::Matchers::NodeHasAnyPositionalArgumentWithValue.new(value_matcher)
17
- # :nocov:
18
- else raise
19
- # :nocov:
20
+ ::Leftovers::Matchers::NodeHasPositionalArgument.new(pos)
21
+ elsif value_matcher
22
+ ::Leftovers::Matchers::NodeHasAnyPositionalArgumentWithValue.new(value_matcher)
23
+ end
20
24
  end
21
25
  end
22
26
  end
@@ -0,0 +1,15 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module NodeHasReceiver
6
+ class << self
7
+ def build(pattern)
8
+ matcher = ::Leftovers::MatcherBuilders::NodeValue.build(pattern)
9
+
10
+ ::Leftovers::Matchers::NodeHasReceiver.new(matcher) if matcher
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -5,18 +5,19 @@ require 'set'
5
5
  module Leftovers
6
6
  module MatcherBuilders
7
7
  module NodeType
8
- def self.build(types_pattern)
8
+ def self.build(types_pattern) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
9
9
  ::Leftovers::MatcherBuilders::Or.each_or_self(types_pattern) do |type|
10
10
  case type
11
11
  when 'Symbol' then ::Leftovers::Matchers::NodeType.new(:sym)
12
12
  when 'String' then ::Leftovers::Matchers::NodeType.new(:str)
13
13
  when 'Integer' then ::Leftovers::Matchers::NodeType.new(:int)
14
14
  when 'Float' then ::Leftovers::Matchers::NodeType.new(:float)
15
- # these would be neat but i can't think of a use-case
16
- # when 'Array' then :array
17
- # when 'Hash' then :hash
18
- # when 'Method' then Set[:send, :csend, :def]
19
- # when 'Constant' then Set[:const, :class, :module]
15
+ when 'Array' then ::Leftovers::Matchers::NodeType.new(:array)
16
+ when 'Hash' then ::Leftovers::Matchers::NodeType.new(:hash)
17
+
18
+ when 'Proc' then ::Leftovers::Matchers::Predicate.new(:proc?)
19
+ # when 'Method' then ::Leftovers::Matchers::NodeType.new(Set[:send, :csend, :def])
20
+ # when 'Constant' then ::Leftovers::Matchers::NodeType.new(Set[:const, :class, :module])
20
21
  # :nocov:
21
22
  else raise
22
23
  # :nocov:
@@ -0,0 +1,50 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module NodeValue
6
+ class << self
7
+ def build(pattern) # rubocop:disable Metrics/MethodLength
8
+ ::Leftovers::MatcherBuilders::Or.each_or_self(pattern) do |pat|
9
+ case pat
10
+ when ::Integer, true, false, nil
11
+ ::Leftovers::Matchers::NodeScalarValue.new(pat)
12
+ when ::String
13
+ ::Leftovers::MatcherBuilders::NodeName.build(pat)
14
+ when ::Hash
15
+ build_from_hash(**pat)
16
+ # :nocov:
17
+ else raise
18
+ # :nocov:
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def build_from_hash( # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
26
+ at: nil, has_value: nil,
27
+ match: nil, has_prefix: nil, has_suffix: nil,
28
+ type: nil,
29
+ has_receiver: nil,
30
+ unless_arg: nil
31
+ )
32
+ matcher = ::Leftovers::MatcherBuilders::And.build([
33
+ ::Leftovers::MatcherBuilders::NodeHasArgument.build(
34
+ at: at, has_value: has_value
35
+ ),
36
+ ::Leftovers::MatcherBuilders::NodeName.build(
37
+ match: match, has_prefix: has_prefix, has_suffix: has_suffix
38
+ ),
39
+ ::Leftovers::MatcherBuilders::NodeType.build(type),
40
+ ::Leftovers::MatcherBuilders::NodeHasReceiver.build(has_receiver)
41
+ ])
42
+
43
+ ::Leftovers::MatcherBuilders::AndNot.build(
44
+ matcher, ::Leftovers::MatcherBuilders::NodeValue.build(unless_arg)
45
+ )
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -4,17 +4,18 @@ module Leftovers
4
4
  module MatcherBuilders
5
5
  autoload(:AndNot, "#{__dir__}/matcher_builders/and_not")
6
6
  autoload(:And, "#{__dir__}/matcher_builders/and")
7
- autoload(:ArgumentNodeValue, "#{__dir__}/matcher_builders/argument_node_value")
8
7
  autoload(:Name, "#{__dir__}/matcher_builders/name")
8
+ autoload(:Node, "#{__dir__}/matcher_builders/node")
9
9
  autoload(:NodeHasArgument, "#{__dir__}/matcher_builders/node_has_argument")
10
10
  autoload(:NodeHasKeywordArgument, "#{__dir__}/matcher_builders/node_has_keyword_argument")
11
11
  autoload(:NodeHasPositionalArgument, "#{__dir__}/matcher_builders/node_has_positional_argument")
12
+ autoload(:NodeHasReceiver, "#{__dir__}/matcher_builders/node_has_receiver")
12
13
  autoload(:NodeName, "#{__dir__}/matcher_builders/node_name")
13
14
  autoload(:NodePairName, "#{__dir__}/matcher_builders/node_pair_name")
14
15
  autoload(:NodePairValue, "#{__dir__}/matcher_builders/node_pair_value")
15
16
  autoload(:NodePath, "#{__dir__}/matcher_builders/node_path")
16
17
  autoload(:NodeType, "#{__dir__}/matcher_builders/node_type")
17
- autoload(:Node, "#{__dir__}/matcher_builders/node")
18
+ autoload(:NodeValue, "#{__dir__}/matcher_builders/node_value")
18
19
  autoload(:Or, "#{__dir__}/matcher_builders/or")
19
20
  autoload(:Path, "#{__dir__}/matcher_builders/path")
20
21
  autoload(:StringPattern, "#{__dir__}/matcher_builders/string_pattern")
@@ -14,7 +14,10 @@ module Leftovers
14
14
  end
15
15
 
16
16
  def ===(node)
17
- node.positional_arguments.any? do |value|
17
+ args = node.positional_arguments
18
+ return false unless args
19
+
20
+ args.any? do |value|
18
21
  @matcher === value
19
22
  end
20
23
  end
@@ -3,10 +3,6 @@
3
3
  module Leftovers
4
4
  module Matchers
5
5
  class NodeHasPositionalArgument
6
- # :nocov:
7
- using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
- # :nocov:
9
-
10
6
  def initialize(position)
11
7
  @position = position
12
8
 
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module Matchers
5
+ class NodeHasReceiver
6
+ def initialize(matcher)
7
+ @matcher = matcher
8
+
9
+ freeze
10
+ end
11
+
12
+ def ===(node)
13
+ receiver = node.receiver
14
+ @matcher === receiver if receiver
15
+ end
16
+
17
+ freeze
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module Matchers
5
+ class Predicate
6
+ def initialize(predicate)
7
+ @predicate = predicate
8
+
9
+ freeze
10
+ end
11
+
12
+ def ===(node)
13
+ node.send(@predicate)
14
+ end
15
+
16
+ freeze
17
+ end
18
+ end
19
+ end
@@ -15,6 +15,7 @@ module Leftovers
15
15
  "#{__dir__}/matchers/node_has_positional_argument_with_value"
16
16
  )
17
17
  autoload(:NodeHasPositionalArgument, "#{__dir__}/matchers/node_has_positional_argument")
18
+ autoload(:NodeHasReceiver, "#{__dir__}/matchers/node_has_receiver")
18
19
  autoload(:NodeName, "#{__dir__}/matchers/node_name")
19
20
  autoload(:NodePairValue, "#{__dir__}/matchers/node_pair_value")
20
21
  autoload(:NodePath, "#{__dir__}/matchers/node_path")
@@ -22,5 +23,6 @@ module Leftovers
22
23
  autoload(:NodeType, "#{__dir__}/matchers/node_type")
23
24
  autoload(:Not, "#{__dir__}/matchers/not")
24
25
  autoload(:Or, "#{__dir__}/matchers/or")
26
+ autoload(:Predicate, "#{__dir__}/matchers/predicate")
25
27
  end
26
28
  end
@@ -37,10 +37,12 @@ module Leftovers
37
37
  Leftovers::Config.new(:'.leftovers_todo.yml', path: Leftovers.pwd + '.leftovers_todo.yml')
38
38
  end
39
39
 
40
- def unmemoize
40
+ def unmemoize # rubocop:disable Metrics/CyclomaticComplexity
41
41
  remove_instance_variable(:@exclude_paths) if defined?(@exclude_paths)
42
42
  remove_instance_variable(:@include_paths) if defined?(@include_paths)
43
43
  remove_instance_variable(:@test_paths) if defined?(@test_paths)
44
+ remove_instance_variable(:@haml_paths) if defined?(@haml_paths)
45
+ remove_instance_variable(:@erb_paths) if defined?(@erb_paths)
44
46
  remove_instance_variable(:@dynamic) if defined?(@dynamic)
45
47
  remove_instance_variable(:@keep) if defined?(@keep)
46
48
  end
@@ -61,6 +63,22 @@ module Leftovers
61
63
  )
62
64
  end
63
65
 
66
+ def haml_paths
67
+ @haml_paths ||= FastIgnore.new(
68
+ include_rules: @configs.flat_map(&:haml_paths),
69
+ gitignore: false,
70
+ root: Leftovers.pwd
71
+ )
72
+ end
73
+
74
+ def erb_paths
75
+ @erb_paths ||= FastIgnore.new(
76
+ include_rules: @configs.flat_map(&:erb_paths),
77
+ gitignore: false,
78
+ root: Leftovers.pwd
79
+ )
80
+ end
81
+
64
82
  def dynamic
65
83
  @dynamic ||= ::Leftovers::ProcessorBuilders::EachDynamic.build(@configs.map(&:dynamic))
66
84
  end