leftovers 0.4.3 → 0.5.3

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