leftovers 0.5.2 → 0.6.0

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 (63) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +17 -0
  3. data/README.md +23 -3
  4. data/docs/Configuration.md +119 -2
  5. data/leftovers.gemspec +8 -4
  6. data/lib/.DS_Store +0 -0
  7. data/lib/config/actionpack.yml +11 -0
  8. data/lib/config/activesupport.yml +1 -0
  9. data/lib/config/ruby.yml +10 -0
  10. data/lib/config/slim.yml +4 -0
  11. data/lib/leftovers/collector.rb +3 -1
  12. data/lib/leftovers/config.rb +12 -4
  13. data/lib/leftovers/config_validator/schema_hash.rb +171 -149
  14. data/lib/leftovers/config_validator.rb +1 -0
  15. data/lib/leftovers/definition.rb +1 -1
  16. data/lib/leftovers/dynamic_processors/call.rb +0 -4
  17. data/lib/leftovers/dynamic_processors/call_definition.rb +0 -4
  18. data/lib/leftovers/dynamic_processors/definition.rb +0 -4
  19. data/lib/leftovers/erb.rb +1 -1
  20. data/lib/leftovers/file.rb +53 -5
  21. data/lib/leftovers/file_collector.rb +33 -2
  22. data/lib/leftovers/json.rb +28 -0
  23. data/lib/leftovers/matcher_builders/document.rb +13 -0
  24. data/lib/leftovers/matcher_builders/node.rb +3 -1
  25. data/lib/leftovers/matcher_builders/node_has_argument.rb +3 -4
  26. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +1 -1
  27. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +1 -1
  28. data/lib/leftovers/matcher_builders.rb +1 -0
  29. data/lib/leftovers/matchers/all.rb +0 -4
  30. data/lib/leftovers/matchers/and.rb +0 -4
  31. data/lib/leftovers/matchers/any.rb +0 -4
  32. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +1 -7
  33. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +1 -7
  34. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +0 -4
  35. data/lib/leftovers/matchers/node_name.rb +0 -4
  36. data/lib/leftovers/matchers/node_pair_value.rb +0 -4
  37. data/lib/leftovers/matchers/node_path.rb +0 -4
  38. data/lib/leftovers/matchers/node_scalar_value.rb +0 -4
  39. data/lib/leftovers/matchers/node_type.rb +0 -4
  40. data/lib/leftovers/matchers/not.rb +0 -4
  41. data/lib/leftovers/matchers/or.rb +0 -4
  42. data/lib/leftovers/merged_config.rb +43 -9
  43. data/lib/leftovers/processor_builders/dynamic.rb +2 -1
  44. data/lib/leftovers/slim.rb +21 -0
  45. data/lib/leftovers/todo_reporter.rb +10 -35
  46. data/lib/leftovers/value_processors/camelize.rb +1 -1
  47. data/lib/leftovers/value_processors/deconstantize.rb +1 -1
  48. data/lib/leftovers/value_processors/delete_prefix.rb +0 -6
  49. data/lib/leftovers/value_processors/delete_suffix.rb +0 -6
  50. data/lib/leftovers/value_processors/demodulize.rb +1 -1
  51. data/lib/leftovers/value_processors/keyword.rb +0 -4
  52. data/lib/leftovers/value_processors/keyword_argument.rb +0 -4
  53. data/lib/leftovers/value_processors/parameterize.rb +1 -1
  54. data/lib/leftovers/value_processors/pluralize.rb +1 -1
  55. data/lib/leftovers/value_processors/return_definition.rb +0 -4
  56. data/lib/leftovers/value_processors/singularize.rb +1 -1
  57. data/lib/leftovers/value_processors/titleize.rb +1 -1
  58. data/lib/leftovers/value_processors/underscore.rb +1 -1
  59. data/lib/leftovers/version.rb +1 -1
  60. data/lib/leftovers/yaml.rb +73 -0
  61. data/lib/leftovers.rb +8 -8
  62. metadata +51 -18
  63. data/lib/leftovers/backports.rb +0 -40
@@ -44,19 +44,21 @@ module Leftovers
44
44
  'name' => {
45
45
  'anyOf' => [
46
46
  { '$ref' => '#/definitions/string' },
47
- { 'allOf' => [
48
- { '$ref' => '#/definitions/stringPattern' },
49
- {
50
- 'type' => 'object',
51
- 'properties' => {
52
- 'match' => true, 'matches' => true,
53
- 'has_prefix' => true, 'has_suffix' => true,
54
- 'unless' => { '$ref' => '#/definitions/nameList' }
55
- },
56
- 'minProperties' => 1,
57
- 'additionalProperties' => false
58
- }
59
- ] }
47
+ {
48
+ 'allOf' => [
49
+ { '$ref' => '#/definitions/stringPattern' },
50
+ {
51
+ 'type' => 'object',
52
+ 'properties' => {
53
+ 'match' => true, 'matches' => true,
54
+ 'has_prefix' => true, 'has_suffix' => true,
55
+ 'unless' => { '$ref' => '#/definitions/nameList' }
56
+ },
57
+ 'minProperties' => 1,
58
+ 'additionalProperties' => false
59
+ }
60
+ ]
61
+ }
60
62
  ]
61
63
  },
62
64
  'nameList' => {
@@ -107,40 +109,42 @@ module Leftovers
107
109
  { 'type' => 'number' },
108
110
  { 'type' => 'boolean' },
109
111
  { '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
- ] }
112
+ {
113
+ 'allOf' => [
114
+ { '$ref' => '#/definitions/stringPattern' },
115
+ {
116
+ 'type' => 'object',
117
+ 'properties' => {
118
+ 'match' => true, 'matches' => true,
119
+ 'has_prefix' => true, 'has_suffix' => true,
120
+ 'at' => { '$ref' => '#/definitions/argumentPositionList' },
121
+ 'has_value' => { '$ref' => '#/definitions/hasValueList' },
122
+ 'has_receiver' => { '$ref' => '#/definitions/hasValueList' },
123
+ 'type' => { '$ref' => '#/definitions/valueTypeList' },
124
+ 'unless' => { '$ref' => '#/definitions/hasValueList' }
125
+ },
126
+ 'minProperties' => 1,
127
+ 'additionalProperties' => false,
128
+ 'allOf' => [
129
+ # incompatible groups
130
+ { 'not' => { 'required' => %w{match at} } },
131
+ { 'not' => { 'required' => %w{match has_value} } },
132
+ { 'not' => { 'required' => %w{match type} } },
133
+ { 'not' => { 'required' => %w{matches at} } },
134
+ { 'not' => { 'required' => %w{matches has_value} } },
135
+ { 'not' => { 'required' => %w{matches type} } },
136
+ { 'not' => { 'required' => %w{has_prefix at} } },
137
+ { 'not' => { 'required' => %w{has_prefix has_value} } },
138
+ { 'not' => { 'required' => %w{has_prefix type} } },
139
+ { 'not' => { 'required' => %w{has_suffix at} } },
140
+ { 'not' => { 'required' => %w{has_suffix has_value} } },
141
+ { 'not' => { 'required' => %w{has_suffix type} } },
142
+ { 'not' => { 'required' => %w{at type} } },
143
+ { 'not' => { 'required' => %w{has_value type} } }
144
+ ]
145
+ }
146
+ ]
147
+ }
144
148
  ]
145
149
  },
146
150
  'hasValueList' => {
@@ -187,6 +191,7 @@ module Leftovers
187
191
  'type' => 'object',
188
192
  'properties' => {
189
193
  'name' => { '$ref' => '#/definitions/nameList' },
194
+ 'document' => { '$ref' => '#/definitions/true' },
190
195
  'names' => { '$ref' => '#/definitions/nameList' },
191
196
  'path' => { '$ref' => '#/definitions/stringList' },
192
197
  'paths' => { '$ref' => '#/definitions/stringList' },
@@ -253,37 +258,39 @@ module Leftovers
253
258
  swapcase
254
259
  }
255
260
  },
256
- { 'allOf' => [
257
- { '$ref' => '#/definitions/transformProperties' },
258
- {
259
- 'type' => 'object',
260
- 'properties' => {
261
- 'original' => true,
262
- 'pluralize' => true,
263
- 'singularize' => true,
264
- 'camelize' => true,
265
- 'camelcase' => true,
266
- 'underscore' => true,
267
- 'titleize' => true,
268
- 'titlecase' => true,
269
- 'demodulize' => true,
270
- 'deconstantize' => true,
271
- 'parameterize' => true,
272
- 'downcase' => true,
273
- 'upcase' => true,
274
- 'capitalize' => true,
275
- 'swapcase' => true,
276
- 'add_prefix' => true,
277
- 'add_suffix' => true,
278
- 'split' => true,
279
- 'delete_prefix' => true,
280
- 'delete_suffix' => true,
281
- 'delete_before' => true,
282
- 'delete_after' => true
283
- },
284
- 'additionalProperties' => false
285
- }
286
- ] }
261
+ {
262
+ 'allOf' => [
263
+ { '$ref' => '#/definitions/transformProperties' },
264
+ {
265
+ 'type' => 'object',
266
+ 'properties' => {
267
+ 'original' => true,
268
+ 'pluralize' => true,
269
+ 'singularize' => true,
270
+ 'camelize' => true,
271
+ 'camelcase' => true,
272
+ 'underscore' => true,
273
+ 'titleize' => true,
274
+ 'titlecase' => true,
275
+ 'demodulize' => true,
276
+ 'deconstantize' => true,
277
+ 'parameterize' => true,
278
+ 'downcase' => true,
279
+ 'upcase' => true,
280
+ 'capitalize' => true,
281
+ 'swapcase' => true,
282
+ 'add_prefix' => true,
283
+ 'add_suffix' => true,
284
+ 'split' => true,
285
+ 'delete_prefix' => true,
286
+ 'delete_suffix' => true,
287
+ 'delete_before' => true,
288
+ 'delete_after' => true
289
+ },
290
+ 'additionalProperties' => false
291
+ }
292
+ ]
293
+ }
287
294
  ]
288
295
  },
289
296
  'transformList' => {
@@ -315,59 +322,63 @@ module Leftovers
315
322
  'anyOf' => [
316
323
  { '$ref' => '#/definitions/string' },
317
324
  { 'type' => 'integer', 'minimum' => 0 },
318
- { 'allOf' => [
319
- { '$ref' => '#/definitions/transformProperties' },
320
- {
321
- 'type' => 'object',
322
- 'properties' => {
323
- 'argument' => { '$ref' => '#/definitions/argumentPositionList' },
324
- 'arguments' => { '$ref' => '#/definitions/argumentPositionList' },
325
- 'keyword' => { '$ref' => '#/definitions/keywordList' },
326
- 'keywords' => { '$ref' => '#/definitions/keywordList' },
327
- 'itself' => { '$ref' => '#/definitions/true' },
328
- 'value' => { '$ref' => '#/definitions/string' },
329
- 'nested' => { '$ref' => '#/definitions/actionList' },
330
- 'recursive' => { '$ref' => '#/definitions/true' },
331
- 'transforms' => { '$ref' => '#/definitions/transformList' },
332
- 'pluralize' => true,
333
- 'singularize' => true,
334
- 'camelize' => true,
335
- 'camelcase' => true,
336
- 'underscore' => true,
337
- 'titleize' => true,
338
- 'titlecase' => true,
339
- 'demodulize' => true,
340
- 'deconstantize' => true,
341
- 'parameterize' => true,
342
- 'downcase' => true,
343
- 'upcase' => true,
344
- 'capitalize' => true,
345
- 'swapcase' => true,
346
- 'add_prefix' => true,
347
- 'add_suffix' => true,
348
- 'split' => true,
349
- 'delete_prefix' => true,
350
- 'delete_suffix' => true,
351
- 'delete_before' => true,
352
- 'delete_after' => true
353
- },
354
- 'additionalProperties' => false,
355
- 'allOf' => [
356
- # synonyms
357
- { 'not' => { 'required' => %w{keyword keywords} } },
358
- { 'not' => { 'required' => %w{argument arguments} } },
359
- # any of
360
- { 'anyOf' => [
361
- { 'required' => ['argument'] },
362
- { 'required' => ['arguments'] },
363
- { 'required' => ['keyword'] },
364
- { 'required' => ['keywords'] },
365
- { 'required' => ['itself'] },
366
- { 'required' => ['value'] }
367
- ] }
368
- ]
369
- }
370
- ] }
325
+ {
326
+ 'allOf' => [
327
+ { '$ref' => '#/definitions/transformProperties' },
328
+ {
329
+ 'type' => 'object',
330
+ 'properties' => {
331
+ 'argument' => { '$ref' => '#/definitions/argumentPositionList' },
332
+ 'arguments' => { '$ref' => '#/definitions/argumentPositionList' },
333
+ 'keyword' => { '$ref' => '#/definitions/keywordList' },
334
+ 'keywords' => { '$ref' => '#/definitions/keywordList' },
335
+ 'itself' => { '$ref' => '#/definitions/true' },
336
+ 'value' => { '$ref' => '#/definitions/string' },
337
+ 'nested' => { '$ref' => '#/definitions/actionList' },
338
+ 'recursive' => { '$ref' => '#/definitions/true' },
339
+ 'transforms' => { '$ref' => '#/definitions/transformList' },
340
+ 'pluralize' => true,
341
+ 'singularize' => true,
342
+ 'camelize' => true,
343
+ 'camelcase' => true,
344
+ 'underscore' => true,
345
+ 'titleize' => true,
346
+ 'titlecase' => true,
347
+ 'demodulize' => true,
348
+ 'deconstantize' => true,
349
+ 'parameterize' => true,
350
+ 'downcase' => true,
351
+ 'upcase' => true,
352
+ 'capitalize' => true,
353
+ 'swapcase' => true,
354
+ 'add_prefix' => true,
355
+ 'add_suffix' => true,
356
+ 'split' => true,
357
+ 'delete_prefix' => true,
358
+ 'delete_suffix' => true,
359
+ 'delete_before' => true,
360
+ 'delete_after' => true
361
+ },
362
+ 'additionalProperties' => false,
363
+ 'allOf' => [
364
+ # synonyms
365
+ { 'not' => { 'required' => %w{keyword keywords} } },
366
+ { 'not' => { 'required' => %w{argument arguments} } },
367
+ # any of
368
+ {
369
+ 'anyOf' => [
370
+ { 'required' => ['argument'] },
371
+ { 'required' => ['arguments'] },
372
+ { 'required' => ['keyword'] },
373
+ { 'required' => ['keywords'] },
374
+ { 'required' => ['itself'] },
375
+ { 'required' => ['value'] }
376
+ ]
377
+ }
378
+ ]
379
+ }
380
+ ]
381
+ }
371
382
  ]
372
383
  },
373
384
  'actionList' => {
@@ -395,10 +406,12 @@ module Leftovers
395
406
  { 'not' => { 'required' => %w{call calls} } },
396
407
  { 'not' => { 'required' => %w{define defines} } },
397
408
  # At least one of
398
- { 'anyOf' => [
399
- { 'required' => ['call'] }, { 'required' => ['calls'] },
400
- { 'required' => ['define'] }, { 'required' => ['defines'] }
401
- ] }
409
+ {
410
+ 'anyOf' => [
411
+ { 'required' => ['call'] }, { 'required' => ['calls'] },
412
+ { 'required' => ['define'] }, { 'required' => ['defines'] }
413
+ ]
414
+ }
402
415
  ]
403
416
  },
404
417
  'ruleMatcherList' => {
@@ -414,13 +427,15 @@ module Leftovers
414
427
  'ruleMatcher' => {
415
428
  'allOf' => [
416
429
  { '$ref' => '#/definitions/rulePattern' },
417
- { 'anyOf' => [
418
- { 'required' => ['name'] }, { 'required' => ['names'] },
419
- { 'required' => ['path'] }, { 'required' => ['paths'] },
420
- { 'required' => ['has_argument'] }, { 'required' => ['has_arguments'] },
421
- { 'required' => ['has_receiver'] },
422
- { 'required' => ['unless'] }
423
- ] },
430
+ {
431
+ 'anyOf' => [
432
+ { 'required' => ['name'] }, { 'required' => ['names'] },
433
+ { 'required' => ['path'] }, { 'required' => ['paths'] },
434
+ { 'required' => ['has_argument'] }, { 'required' => ['has_arguments'] },
435
+ { 'required' => ['has_receiver'] },
436
+ { 'required' => ['unless'] }
437
+ ]
438
+ },
424
439
  {
425
440
  'type' => 'object',
426
441
  'properties' => {
@@ -441,19 +456,23 @@ module Leftovers
441
456
  'allOf' => [
442
457
  { '$ref' => '#/definitions/rulePattern' },
443
458
  { '$ref' => '#/definitions/dynamicAction' },
444
- { 'anyOf' => [
445
- { 'required' => ['name'] }, { 'required' => ['names'] },
446
- { 'required' => ['path'] }, { 'required' => ['paths'] },
447
- { 'required' => ['has_argument'] }, { 'required' => ['has_arguments'] },
448
- { 'required' => ['has_receiver'] },
449
- { 'required' => ['unless'] }
450
- ] },
459
+ {
460
+ 'anyOf' => [
461
+ { 'required' => ['name'] }, { 'required' => ['names'] },
462
+ { 'required' => ['document'] },
463
+ { 'required' => ['path'] }, { 'required' => ['paths'] },
464
+ { 'required' => ['has_argument'] }, { 'required' => ['has_arguments'] },
465
+ { 'required' => ['has_receiver'] },
466
+ { 'required' => ['unless'] }
467
+ ]
468
+ },
451
469
  {
452
470
  'type' => 'object',
453
471
  'properties' => {
454
472
  # unfortunately this repetition is necessary to use additionalProperties: false
455
473
  'name' => true, 'names' => true,
456
474
  'path' => true, 'paths' => true,
475
+ 'document' => true,
457
476
  'has_argument' => true, 'has_arguments' => true,
458
477
  'has_receiver' => true,
459
478
  'unless' => { '$ref' => '#/definitions/ruleMatcherList' },
@@ -517,6 +536,9 @@ module Leftovers
517
536
  'exclude_paths' => { '$ref' => '#/definitions/stringList' },
518
537
  'test_paths' => { '$ref' => '#/definitions/stringList' },
519
538
  'haml_paths' => { '$ref' => '#/definitions/stringList' },
539
+ 'slim_paths' => { '$ref' => '#/definitions/stringList' },
540
+ 'yaml_paths' => { '$ref' => '#/definitions/stringList' },
541
+ 'json_paths' => { '$ref' => '#/definitions/stringList' },
520
542
  'erb_paths' => { '$ref' => '#/definitions/stringList' },
521
543
  'requires' => { '$ref' => '#/definitions/stringList' },
522
544
  'gems' => { '$ref' => '#/definitions/stringList' },
@@ -1,5 +1,6 @@
1
1
  # frozen-string-literal: true
2
2
 
3
+ require 'set'
3
4
  require 'json_schemer'
4
5
 
5
6
  module Leftovers
@@ -10,7 +10,7 @@ module Leftovers
10
10
  def initialize(
11
11
  name,
12
12
  location: method_node.loc.expression,
13
- test: method_node.test_line?
13
+ test: method_node.test_line? || ::Leftovers.config.test_only === method_node
14
14
  )
15
15
  @name = name
16
16
  @path = location.source_buffer.name.to_s
@@ -3,10 +3,6 @@
3
3
  module Leftovers
4
4
  module DynamicProcessors
5
5
  class Call
6
- # :nocov:
7
- using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
- # :nocov:
9
-
10
6
  def initialize(matcher, processor)
11
7
  @matcher = matcher
12
8
  @processor = processor
@@ -3,10 +3,6 @@
3
3
  module Leftovers
4
4
  module DynamicProcessors
5
5
  class CallDefinition
6
- # :nocov:
7
- using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
- # :nocov:
9
-
10
6
  def initialize(matcher, call_processor, definition_processor)
11
7
  @matcher = matcher
12
8
  @call_processor = call_processor
@@ -3,10 +3,6 @@
3
3
  module Leftovers
4
4
  module DynamicProcessors
5
5
  class Definition
6
- # :nocov:
7
- using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
- # :nocov:
9
-
10
6
  def initialize(matcher, processor)
11
7
  @matcher = matcher
12
8
  @processor = processor
data/lib/leftovers/erb.rb CHANGED
@@ -4,7 +4,7 @@ require 'erb'
4
4
 
5
5
  module Leftovers
6
6
  class ERB < ::ERB::Compiler
7
- def self.precompile(erb)
7
+ def self.precompile(erb, _name)
8
8
  @compiler ||= new('-')
9
9
  @compiler.compile(erb).first
10
10
  end
@@ -14,14 +14,62 @@ module Leftovers
14
14
  @test = Leftovers.config.test_paths.allowed?(relative_path)
15
15
  end
16
16
 
17
- def ruby
18
- if Leftovers.config.haml_paths.allowed?(relative_path)
19
- ::Leftovers::Haml.precompile(read, self)
20
- elsif Leftovers.config.erb_paths.allowed?(relative_path)
21
- ::Leftovers::ERB.precompile(read)
17
+ def ruby # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
18
+ precompiled = []
19
+ precompile = false
20
+
21
+ if haml?
22
+ precompiled << ::Leftovers::Haml.precompile(read, self)
23
+ precompile = true
24
+ end
25
+
26
+ if json?
27
+ precompiled << ::Leftovers::JSON.precompile(read, self)
28
+ precompile = true
29
+ end
30
+
31
+ if erb?
32
+ precompiled << ::Leftovers::ERB.precompile(read, self)
33
+ precompile = true
34
+ end
35
+
36
+ if slim?
37
+ precompiled << ::Leftovers::Slim.precompile(read, self)
38
+ precompile = true
39
+ end
40
+
41
+ if yaml?
42
+ precompiled << ::Leftovers::YAML.precompile(read, self)
43
+ precompile = true
44
+ end
45
+
46
+ if precompile
47
+ precompiled.join("\n")
22
48
  else
23
49
  read
24
50
  end
25
51
  end
52
+
53
+ private
54
+
55
+ def erb?
56
+ Leftovers.config.erb_paths.allowed?(relative_path)
57
+ end
58
+
59
+ def haml?
60
+ Leftovers.config.haml_paths.allowed?(relative_path)
61
+ end
62
+
63
+ def yaml?
64
+ Leftovers.config.yaml_paths.allowed?(relative_path)
65
+ end
66
+
67
+ def json?
68
+ Leftovers.config.json_paths.allowed?(relative_path)
69
+ end
70
+
71
+ def slim?
72
+ Leftovers.config.slim_paths.allowed?(relative_path)
73
+ end
26
74
  end
27
75
  end
@@ -12,6 +12,7 @@ module Leftovers
12
12
  @definitions = []
13
13
  @allow_lines = Set.new.compare_by_identity
14
14
  @test_lines = Set.new.compare_by_identity
15
+ @dynamic_lines = {}
15
16
  @ruby = ruby
16
17
  @file = file
17
18
  end
@@ -58,14 +59,18 @@ module Leftovers
58
59
  LEFTOVERS_CALL_RE = /\bleftovers:call(?:s|ed|er|ers|) (#{NAME_RE}(?:[, :]+#{NAME_RE})*)/.freeze
59
60
  LEFTOVERS_ALLOW_RE = /\bleftovers:(?:keeps?|skip(?:s|ped|)|allow(?:s|ed|))\b/.freeze
60
61
  LEFTOVERS_TEST_RE = /\bleftovers:(?:for_tests?|tests?|testing|test_only)\b/.freeze
62
+ LEFTOVERS_DYNAMIC_RE = /\bleftovers:dynamic:(#{NAME_RE})\b/.freeze
63
+
61
64
  def process_comments(comments) # rubocop:disable Metrics/AbcSize
62
65
  comments.each do |comment|
63
66
  @allow_lines << comment.loc.line if comment.text.match?(LEFTOVERS_ALLOW_RE)
64
67
  @test_lines << comment.loc.line if comment.text.match?(LEFTOVERS_TEST_RE)
68
+ dynamic_match = comment.text.match(LEFTOVERS_DYNAMIC_RE)
69
+ @dynamic_lines[comment.loc.line] = dynamic_match[1] if dynamic_match
65
70
 
66
- next unless (match = comment.text.match(LEFTOVERS_CALL_RE))
71
+ next unless (call_match = comment.text.match(LEFTOVERS_CALL_RE))
67
72
 
68
- match[1].scan(NAME_RE).each { |s| add_call(s.to_sym) }
73
+ call_match[1].scan(NAME_RE).each { |s| add_call(s.to_sym) }
69
74
  end
70
75
  end
71
76
 
@@ -136,6 +141,16 @@ module Leftovers
136
141
  add_call(node.name)
137
142
  end
138
143
 
144
+ def on_array(node)
145
+ super
146
+ collect_commented_dynamic(node)
147
+ end
148
+
149
+ def on_hash(node)
150
+ super
151
+ collect_commented_dynamic(node)
152
+ end
153
+
139
154
  # grab e.g. :to_s in each(&:to_s)
140
155
  def on_block_pass(node)
141
156
  super
@@ -225,6 +240,22 @@ module Leftovers
225
240
  end
226
241
  end
227
242
 
243
+ def collect_commented_dynamic(node)
244
+ fake_method_name = @dynamic_lines[node.loc.line]
245
+ return unless fake_method_name
246
+
247
+ node = build_send_wrapper_for(node, fake_method_name)
248
+ collect_dynamic(node)
249
+ end
250
+
251
+ def build_send_wrapper_for(node, name)
252
+ ::Leftovers::AST::Node.new(
253
+ :send,
254
+ [nil, name.to_sym, *node.arguments],
255
+ location: node.location
256
+ )
257
+ end
258
+
228
259
  def collect_dynamic(node) # rubocop:disable Metrics/AbcSize
229
260
  node.keep_line = @allow_lines.include?(node.loc.line)
230
261
  node.test_line = test_line?(node.loc) unless node.keep_line?
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Leftovers
6
+ module JSON
7
+ class << self
8
+ def precompile(json, name)
9
+ "__leftovers_document(#{to_ruby_argument(::JSON.parse(json))})"
10
+ rescue ::JSON::ParserError => e
11
+ Leftovers.warn "#{e.class}: (#{name.relative_path}): #{e.message}"
12
+ ''
13
+ end
14
+
15
+ private
16
+
17
+ def to_ruby_argument(value)
18
+ ruby = value.inspect
19
+ return ruby unless value.is_a?(Array)
20
+
21
+ ruby.delete_prefix!('[')
22
+ ruby.delete_suffix!(']')
23
+
24
+ ruby
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module Document
6
+ def self.build(true_arg)
7
+ return unless true_arg
8
+
9
+ ::Leftovers::Matchers::NodeName.new(:__leftovers_document)
10
+ end
11
+ end
12
+ end
13
+ end