leftovers 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -3
  3. data/docs/Configuration.md +82 -18
  4. data/leftovers.gemspec +1 -1
  5. data/lib/config/actionmailer.yml +11 -11
  6. data/lib/config/activesupport.yml +1 -1
  7. data/lib/config/rails.yml +1 -1
  8. data/lib/config/railties.yml +11 -0
  9. data/lib/config/ruby.yml +72 -0
  10. data/lib/leftovers/ast/node.rb +16 -11
  11. data/lib/leftovers/config.rb +1 -24
  12. data/lib/leftovers/config_loader/argument_position_schema.rb +11 -0
  13. data/lib/leftovers/config_loader/argumentless_transform_schema.rb +21 -0
  14. data/lib/leftovers/config_loader/attribute.rb +30 -0
  15. data/lib/leftovers/config_loader/document_schema.rb +21 -0
  16. data/lib/leftovers/config_loader/dynamic_schema.rb +17 -0
  17. data/lib/leftovers/config_loader/has_argument_schema.rb +13 -0
  18. data/lib/leftovers/config_loader/has_value_schema.rb +18 -0
  19. data/lib/leftovers/config_loader/keep_test_only_schema.rb +13 -0
  20. data/lib/leftovers/config_loader/node.rb +106 -0
  21. data/lib/leftovers/config_loader/object_schema.rb +189 -0
  22. data/lib/leftovers/config_loader/privacy_processor_schema.rb +12 -0
  23. data/lib/leftovers/config_loader/privacy_schema.rb +15 -0
  24. data/lib/leftovers/config_loader/require_schema.rb +11 -0
  25. data/lib/leftovers/config_loader/rule_pattern_schema.rb +18 -0
  26. data/lib/leftovers/config_loader/scalar_argument_schema.rb +14 -0
  27. data/lib/leftovers/config_loader/scalar_value_schema.rb +14 -0
  28. data/lib/leftovers/config_loader/schema.rb +21 -0
  29. data/lib/leftovers/config_loader/string_enum_schema.rb +62 -0
  30. data/lib/leftovers/config_loader/string_pattern_schema.rb +14 -0
  31. data/lib/leftovers/config_loader/string_schema.rb +14 -0
  32. data/lib/leftovers/config_loader/string_value_processor_schema.rb +11 -0
  33. data/lib/leftovers/config_loader/suggester.rb +22 -0
  34. data/lib/leftovers/config_loader/transform_schema.rb +28 -0
  35. data/lib/leftovers/config_loader/true_schema.rb +18 -0
  36. data/lib/leftovers/config_loader/value_matcher_schema.rb +18 -0
  37. data/lib/leftovers/config_loader/value_or_array_schema.rb +64 -0
  38. data/lib/leftovers/config_loader/value_processor_schema.rb +14 -0
  39. data/lib/leftovers/config_loader/value_type_schema.rb +17 -0
  40. data/lib/leftovers/config_loader.rb +82 -0
  41. data/lib/leftovers/definition_node.rb +6 -17
  42. data/lib/leftovers/definition_node_set.rb +11 -0
  43. data/lib/leftovers/definition_to_add.rb +31 -0
  44. data/lib/leftovers/dynamic_processors/call.rb +4 -3
  45. data/lib/leftovers/dynamic_processors/call_definition.rb +14 -7
  46. data/lib/leftovers/dynamic_processors/definition.rb +8 -3
  47. data/lib/leftovers/dynamic_processors/set_default_privacy.rb +18 -0
  48. data/lib/leftovers/dynamic_processors/set_privacy.rb +23 -0
  49. data/lib/leftovers/dynamic_processors.rb +2 -0
  50. data/lib/leftovers/file.rb +5 -1
  51. data/lib/leftovers/file_collector.rb +44 -17
  52. data/lib/leftovers/matcher_builders/node.rb +4 -0
  53. data/lib/leftovers/matcher_builders/node_privacy.rb +13 -0
  54. data/lib/leftovers/matcher_builders/node_type.rb +4 -4
  55. data/lib/leftovers/matcher_builders/node_value.rb +1 -1
  56. data/lib/leftovers/matcher_builders/string_pattern.rb +14 -5
  57. data/lib/leftovers/matcher_builders.rb +1 -0
  58. data/lib/leftovers/matchers/node_privacy.rb +19 -0
  59. data/lib/leftovers/matchers.rb +1 -0
  60. data/lib/leftovers/merged_config.rb +18 -34
  61. data/lib/leftovers/processor_builders/add_prefix.rb +1 -1
  62. data/lib/leftovers/processor_builders/add_suffix.rb +1 -1
  63. data/lib/leftovers/processor_builders/dynamic.rb +50 -16
  64. data/lib/leftovers/processor_builders/transform.rb +2 -2
  65. data/lib/leftovers/processor_builders/transform_set.rb +8 -8
  66. data/lib/leftovers/value_processors/each_for_definition_set.rb +2 -5
  67. data/lib/leftovers/value_processors/each_positional_argument.rb +1 -1
  68. data/lib/leftovers/value_processors/return_definition_node.rb +14 -0
  69. data/lib/leftovers/value_processors/{return_string.rb → return_sym.rb} +1 -1
  70. data/lib/leftovers/value_processors.rb +2 -2
  71. data/lib/leftovers/version.rb +1 -1
  72. data/lib/leftovers.rb +23 -14
  73. metadata +54 -22
  74. data/lib/config/actioncable.yml +0 -4
  75. data/lib/leftovers/config_validator/error_processor.rb +0 -196
  76. data/lib/leftovers/config_validator/schema_hash.rb +0 -551
  77. data/lib/leftovers/config_validator.rb +0 -61
  78. data/lib/leftovers/value_processors/return_definition.rb +0 -22
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 32e8f2762f7f513145ea799b64a059c7228dd7e9a4e08c2762abe92aad1370b1
4
- data.tar.gz: 9134e7d5c66bcbb25bb5fba15f5b1bb661ce18972cf91e179f165af52f955662
3
+ metadata.gz: f27830ef42bcbcec33a78126a3b47582fa394714e1d137e802cd5ab166e35df5
4
+ data.tar.gz: a111ed33a8345fe8dc5d43cb92206d52cbc47a03bc8e961baee8558d677542b6
5
5
  SHA512:
6
- metadata.gz: e361dc15e0a3496dadf81f91d356183631b1ad9f0b44951f976785622aa8550ccd0d8a6632064ab646a65231c4b772236cf1136b9267ceb81c59217d36bb4f78
7
- data.tar.gz: d82fd190746370c9ead45a27e5a660f81aafadf58736afd644d5fafad816daa450f25eebcf30d18875b185ab7d76b3215a696ed35bb75ad33509a474cff87736
6
+ metadata.gz: e14c6c1b74d4c13ebcbb4d1184d50257d6aacaf05e8e6708282633f61ea1988374156880d66bb26a037bf4b67b58381246f12357bdaa99ff9248db620d94c152
7
+ data.tar.gz: 34e766e6ca2374858ee6da35e924287641bc4441d8f642e4d08285a0066185aa865724567b90f91de34b17f340f3f182e9b3f326c5fc63bf6abc414c0dc058b3
data/CHANGELOG.md CHANGED
@@ -1,14 +1,32 @@
1
- # 0.6.0
1
+ # v0.7.0
2
+ - Rewrite the config parser/validation
3
+ - to provide clearer error messages with line numbers and everything
4
+ - to allow removing the json_schemer dependency with its 4 further dependencies
5
+ - Allow `match:` to be used with `has_prefix:` and/or `has_suffix:`. There's not a good use for this but it was easier than encoding 'this can't be used with that' logic especially for it.
6
+ - Add the possibility to quiet the `requires:` config, like:
7
+ ```yml
8
+ requires:
9
+ - 'active_support/inflections'
10
+ - quiet: './config/initializers/inflections'
11
+ ```
12
+ - consider all the public methods in rails custom generators to be used, this required some new features:
13
+ - add filtering methods/constants by public/protected/private
14
+ - add the possibility to set the privacy of methods and constants with method calls (`set_privacy:`, and `set_default_privacy:`)
15
+ - add `Method` and `Constant` as options for the `type:` filter
16
+ - add type filtering to dynamic.
17
+ - check `def self.whatever` as a definition, i didn't realise i wasn't checking this.
18
+
19
+ # v0.6.0
2
20
  - drop ruby 2.4 support, allowing for some performance improvements
3
21
  - Add ability to parse JSON and YAML files
4
22
  - Add magic comment that points to a particular dynamic rule
5
23
  - repeated calls to --write-todo won't have ordering differences
6
24
  - fix issue with --write-todo and unused methods defined in test files
7
25
 
8
- # 0.5.5
26
+ # v0.5.5
9
27
  - Fix rails resource/resources method signatures
10
28
 
11
- # 0.5.4
29
+ # v0.5.4
12
30
  - Add support for slim templates #13 - thanks @veganstraightedge
13
31
  - fix the #how-to-resolve link #11 - thanks @veganstraightedge
14
32
 
@@ -59,12 +59,17 @@ List filenames/paths that you want to include
59
59
  Unlike other `paths:` configuration, each entry is **not** the gitignore pattern format.
60
60
  Instead it is strings that can be passed directly to ruby's `require` method (relative paths should start with `./`).
61
61
 
62
- Missing files/gems will be a warning, but not a LoadError.
62
+ ```yml
63
+ require: ./config/initializers/my_other_inflections_file
64
+ ```
63
65
 
64
- By default, the default [`gems: active_support`]() config `require: activesupport` and `gems: rails` will `require: ./config/initializers/inflections`
66
+ Missing files/gems will be a warning, but not a LoadError.
67
+ To avoid seeing the warning if the file isn't there use `quiet:`.
65
68
 
66
69
  ```yml
67
- require: ./config/initializers/my_other_inflections_file
70
+ requires:
71
+ - 'active_support/inflections' # will warn if it's missing
72
+ - quiet: './config/initializers/inflections' # will say nothing
68
73
  ```
69
74
 
70
75
  Arrays are not necessary for single values
@@ -213,10 +218,12 @@ Each entry can be a string (an exact match for a method, constant, or variable n
213
218
  or the properties from `names:`
214
219
  - [`has_prefix:`](#has_prefix)
215
220
  - [`has_suffix:`](#has_suffix)
216
- - [`matches:`](#matches) (can't be used in the same entry as `has_prefix:` or `has_suffix:`)
221
+ - [`matches:`](#matches)
217
222
  - [`paths:`](#paths)
218
223
  - [`has_arguments:`](#has_arguments)
219
224
  - [`has_receiver:`](#has_receiver)
225
+ - [`type:`](#type)
226
+ - [`privacy:`](#privacy)
220
227
  - [`unless`](#unless)
221
228
 
222
229
  Arrays are not necessary for single values
@@ -242,7 +249,7 @@ Each entry can be a string (an exact match for a method, constant, or variable n
242
249
  or the properties from `names:`
243
250
  - [`has_prefix:`](#has_prefix)
244
251
  - [`has_suffix:`](#has_suffix)
245
- - [`matches:`](#matches) (can't be used in the same entry as `has_prefix:` or `has_suffix:`)
252
+ - [`matches:`](#matches)
246
253
  - [`paths:`](#paths)
247
254
  - [`has_arguments:`](#has_arguments)
248
255
  - [`unless`](#unless)
@@ -277,9 +284,11 @@ Each entry must have at least one of the following properties to restrict which
277
284
  - [`unless:`](#unless)
278
285
  - [`document: true`](#document-true)
279
286
 
280
- And must have one or both of
287
+ And must have at least one of
281
288
  - ['calls:`](#calls-defines)
282
289
  - [`defines:`](#calls-defines)
290
+ - [`set_privacy:](#set-privacy)
291
+ - [`set_default_privacy:`](#set-default-privacy)
283
292
 
284
293
  Arrays are not necessary for single values.
285
294
 
@@ -305,7 +314,7 @@ This is a list of methods/constants/variables, and can be used in [`dynamic:`](#
305
314
  Each entry can be a string (an exact match for a method, constant, or variable name that includes the sigil), or have at least one of the following properties:
306
315
  - [`has_prefix:`](#has_prefix)
307
316
  - [`has_suffix:`](#has_suffix)
308
- - [`matches:`](#matches) (this can't be used in the same entry as `has_prefix:` or `has_suffix:`)
317
+ - [`matches:`](#matches)
309
318
 
310
319
  Arrays are not necessary for single values
311
320
 
@@ -402,7 +411,7 @@ and consider it to have created methods like `can_build_house?` and `can_drive_c
402
411
  ## `calls:`, `defines:`
403
412
  _aliases `call:`, `define:`_
404
413
 
405
- At least one of these must be used in each entry in [`dynamic:`](#dynamic)
414
+ These may be used as entries in [`dynamic:`](#dynamic)
406
415
 
407
416
  This is a list of values that are called or defined dynamically by the matched method, or eventually after being assigned to the the matched constant or variable.
408
417
 
@@ -454,6 +463,43 @@ dynamic:
454
463
  calls: 1
455
464
  ```
456
465
 
466
+ ## `set_privacy:`
467
+
468
+ Set privacy has the same requirements as [`calls:` & `defines:`](#calls-defines).
469
+
470
+ additional it requires a `to:` with one of either `private`, `public`, or `protected`.
471
+
472
+ For example, from the ruby config:
473
+ ```yml
474
+ dynamic:
475
+ name: private_class_method
476
+ has_argument: 0
477
+ set_privacy:
478
+ argument: '*'
479
+ to: private
480
+ ```
481
+
482
+ which sets all methods named by the arguments to the privacy_class_method method to private.
483
+
484
+ these methods could then be filtered using the [`privacy:`](#privacy) method in another [`dynamic:`](#dynamic) or [`keep:`](#keep) rule.
485
+
486
+ Leftovers limits this to only affect methods defined in the same file.
487
+
488
+ ## `set_default_privacy:`
489
+
490
+ This must be one of `public`, `private`, or `protected` and will set all subsequent method definitions in this file to that default privacy (unless its then overridden by [`set_privacy`](#set_privacy))
491
+
492
+ For example, from the default ruby config:
493
+ ```yml
494
+ dynamic:
495
+ name: private
496
+ unless:
497
+ has_argument: 0
498
+ set_default_privacy: private
499
+ ```
500
+
501
+ these methods could then be filtered using the [`privacy:`](#privacy) method in another [`dynamic:`](#dynamic) or [`keep:`](#keep) rule.
502
+
457
503
  ## `arguments:`
458
504
  _alias `argument:`_
459
505
 
@@ -522,7 +568,7 @@ Each entry can be any of:
522
568
  - or have at least one of the following properties to match the keyword/hash key string or symbol:
523
569
  - [`has_prefix:`](#has_prefix)
524
570
  - [`has_suffix:`](#has_suffix)
525
- - [`matches:`](#matches) (this can't be used in the same entry as `has_prefix:` or `has_suffix:`)
571
+ - [`matches:`](#matches)
526
572
 
527
573
  Arrays are not necessary for single values
528
574
 
@@ -533,10 +579,10 @@ filter [`arguments:`](#arguments), [`has_arguments:`](#has_arguments), and [`key
533
579
  Each entry can be one of
534
580
  - `true`, `false`, `nil`, or an Integer. matches the literal value
535
581
  - a String. matches the literal string or symbol value
536
- - or have at least one of the following properties to match a string or symbol:
582
+ - or have at least one of the following properties to match the name:
537
583
  - [`has_prefix:`](#has_prefix)
538
584
  - [`has_suffix:`](#has_suffix)
539
- - [`matches:`](#matches) (this can't be used in the same entry as `has_prefix:` or `has_suffix:`)
585
+ - [`matches:`](#matches)
540
586
  - or have at least one of the following properties to match within an array or hash:
541
587
  - [`at`](#at)
542
588
  - [`has_value`](#has_value_has_receiver)
@@ -545,17 +591,35 @@ Each entry can be one of
545
591
  - or have the following property to match the receiver
546
592
  - [`has_receiver`](#has_value_has_receiver)
547
593
 
594
+ ## `privacy:`
595
+
596
+ filter [`dynamic:`](#dynamic) and [`keep:`](#keep) by method/constant privacy
597
+
598
+ e.g.
599
+
600
+ ```yml
601
+ keep:
602
+ - path: '**/generators/**/*_generator.rb'
603
+ privacy: public
604
+ type: Method
605
+ ```
606
+
607
+ considers all public methods defined in rails generators to be called.
608
+
548
609
  ## `type:`
549
610
 
550
- Filter [`has_value`](#has_value_has_receiver), by the argument/assigned value type
611
+ Filter by the literal type
551
612
 
552
613
  Each entry can be one of
553
- - `'String'`
554
- - `'Symbol'`
555
- - `'Integer'`
556
- - `'Float'`
557
- - `'Array'`
558
- - `'Hash'`
614
+ - `'String'` a literal string, defined with "" or '' (not String.new)
615
+ - `'Symbol'` a literal symbol
616
+ - `'Integer'` a literal integer
617
+ - `'Float'` a literal float
618
+ - `'Array'` a literal array defined with [] (not Array.new)
619
+ - `'Hash'` a literal hash, defined with {} (not Hash.new)
620
+ - `'Proc'` a literal proc/lambda, defined with lambda {}, proc {}, or -> {} (not Proc.new)
621
+ - `'Method'` a method call or definition defined with def, (not define_method {})
622
+ - `'Constant'` a constant assignment, or a literal module or class defined with keywords, (not Module/Class.new)
559
623
 
560
624
  Arrays are not necessary for single values
561
625
 
data/leftovers.gemspec CHANGED
@@ -35,6 +35,7 @@ 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'
38
39
  spec.add_development_dependency 'haml'
39
40
  spec.add_development_dependency 'pry', '~> 0.1'
40
41
  spec.add_development_dependency 'rake', '>= 13'
@@ -51,7 +52,6 @@ Gem::Specification.new do |spec|
51
52
 
52
53
  spec.add_development_dependency 'spellr', '>= 0.8.1'
53
54
  spec.add_dependency 'fast_ignore', '>= 0.15.1'
54
- spec.add_dependency 'json_schemer'
55
55
  spec.add_dependency 'parallel'
56
56
  spec.add_dependency 'parser'
57
57
  end
@@ -9,14 +9,14 @@ keep:
9
9
  - delivered_email
10
10
 
11
11
  dynamic:
12
- names:
13
- - deliver_now
14
- - deliver_later
15
- calls:
16
- value:
17
- deliver
18
- names:
19
- - before_action
20
- - after_action
21
- - around_action
22
- calls: ['*', if, unless]
12
+ - names:
13
+ - deliver_now
14
+ - deliver_later
15
+ calls:
16
+ value:
17
+ deliver
18
+ - names:
19
+ - before_action
20
+ - after_action
21
+ - around_action
22
+ calls: ['*', if, unless]
@@ -2,7 +2,7 @@ requires:
2
2
  - 'active_support'
3
3
  - 'active_support/core_ext/string'
4
4
  - 'active_support/inflections'
5
- - './config/initializers/inflections'
5
+ - quiet: './config/initializers/inflections'
6
6
 
7
7
  # THIS IS INCOMPLETE (you can help by expanding it)
8
8
  # rails is _really complicated_ and has a lot of magic which calls methods for you.
data/lib/config/rails.yml CHANGED
@@ -3,7 +3,6 @@
3
3
  # some is currently impossible to handle (with_options).
4
4
  # Some is just corners of rails I haven't hit yet.
5
5
  gems:
6
- - actioncable
7
6
  - actionmailer
8
7
  - actionpack
9
8
  - actionview
@@ -11,6 +10,7 @@ gems:
11
10
  - activemodel
12
11
  - activerecord
13
12
  - activesupport
13
+ - railties
14
14
 
15
15
  keep:
16
16
  - default_url_options # called by url_for, unsure what gem does
@@ -0,0 +1,11 @@
1
+ keep:
2
+ - # https://guides.rubyonrails.org/generators.html#generators-lookup
3
+ path: '**/generators/**/*_generator.rb'
4
+ # "When a generator is invoked, each public method in the generator is executed sequentially in
5
+ # the order that it is defined When a generator is invoked, each public method in the generator
6
+ # is executed sequentially in the order that it is defined"
7
+ #
8
+ # https://guides.rubyonrails.org/generators.html
9
+ privacy: public
10
+ type: Method
11
+
data/lib/config/ruby.yml CHANGED
@@ -98,3 +98,75 @@ dynamic:
98
98
  - instance_variable_set
99
99
  - class_variable_set
100
100
  defines: 0
101
+
102
+ # Module
103
+ - name: public
104
+ unless:
105
+ has_argument: 0
106
+ set_default_privacy: public
107
+
108
+ - name:
109
+ - public
110
+ - public_class_method
111
+ - public_constant
112
+ has_argument: 0
113
+ set_privacy:
114
+ argument: '*'
115
+ to: public
116
+
117
+ - name:
118
+ - public
119
+ - public_class_method
120
+ has_argument: 0
121
+ unless:
122
+ has_argument: 1
123
+ set_privacy:
124
+ argument: 0
125
+ nested:
126
+ argument: '*'
127
+ to: public
128
+
129
+ - name: protected
130
+ unless:
131
+ has_argument: 0
132
+ set_default_privacy: protected
133
+
134
+ - name: protected
135
+ has_argument: 0
136
+ set_privacy:
137
+ argument: '*'
138
+ to: protected
139
+
140
+ - name: protected
141
+ has_argument: 0
142
+ unless:
143
+ has_argument: 1
144
+ set_privacy:
145
+ argument: 0
146
+ nested:
147
+ argument: '*'
148
+ to: protected
149
+
150
+ - name: private
151
+ unless:
152
+ has_argument: 0
153
+ set_default_privacy: private
154
+
155
+ - name:
156
+ - private
157
+ - private_class_method
158
+ - private_constant
159
+ has_argument: 0
160
+ set_privacy:
161
+ argument: '*'
162
+ to: private
163
+
164
+ - name: private
165
+ has_argument: 0
166
+ unless:
167
+ has_argument: 1
168
+ set_privacy:
169
+ argument: 0
170
+ nested:
171
+ argument: '*'
172
+ to: private
@@ -25,14 +25,6 @@ module Leftovers
25
25
  @memo[:path] ||= loc.expression.source_buffer.name.to_s
26
26
  end
27
27
 
28
- def test_line?
29
- @memo[:test_line]
30
- end
31
-
32
- def test_line=(value)
33
- @memo[:test_line] = value
34
- end
35
-
36
28
  def keep_line=(value)
37
29
  @memo[:keep_line] = value
38
30
  end
@@ -41,6 +33,14 @@ module Leftovers
41
33
  @memo[:keep_line]
42
34
  end
43
35
 
36
+ def privacy=(value)
37
+ @memo[:privacy] = value
38
+ end
39
+
40
+ def privacy
41
+ @memo[:privacy] || :public
42
+ end
43
+
44
44
  def to_scalar_value
45
45
  case type
46
46
  when :sym, :int, :float, :str
@@ -58,7 +58,8 @@ module Leftovers
58
58
  case type
59
59
  when :sym, :int, :float, :str, :true, :false, :nil
60
60
  true
61
- else false
61
+ else
62
+ false
62
63
  end
63
64
  end
64
65
 
@@ -78,6 +79,10 @@ module Leftovers
78
79
  type == :str || type == :sym
79
80
  end
80
81
 
82
+ def string_or_symbol_or_def?
83
+ type == :str || type == :sym || type == :def || type == :defs
84
+ end
85
+
81
86
  def proc?
82
87
  return unless type == :block
83
88
 
@@ -140,9 +145,9 @@ module Leftovers
140
145
 
141
146
  def name
142
147
  @memo[:name] ||= case type
143
- when :send, :csend, :casgn, :const
148
+ when :send, :csend, :casgn, :const, :defs
144
149
  second
145
- when :def, :ivasgn, :ivar, :gvar, :cvar, :gvasgn, :cvasgn, :sym
150
+ when :def, :ivasgn, :ivar, :gvar, :cvar, :gvasgn, :cvasgn, :sym, :lvar
146
151
  first
147
152
  when :str
148
153
  first.to_sym
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
-
5
3
  module Leftovers
6
4
  class Config
7
5
  attr_reader :name
@@ -66,29 +64,8 @@ module Leftovers
66
64
 
67
65
  private
68
66
 
69
- def content
70
- @content ||= ::File.exist?(path) ? ::File.read(path) : ''
71
- end
72
-
73
- def path
74
- @path ||= ::File.expand_path("../config/#{name}.yml", __dir__)
75
- end
76
-
77
67
  def yaml
78
- @yaml ||= ::Leftovers::ConfigValidator.validate_and_process!(parse_yaml, path)
79
- end
80
-
81
- def parse_yaml
82
- # :nocov:
83
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6')
84
- Psych.safe_load(content, filename: path) || {}
85
- else
86
- Psych.safe_load(content, [], [], false, path) || {}
87
- end
88
- # :nocov:
89
- rescue ::Psych::SyntaxError => e
90
- warn "\e[31mConfig SyntaxError: #{e.message}\e[0m"
91
- Leftovers.exit 1
68
+ @yaml ||= ::Leftovers::ConfigLoader.load(name, path: @path, content: @content)
92
69
  end
93
70
  end
94
71
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class ArgumentPositionSchema < ObjectSchema
6
+ inherit_attributes_from StringPatternSchema
7
+
8
+ self.or_schema = ScalarArgumentSchema
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class ArgumentlessTransformSchema < StringEnumSchema
6
+ value :original
7
+ value :pluralize
8
+ value :singularize
9
+ value :camelize, aliases: :camelcase
10
+ value :underscore
11
+ value :titleize, aliases: :titlecase
12
+ value :demodulize
13
+ value :deconstantize
14
+ value :parameterize
15
+ value :downcase
16
+ value :upcase
17
+ value :capitalize
18
+ value :swapcase
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class Attribute
6
+ def initialize(name, value_schema, aliases: nil, require_group: nil)
7
+ @name = name
8
+ @value_schema = value_schema
9
+ @aliases = aliases
10
+ @require_group = require_group
11
+ end
12
+
13
+ def attributes
14
+ { @name => @value_schema }
15
+ end
16
+
17
+ def aliases
18
+ ::Leftovers.each_or_self(@aliases).map do |aka|
19
+ [aka, @name]
20
+ end.to_h
21
+ end
22
+
23
+ def require_groups
24
+ return {} unless @require_group
25
+
26
+ { @require_group => [@name, *::Leftovers.each_or_self(@aliases)] }
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class DocumentSchema < ObjectSchema
6
+ attribute :include_paths, ValueOrArraySchema[StringSchema], aliases: :include_path
7
+ attribute :exclude_paths, ValueOrArraySchema[StringSchema], aliases: :exclude_path
8
+ attribute :test_paths, ValueOrArraySchema[StringSchema], aliases: :test_path
9
+ attribute :haml_paths, ValueOrArraySchema[StringSchema], aliases: :haml_path
10
+ attribute :slim_paths, ValueOrArraySchema[StringSchema], aliases: :slim_path
11
+ attribute :yaml_paths, ValueOrArraySchema[StringSchema], aliases: :yaml_path
12
+ attribute :json_paths, ValueOrArraySchema[StringSchema], aliases: :json_path
13
+ attribute :erb_paths, ValueOrArraySchema[StringSchema], aliases: :erb_path
14
+ attribute :requires, ValueOrArraySchema[RequireSchema], aliases: :require
15
+ attribute :gems, ValueOrArraySchema[StringSchema], aliases: :gem
16
+ attribute :keep, ValueOrArraySchema[KeepTestOnlySchema]
17
+ attribute :test_only, ValueOrArraySchema[KeepTestOnlySchema]
18
+ attribute :dynamic, ValueOrArraySchema[DynamicSchema]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class DynamicSchema < ObjectSchema
6
+ inherit_attributes_from RulePatternSchema
7
+
8
+ attribute :call, ValueOrArraySchema[ValueProcessorSchema], aliases: :calls,
9
+ require_group: :processor
10
+ attribute :define, ValueOrArraySchema[ValueProcessorSchema], aliases: :defines,
11
+ require_group: :processor
12
+ attribute :set_privacy, ValueOrArraySchema[PrivacyProcessorSchema],
13
+ require_group: :processor
14
+ attribute :set_default_privacy, PrivacySchema, require_group: :processor
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class HasArgumentSchema < ObjectSchema
6
+ attribute :at, ValueOrArraySchema[ArgumentPositionSchema], require_group: :matcher
7
+ attribute :has_value, ValueOrArraySchema[HasValueSchema], require_group: :matcher
8
+ attribute :unless, ValueOrArraySchema[HasArgumentSchema], require_group: :matcher
9
+
10
+ self.or_schema = ScalarArgumentSchema
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class HasValueSchema < ObjectSchema
6
+ inherit_attributes_from StringPatternSchema, except: :unless
7
+
8
+ attribute :at, ValueOrArraySchema[ArgumentPositionSchema], require_group: :matcher
9
+ attribute :has_value, ValueOrArraySchema[HasValueSchema], require_group: :matcher
10
+
11
+ attribute :has_receiver, ValueOrArraySchema[HasValueSchema], require_group: :matcher
12
+ attribute :type, ValueOrArraySchema[ValueTypeSchema], require_group: :matcher
13
+ attribute :unless, ValueOrArraySchema[HasValueSchema], require_group: :matcher
14
+
15
+ self.or_schema = ScalarValueSchema
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class KeepTestOnlySchema < ObjectSchema
6
+ inherit_attributes_from StringPatternSchema, except: :unless
7
+ inherit_attributes_from RulePatternSchema, except: :unless
8
+ attribute :unless, ValueOrArraySchema[KeepTestOnlySchema], require_group: :matcher
9
+
10
+ self.or_schema = StringSchema
11
+ end
12
+ end
13
+ end