leftovers 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (191) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +17 -0
  3. data/README.md +7 -7
  4. data/docs/Configuration.md +141 -32
  5. data/docs/Custom-Precompilers.md +6 -0
  6. data/leftovers.gemspec +2 -1
  7. data/lib/config/actioncable.yml +36 -0
  8. data/lib/config/actionmailbox.yml +28 -0
  9. data/lib/config/actionmailer.yml +87 -11
  10. data/lib/config/actionpack.yml +130 -34
  11. data/lib/config/actiontext.yml +56 -0
  12. data/lib/config/actionview.yml +194 -44
  13. data/lib/config/activejob.yml +15 -8
  14. data/lib/config/activemodel.yml +175 -18
  15. data/lib/config/activerecord.yml +397 -86
  16. data/lib/config/activestorage.yml +26 -0
  17. data/lib/config/activesupport.yml +167 -24
  18. data/lib/config/leftovers.yml +48 -0
  19. data/lib/config/rails.yml +7 -3
  20. data/lib/config/railties.yml +7 -0
  21. data/lib/config/ruby.yml +438 -83
  22. data/lib/config/test-unit.yml +8 -0
  23. data/lib/leftovers/ast/array_node.rb +12 -0
  24. data/lib/leftovers/ast/block_node.rb +12 -0
  25. data/lib/leftovers/ast/builder.rb +24 -5
  26. data/lib/leftovers/ast/casgn_node.rb +20 -0
  27. data/lib/leftovers/ast/const_node.rb +15 -0
  28. data/lib/leftovers/ast/def_node.rb +15 -0
  29. data/lib/leftovers/ast/defs_node.rb +15 -0
  30. data/lib/leftovers/ast/false_node.rb +24 -0
  31. data/lib/leftovers/ast/has_arguments.rb +31 -0
  32. data/lib/leftovers/ast/hash_node.rb +17 -0
  33. data/lib/leftovers/ast/module_node.rb +16 -0
  34. data/lib/leftovers/ast/nil_node.rb +23 -0
  35. data/lib/leftovers/ast/node.rb +33 -90
  36. data/lib/leftovers/ast/numeric_node.rb +22 -0
  37. data/lib/leftovers/ast/send_node.rb +25 -0
  38. data/lib/leftovers/ast/str_node.rb +24 -0
  39. data/lib/leftovers/ast/sym_node.rb +25 -0
  40. data/lib/leftovers/ast/true_node.rb +24 -0
  41. data/lib/leftovers/ast/var_node.rb +14 -0
  42. data/lib/leftovers/ast/vasgn_node.rb +20 -0
  43. data/lib/leftovers/ast.rb +18 -0
  44. data/lib/leftovers/cli.rb +7 -1
  45. data/lib/leftovers/comparable_instance.rb +18 -0
  46. data/lib/leftovers/config_loader/argument_position_schema.rb +3 -1
  47. data/lib/leftovers/config_loader/array_schema.rb +53 -0
  48. data/lib/leftovers/config_loader/document_schema.rb +3 -2
  49. data/lib/leftovers/config_loader/dynamic_schema.rb +1 -0
  50. data/lib/leftovers/config_loader/has_value_schema.rb +4 -0
  51. data/lib/leftovers/config_loader/keyword_argument_schema.rb +13 -0
  52. data/lib/leftovers/config_loader/regexp_schema.rb +27 -0
  53. data/lib/leftovers/config_loader/rule_pattern_schema.rb +2 -0
  54. data/lib/leftovers/config_loader/scalar_value_schema.rb +8 -0
  55. data/lib/leftovers/config_loader/schema.rb +10 -0
  56. data/lib/leftovers/config_loader/string_enum_schema.rb +1 -1
  57. data/lib/leftovers/config_loader/string_pattern_schema.rb +1 -1
  58. data/lib/leftovers/config_loader/transform_schema.rb +12 -6
  59. data/lib/leftovers/config_loader/value_matcher_condition_schema.rb +13 -0
  60. data/lib/leftovers/config_loader/value_matcher_schema.rb +4 -1
  61. data/lib/leftovers/config_loader/value_or_array_schema.rb +2 -34
  62. data/lib/leftovers/config_loader/value_processor_schema.rb +2 -2
  63. data/lib/leftovers/config_loader.rb +11 -4
  64. data/lib/leftovers/definition_collection.rb +37 -0
  65. data/lib/leftovers/definition_node_set.rb +10 -2
  66. data/lib/leftovers/file.rb +1 -1
  67. data/lib/leftovers/file_collector/comments_processor.rb +1 -1
  68. data/lib/leftovers/file_collector/node_processor.rb +7 -7
  69. data/lib/leftovers/file_collector.rb +26 -32
  70. data/lib/leftovers/file_list.rb +3 -2
  71. data/lib/leftovers/matcher_builders/and.rb +26 -9
  72. data/lib/leftovers/matcher_builders/node.rb +32 -20
  73. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +3 -1
  74. data/lib/leftovers/matcher_builders/node_pair_key.rb +16 -0
  75. data/lib/leftovers/matcher_builders/node_type.rb +9 -9
  76. data/lib/leftovers/matcher_builders/node_value.rb +23 -9
  77. data/lib/leftovers/matcher_builders/or.rb +22 -7
  78. data/lib/leftovers/matcher_builders/path.rb +3 -1
  79. data/lib/leftovers/matcher_builders.rb +1 -1
  80. data/lib/leftovers/matchers/all.rb +4 -0
  81. data/lib/leftovers/matchers/and.rb +4 -0
  82. data/lib/leftovers/matchers/any.rb +2 -0
  83. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +7 -4
  84. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +5 -4
  85. data/lib/leftovers/matchers/node_has_positional_argument.rb +5 -1
  86. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +6 -1
  87. data/lib/leftovers/matchers/node_has_receiver.rb +4 -0
  88. data/lib/leftovers/matchers/node_is_proc.rb +13 -0
  89. data/lib/leftovers/matchers/node_name.rb +9 -3
  90. data/lib/leftovers/matchers/node_pair_key.rb +23 -0
  91. data/lib/leftovers/matchers/node_pair_value.rb +7 -3
  92. data/lib/leftovers/matchers/node_path.rb +7 -3
  93. data/lib/leftovers/matchers/node_privacy.rb +7 -3
  94. data/lib/leftovers/matchers/node_scalar_value.rb +6 -1
  95. data/lib/leftovers/matchers/node_type.rb +7 -3
  96. data/lib/leftovers/matchers/not.rb +2 -0
  97. data/lib/leftovers/matchers/or.rb +2 -0
  98. data/lib/leftovers/matchers/path.rb +21 -0
  99. data/lib/leftovers/matchers.rb +3 -1
  100. data/lib/leftovers/merged_config.rb +26 -25
  101. data/lib/leftovers/parser.rb +7 -4
  102. data/lib/leftovers/precompilers.rb +5 -5
  103. data/lib/leftovers/processor_builders/action.rb +55 -37
  104. data/lib/leftovers/processor_builders/add_prefix.rb +18 -10
  105. data/lib/leftovers/processor_builders/add_suffix.rb +18 -10
  106. data/lib/leftovers/processor_builders/argument.rb +28 -11
  107. data/lib/leftovers/processor_builders/dynamic.rb +37 -31
  108. data/lib/leftovers/processor_builders/each.rb +82 -10
  109. data/lib/leftovers/processor_builders/itself.rb +2 -2
  110. data/lib/leftovers/processor_builders/keyword.rb +7 -6
  111. data/lib/leftovers/processor_builders/keyword_argument.rb +4 -2
  112. data/lib/leftovers/processor_builders/receiver.rb +13 -0
  113. data/lib/leftovers/processor_builders/transform.rb +55 -44
  114. data/lib/leftovers/processor_builders/transform_chain.rb +1 -1
  115. data/lib/leftovers/processor_builders/transform_set.rb +9 -29
  116. data/lib/leftovers/processor_builders/value.rb +4 -4
  117. data/lib/leftovers/processor_builders.rb +1 -3
  118. data/lib/leftovers/processors/add_call.rb +14 -0
  119. data/lib/leftovers/processors/add_definition_node.rb +16 -0
  120. data/lib/leftovers/processors/add_dynamic_prefix.rb +29 -0
  121. data/lib/leftovers/processors/add_dynamic_suffix.rb +29 -0
  122. data/lib/leftovers/{value_processors → processors}/add_prefix.rb +7 -3
  123. data/lib/leftovers/{value_processors → processors}/add_suffix.rb +7 -3
  124. data/lib/leftovers/processors/append_sym.rb +13 -0
  125. data/lib/leftovers/{value_processors → processors}/camelize.rb +7 -3
  126. data/lib/leftovers/{value_processors → processors}/capitalize.rb +7 -3
  127. data/lib/leftovers/{value_processors → processors}/deconstantize.rb +7 -3
  128. data/lib/leftovers/{value_processors → processors}/delete_after.rb +9 -5
  129. data/lib/leftovers/processors/delete_after_last.rb +26 -0
  130. data/lib/leftovers/processors/delete_before.rb +27 -0
  131. data/lib/leftovers/processors/delete_before_last.rb +27 -0
  132. data/lib/leftovers/{value_processors → processors}/delete_prefix.rb +7 -3
  133. data/lib/leftovers/{value_processors → processors}/delete_suffix.rb +7 -3
  134. data/lib/leftovers/{value_processors → processors}/demodulize.rb +7 -3
  135. data/lib/leftovers/{value_processors → processors}/downcase.rb +7 -3
  136. data/lib/leftovers/processors/each.rb +25 -0
  137. data/lib/leftovers/processors/each_for_definition_set.rb +33 -0
  138. data/lib/leftovers/processors/each_keyword.rb +29 -0
  139. data/lib/leftovers/processors/each_keyword_argument.rb +29 -0
  140. data/lib/leftovers/processors/each_positional_argument.rb +27 -0
  141. data/lib/leftovers/processors/each_positional_argument_from.rb +30 -0
  142. data/lib/leftovers/processors/eval.rb +16 -0
  143. data/lib/leftovers/processors/itself.rb +21 -0
  144. data/lib/leftovers/processors/keyword_argument.rb +30 -0
  145. data/lib/leftovers/processors/match_current_node.rb +26 -0
  146. data/lib/leftovers/processors/match_matched_node.rb +26 -0
  147. data/lib/leftovers/{value_processors → processors}/parameterize.rb +7 -3
  148. data/lib/leftovers/{value_processors → processors}/placeholder.rb +5 -4
  149. data/lib/leftovers/{value_processors → processors}/pluralize.rb +7 -3
  150. data/lib/leftovers/{value_processors → processors}/positional_argument.rb +8 -6
  151. data/lib/leftovers/processors/receiver.rb +24 -0
  152. data/lib/leftovers/{value_processors → processors}/replace_value.rb +7 -3
  153. data/lib/leftovers/processors/set_default_privacy.rb +21 -0
  154. data/lib/leftovers/processors/set_privacy.rb +23 -0
  155. data/lib/leftovers/{value_processors → processors}/singularize.rb +7 -3
  156. data/lib/leftovers/{value_processors → processors}/split.rb +8 -4
  157. data/lib/leftovers/{value_processors → processors}/swapcase.rb +7 -3
  158. data/lib/leftovers/{value_processors → processors}/titleize.rb +7 -3
  159. data/lib/leftovers/{value_processors → processors}/underscore.rb +7 -3
  160. data/lib/leftovers/{value_processors → processors}/upcase.rb +7 -3
  161. data/lib/leftovers/processors.rb +49 -0
  162. data/lib/leftovers/version.rb +1 -1
  163. data/lib/leftovers.rb +3 -12
  164. metadata +97 -52
  165. data/lib/leftovers/dynamic_processors/call.rb +0 -22
  166. data/lib/leftovers/dynamic_processors/call_definition.rb +0 -34
  167. data/lib/leftovers/dynamic_processors/definition.rb +0 -27
  168. data/lib/leftovers/dynamic_processors/each.rb +0 -19
  169. data/lib/leftovers/dynamic_processors/null.rb +0 -9
  170. data/lib/leftovers/dynamic_processors/set_default_privacy.rb +0 -18
  171. data/lib/leftovers/dynamic_processors/set_privacy.rb +0 -23
  172. data/lib/leftovers/dynamic_processors.rb +0 -13
  173. data/lib/leftovers/matcher_builders/node_pair_name.rb +0 -18
  174. data/lib/leftovers/matchers/predicate.rb +0 -19
  175. data/lib/leftovers/processor_builders/each_action.rb +0 -51
  176. data/lib/leftovers/processor_builders/each_dynamic.rb +0 -50
  177. data/lib/leftovers/processor_builders/each_for_definition_set.rb +0 -40
  178. data/lib/leftovers/value_processors/add_dynamic_prefix.rb +0 -24
  179. data/lib/leftovers/value_processors/add_dynamic_suffix.rb +0 -24
  180. data/lib/leftovers/value_processors/delete_before.rb +0 -22
  181. data/lib/leftovers/value_processors/each.rb +0 -21
  182. data/lib/leftovers/value_processors/each_for_definition_set.rb +0 -23
  183. data/lib/leftovers/value_processors/each_keyword.rb +0 -27
  184. data/lib/leftovers/value_processors/each_keyword_argument.rb +0 -27
  185. data/lib/leftovers/value_processors/each_positional_argument.rb +0 -25
  186. data/lib/leftovers/value_processors/itself.rb +0 -17
  187. data/lib/leftovers/value_processors/keyword.rb +0 -28
  188. data/lib/leftovers/value_processors/keyword_argument.rb +0 -28
  189. data/lib/leftovers/value_processors/return_definition_node.rb +0 -14
  190. data/lib/leftovers/value_processors/return_sym.rb +0 -14
  191. data/lib/leftovers/value_processors.rb +0 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c2e0c74dad85b7b571608a7207f006fe14d5748e1a155470185112b80a7b80a3
4
- data.tar.gz: 68f3d83b310f640e127b961e6ac2ece795a7b9e2a6de961a1b42498916e092d7
3
+ metadata.gz: 36067c7870efb2d16529b0af04739161fc445c310bd5eab7b4b5ff5ccf556126
4
+ data.tar.gz: 5953a6893935af8ac6f1c33afad540c097515a12c4dede73261079cbbd2a561d
5
5
  SHA512:
6
- metadata.gz: c57c64254cc2092e38b8decfd7bde0a021d66a7c3f563dc3e1f5a68b91c4bfc7b16a8490e5437b3da942071d41d2c35c247e1e51739064e14fdfcc6653b192b3
7
- data.tar.gz: b129119436c793987c89b032d5936b10ca935c7fc5398e7a2843665bbfec28ccaacd0a0090c8cd37c5172b6892f4291455aef40df6bae67727d25ac47fd871a3
6
+ metadata.gz: 70b0cd0d8f3caa5f14282b36bf7f3776a1b0396485a7cfb7fb66460fc3f287edf7ed1d8f733ce303fcb67704c8839df2bb9eb105c761f492b53e1ea575b8f685
7
+ data.tar.gz: f43bf9b235fcc43dfdf0d322037523f659214d35387ad788dc5f2c8453a74ef74861db6cca91dc9ae159f8122edcf2fbb6adb9fa107b69e74a753b4e4d286d42
data/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ # v0.9.0
2
+ - Automatically test the config examples in the documentation, and fix the errors
3
+ - simplify the `type: Proc` matcher
4
+ - Update FastIgnore dependency, make fewer filesystem calls
5
+ - Comprehensively describe all of ruby core and rails
6
+ This required/revealed a number of additions to the config
7
+ - Improve the performance of large config files by squash the config matching more
8
+ - Add `names:` and `has_arguments:` to `has_value:`.
9
+ - Fix error when positional `has_arguments:`/`has_value: at:` checks a node without arguments
10
+ - Add `eval` as a processing type, alongside `calls:` and `defines:`, this will process allow processing literal calls to instance_eval etc.
11
+ - Allow calling or defining based on the `receiver:`
12
+ - `all: []` & `any: []` arguments to dynamic/keep/test_only
13
+ - add `arguments: 1+` or `has_arguments: { at: 1+, has_value: true }` to match arguments from that position onward
14
+ - allow `has_arguments:` and `has_receiver:` (and `unless:` and `all:` and `any:` of those) to go within `calls:`,`defines:`,`set_privacy:`,`add_prefix:`,`add_suffix:` for cases like the `delegate prefix: true` vs `delegate prefix: :value` without having to redefine everything.
15
+ - allow `has_arguments.at` and `arguments:` to have a `type:` to distinguish between e.g. symbol keys and string keys.
16
+ - Add a way to test custom precompilers with --view-compiled [PATH_PATTERNS...]
17
+
1
18
  # v0.8.0
2
19
  - Allow custom precompilers
3
20
  ```yml
data/README.md CHANGED
@@ -15,7 +15,7 @@ Code that never gets executed is code that you shouldn't need to maintain
15
15
 
16
16
  Leftovers will use static analysis to find these bits of code for you.
17
17
 
18
- It's aware of how some gems call methods for you, including (still somewhat incomplete) support for rails.
18
+ It's aware of how some gems call methods for you, including support for much of rails.
19
19
 
20
20
  ## Features
21
21
 
@@ -141,21 +141,21 @@ This would consider `puts` and `warn` to both have been called
141
141
  To mark a dynamic call for literal hash and array values without enumerating everything in the comment again, use `leftovers:dynamic:` on the same line as the beginning of the array or hash
142
142
 
143
143
  ```ruby
144
- [ # leftovers:dynamic:call_login
144
+ [ # leftovers:dynamic:call_attributes
145
145
  :user,
146
146
  :admin
147
- ].each { |method| send("#{method}_login") }
147
+ ].map { |method| send("#{method}_attributes") }
148
148
  ```
149
149
 
150
150
  with the following configuration matching the `name: value` to the `leftovers:dynamic:process_name`
151
151
 
152
152
  ```yaml
153
153
  dynamic:
154
- name: call_login
154
+ name: call_attributes
155
155
  arguments: '*'
156
- add_suffix: '_login'
156
+ add_suffix: '_attributes'
157
157
  ```
158
- This would consider `user_login` and `admin_login` to both have been called.
158
+ This would consider `user_attributes` and `admin_attributes` to both have been called.
159
159
 
160
160
  ## Configuration file
161
161
 
@@ -201,7 +201,7 @@ To install this gem onto your local machine, run `bundle exec rake install`.
201
201
 
202
202
  Bug reports and pull requests are welcome on GitHub at https://github.com/robotdana/leftovers.
203
203
 
204
- I especially encourage issues and improvements to the default config, whether expanding the existing config/*.yml (rails.yml is particularly incomplete) or adding new gems.
204
+ I especially encourage issues and improvements to the default config, whether expanding the existing config/*.yml or adding new gems.
205
205
  The file should be named `[rubygems name].yml` and its structure is identical to the [project config](#configuration)
206
206
 
207
207
  ## License
@@ -99,10 +99,10 @@ Define any precompilers and the paths they affect.
99
99
 
100
100
  `paths:` are defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
101
101
 
102
- `format:` must be one of the predefined precompilers (erb, haml, [json](#format-json), slim, [yaml](#format-yaml)), or `custom:` with the name of a [custom precompiler]('../Custom-Precompilers.md) module.
102
+ `format:` must be one of the predefined precompilers (erb, haml, [json](#format-json), slim, [yaml](#format-yaml)), or `custom:` with the name of a [custom precompiler](https://github.com/robotdana/leftovers/blob/main/docs/Custom-Precompilers.md) module.
103
103
  (use [`require:`](#requires) to have leftovers load its file)
104
104
 
105
- See [Custom precompilers]('../Custom-Precompilers.md) for more details on the custom precompiler class
105
+ See [Custom precompilers](https://github.com/robotdana/leftovers/blob/main/docs/Custom-Precompilers.md) for more details on the custom precompiler class
106
106
 
107
107
  Arrays are not necessary for single values.
108
108
 
@@ -113,7 +113,7 @@ and renders the structure of the yaml document as arguments for the [`document:t
113
113
 
114
114
  so you could, e.g. read the class name out of a yaml document like:
115
115
 
116
- ```yml
116
+ ```
117
117
  class_name: MyClass
118
118
  ```
119
119
 
@@ -187,7 +187,9 @@ Each entry can be a string (an exact match for a method, constant, or variable n
187
187
  - [`has_receiver:`](#has_receiver)
188
188
  - [`type:`](#type)
189
189
  - [`privacy:`](#privacy)
190
- - [`unless`](#unless)
190
+ - [`unless:`](#unless)
191
+ - [`all:`](#any-all)
192
+ - [`any:`](#any-all)
191
193
 
192
194
  Arrays are not necessary for single values
193
195
 
@@ -198,7 +200,6 @@ keep:
198
200
  - ssl_configured?
199
201
  - has_suffix: Helper
200
202
  path: /app/helpers
201
- ...
202
203
  ```
203
204
 
204
205
  Alternatively, you can mark method/constants/variables in-place using [magic comments](https://github.com/robotdana/leftovers/tree/main/README.md#magic-comments).
@@ -215,7 +216,12 @@ Each entry can be a string (an exact match for a method, constant, or variable n
215
216
  - [`matches:`](#matches)
216
217
  - [`paths:`](#paths)
217
218
  - [`has_arguments:`](#has_arguments)
219
+ - [`has_receiver:`](#has_receiver)
220
+ - [`type:`](#type)
221
+ - [`privacy:`](#privacy)
218
222
  - [`unless`](#unless)
223
+ - [`all:`](#any-all)
224
+ - [`any:`](#any-all)
219
225
 
220
226
  Arrays are not necessary for single values
221
227
 
@@ -226,7 +232,6 @@ test_only:
226
232
  - ssl_configured?
227
233
  - has_suffix: Helper
228
234
  path: /app/helpers
229
- ...
230
235
  ```
231
236
 
232
237
  Alternatively, you can mark method/constants/variables in-place using [magic comments](https://github.com/robotdana/leftovers/tree/main/README.md#magic-comments).
@@ -241,17 +246,22 @@ Each entry must have at least one of the following properties to restrict which
241
246
  - [`has_prefix:`](#has_prefix)
242
247
  - [`has_suffix:`](#has_suffix)
243
248
  - [`matches:`](#matches)
249
+ - [`document: true`](#document-true)
244
250
  - [`paths:`](#paths)
245
251
  - [`has_arguments:`](#has_arguments)
246
252
  - [`has_receiver:`](#has_receiver)
253
+ - [`type:`](#type)
254
+ - [`privacy:`](#privacy)
247
255
  - [`unless:`](#unless)
248
- - [`document: true`](#document-true)
256
+ - [`all:`](#any-all)
257
+ - [`any:`](#any-all)
249
258
 
250
259
  And must have at least one of
251
260
  - ['calls:`](#calls-defines)
252
261
  - [`defines:`](#calls-defines)
253
262
  - [`set_privacy:](#set-privacy)
254
263
  - [`set_default_privacy:`](#set-default-privacy)
264
+ - [`eval:`](#eval)
255
265
 
256
266
  Arrays are not necessary for single values.
257
267
 
@@ -266,7 +276,6 @@ dynamic:
266
276
  calls:
267
277
  arguments: '*'
268
278
  add_prefix: '@'
269
- ...
270
279
  ```
271
280
 
272
281
  ## `names:`
@@ -289,7 +298,6 @@ keep:
289
298
  - names:
290
299
  has_suffix: Helper
291
300
  path: /app/helpers
292
- ...
293
301
  ```
294
302
 
295
303
  ## `has_prefix:`, `has_suffix:`
@@ -351,7 +359,7 @@ Instructs to consider the whole document. this is useful when parsing [YAML](#ya
351
359
  e.g.
352
360
 
353
361
  ```yml
354
- includes: /config/roles.yml
362
+ include_paths: /config/roles.yml
355
363
  dynamic:
356
364
  - document: true
357
365
  path: /config/roles.yml
@@ -362,7 +370,7 @@ dynamic:
362
370
  ```
363
371
 
364
372
  will parse "config/roles.yml"
365
- ```yml
373
+ ```
366
374
  - build_house
367
375
  - drive_car
368
376
  ```
@@ -393,8 +401,10 @@ also there may be any or all of these properties:
393
401
  - [`add_suffix:`](#add_prefix-add_suffix)
394
402
  - [`delete_prefix:`](#delete_prefix-delete_suffix)
395
403
  - [`delete_suffix:`](#delete_prefix-delete_suffix)
396
- - [`delete_before:`](#delete_before-delete_after)
397
- - [`delete_after:`](#delete_before-delete_after)
404
+ - [`delete_before:`](#delete_before-delete_after--delete_before_last-delete_after_last)
405
+ - [`delete_after:`](#delete_before-delete_after--delete_before_last-delete_after_last)
406
+ - [`delete_before_last:`](#delete_before-delete_after-delete_before_last-delete_after_last)
407
+ - [`delete_after_last:`](#delete_before-delete_after-delete_before_last-delete_after_last)
398
408
  - [`split:`](#split)
399
409
  - [`downcase:`](#downcase-upcase-capitalize-swapcase)
400
410
  - [`upcase:`](#downcase-upcase-capitalize-swapcase)
@@ -417,13 +427,13 @@ dynamic:
417
427
  - send
418
428
  calls:
419
429
  arguments:
420
- - 1
430
+ - 0
421
431
  ```
422
432
  is equivalent to:
423
433
  ```yml
424
434
  dynamic:
425
435
  name: send
426
- calls: 1
436
+ calls: 0
427
437
  ```
428
438
 
429
439
  ## `set_privacy:`
@@ -463,6 +473,27 @@ dynamic:
463
473
 
464
474
  these methods could then be filtered using the [`privacy:`](#privacy) method in another [`dynamic:`](#dynamic) or [`keep:`](#keep) rule.
465
475
 
476
+ ## `eval:`
477
+
478
+ Eval has the same requirements as [`calls:` & `defines:`](#calls-defines).
479
+
480
+ it parses a string or transformed string as ruby, using the same rules as the containing file
481
+ For example:
482
+
483
+ ```yml
484
+ dynamic:
485
+ name: eval_later
486
+ eval:
487
+ argument: my_ruby_string
488
+ ```
489
+
490
+ with the ruby:
491
+ ```ruby
492
+ eval_later(delay: 1000, my_ruby_string: "MyClass.puts 'shenanigans'")
493
+ ```
494
+
495
+ would consider `MyClass`, and `puts` to have been called.
496
+
466
497
  ## `arguments:`
467
498
  _alias `argument:`_
468
499
 
@@ -503,11 +534,11 @@ When the keyword argument **keywords** are the thing being called.
503
534
  ```yml
504
535
  dynamic:
505
536
  - name: validates
506
- calls:
507
- - arguments: '*'
508
- - keywords: '**'
509
- camelize: true
510
- add_suffix: Validator
537
+ calls:
538
+ - arguments: '*'
539
+ - keywords: '**'
540
+ camelize: true
541
+ add_suffix: Validator
511
542
  ```
512
543
  ```ruby
513
544
  validates :first_name, :surname, presence: true
@@ -526,7 +557,9 @@ This can be used in:
526
557
  Each entry can be any of:
527
558
  - `'*'`: matches all positional arguments/array positions
528
559
  - `'**'`: matches all keyword arguments/hash positions
529
- - any positive Integer: matches the 1-indexed argument position/array position
560
+ - `1+`, `2+`, etc: matches all positional arguments/array elements at or greater than the 0-indexed position
561
+ - any Integer: matches the 0-indexed argument position/array position
562
+ - negative values match positions counting from the end, e.g. `-1` is the last item
530
563
  - any other String: matches the keyword argument or hash value, where the keyword/hash key string or symbol
531
564
  - or have at least one of the following properties to match the keyword/hash key string or symbol:
532
565
  - [`has_prefix:`](#has_prefix)
@@ -535,6 +568,41 @@ Each entry can be any of:
535
568
 
536
569
  Arrays are not necessary for single values
537
570
 
571
+ ## `any:`, `all:`
572
+
573
+ filter by `any:` or `all:` of the argument filters
574
+
575
+ by default array values match any of the values,
576
+ and hash values are match all of the values
577
+
578
+ ```yml
579
+ dynamic:
580
+ name: my_method
581
+ has_receiver: MyReceiver
582
+ has_arguments:
583
+ - part_a
584
+ - part_b
585
+ calls: 0
586
+ ```
587
+
588
+ will match the first argument of anything named my_method, with the receiver MyReceiver that has the keyword argument part_a and/or part_b.
589
+
590
+ to avoid this default use `all:` and/or `any:`
591
+
592
+ ```yml
593
+ dynamic:
594
+ any:
595
+ - name: my_method
596
+ - has_receiver: MyReceiver
597
+ all:
598
+ - has_argument: part_a
599
+ - has_argument: part_b
600
+ calls: 0
601
+ ```
602
+
603
+ will match the first argument of anything named my_method or with the receiver MyReceiver, that have both the keyword arguments part_a and part_b
604
+
605
+
538
606
  ## `has_value:`, `has_receiver:`
539
607
 
540
608
  filter [`arguments:`](#arguments), [`has_arguments:`](#has_arguments), and [`keywords:`](#keywords), by the argument/assigned/receiver value
@@ -606,7 +674,7 @@ e.g.
606
674
  dynamic:
607
675
  - names: my_method
608
676
  calls:
609
- argument: 2
677
+ argument: 1
610
678
  nested:
611
679
  argument: '*'
612
680
  nested:
@@ -643,6 +711,7 @@ The original method/constant/variable name will continue to be called/defined as
643
711
  This can be used in [`calls:`](#calls-defines) and [`defines:`](#calls-defines)
644
712
 
645
713
  ```yml
714
+ dynamic:
646
715
  - name:
647
716
  has_prefix: be_
648
717
  calls:
@@ -661,6 +730,7 @@ Will supply a literal string value method/constant/variable name itself as the t
661
730
  This can be used in [`calls:`](#calls-defines) and [`defines:`](#calls-defines).
662
731
 
663
732
  ```yml
733
+ dynamic:
664
734
  - name: perform_async
665
735
  calls:
666
736
  value: perform
@@ -683,8 +753,10 @@ Each entry can have a string that is an argumentless transform (e.g. capitalize)
683
753
  - [`add_suffix:`](#add_prefix-add_suffix)
684
754
  - [`delete_prefix:`](#delete_prefix-delete_suffix)
685
755
  - [`delete_suffix:`](#delete_prefix-delete_suffix)
686
- - [`delete_before:`](#delete_before-delete_after)
687
- - [`delete_after:`](#delete_before-delete_after)
756
+ - [`delete_before:`](#delete_before-delete_after-delete_before_last-delete_after_last)
757
+ - [`delete_after:`](#delete_before-delete_after-delete_before_last-delete_after_last)
758
+ - [`delete_before_last:`](#delete_before-delete_after-delete_before_last-delete_after_last)
759
+ - [`delete_after_last:`](#delete_before-delete_after-delete_before_last-delete_after_last)
688
760
  - [`split:`](#split)
689
761
  - [`downcase`](#downcase-upcase-capitalize-swapcase) or `downcase: true`
690
762
  - [`upcase`](#downcase-upcase-capitalize-swapcase) or `upcase: true`
@@ -699,26 +771,43 @@ Each entry can have a string that is an argumentless transform (e.g. capitalize)
699
771
  - [`deconstantize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `deconstantize: true`
700
772
  - [`titleize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `titleize: true`
701
773
  - [`parameterize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `parameterize: true`
774
+ - `transforms:`
702
775
 
703
776
  If any one of these `transforms:` entries are used, all count as being used. To have these be counted independently instead, create multiple entries in the `defines:` list.
704
777
 
705
778
  ```yml
779
+ dynamic:
706
780
  - name: attribute
707
- defines:
708
- - argument: 1
709
- transforms:
710
- - original # no transformation
711
- - add_suffix: '?'
712
- - add_suffix: '='
781
+ defines:
782
+ - argument: 0
783
+ transforms:
784
+ - original # no transformation
785
+ - add_suffix: '?'
786
+ - add_suffix: '='
713
787
  ```
714
788
  ```ruby
715
789
  attribute :first_name
716
790
  ```
717
791
  will count as a definition of `first_name`, `first_name=` and `first_name?`. `firstname=` wouldn't be reported on, even if only `first_name` and `first_name?` were used.
718
792
 
793
+ ```yml
794
+ dynamic:
795
+ - name: attr_accessor
796
+ defines:
797
+ - argument: '*'
798
+ - argument: '*'
799
+ transforms:
800
+ add_suffix: '='
801
+ ```
802
+ ```ruby
803
+ attr_accessor :first_name
804
+ ```
805
+ will count the calls to `first_name` and `first_name=` separately, with the understand it can be swapped to attr_reader or attr_writer if one or other isn't used.
806
+
719
807
  Arrays are not necessary for single values, and if there is just one set of transforms, the `transforms:` keyword can be omitted and everything moved up a level.
720
808
 
721
809
  ```yml
810
+ dynamic:
722
811
  - name: attr_writer
723
812
  defines:
724
813
  - argument: '*'
@@ -729,6 +818,21 @@ attr_writer :first_name, :surname
729
818
  ```
730
819
  will count as the definition of `first_name=`, and `surname=`
731
820
 
821
+ Multiple transform arguments will be applied sequentially
822
+ ```yml
823
+ dynamic:
824
+ - name: has_many
825
+ calls:
826
+ - argument: 0
827
+ singularize: true
828
+ camelize: true
829
+ split: '::'
830
+ ```
831
+ ```ruby
832
+ has_many :users
833
+ ```
834
+ counts as a call to `User`
835
+
732
836
  ## `original`
733
837
 
734
838
  Can be used in the [`transforms:`](#transforms) list, if used in a hash `true` can be used as a placeholder value
@@ -758,11 +862,16 @@ if multiple transform results are possible (from multiple entries), then all res
758
862
 
759
863
  Arrays are not necessary for single values
760
864
 
761
- ## `delete_before:`, `delete_after:`
865
+ ## `delete_before:`, `delete_after:`, `delete_before_last:`, `delete_after_last:`
762
866
 
763
867
  Can be used in the [`transforms:`](#transforms) list (or anywhere `transforms:` is able to be omitted).
764
868
 
765
- Each entry is a literal string, and _if present_ the string and everything before/after will be removed from the incoming value (if it's not present, this transform will continue to the next transform/result unmodified). if it's present multiple times then it will always be everything before/after the first substring match
869
+ Each entry is a literal string, and _if present_ the string and everything before/after will be removed from the incoming value (if it's not present, this transform will continue to the next transform/result unmodified).
870
+
871
+ - `delete_before:` will delete everything before and including the _first_ occurrence
872
+ - `delete_after:` will delete everything after and including the _first_ occurrence
873
+ - `delete_before_last:` will delete everything before and including the _last_ occurrence
874
+ - `delete_after_last:` will delete everything after and including the _last_ occurrence
766
875
 
767
876
  if multiple transform results are possible (from multiple entries), then all results will be used.
768
877
 
@@ -36,3 +36,9 @@ Define which paths use the custom precompiler using [`precompile:`](https://gith
36
36
  reference the name of the precompiler with `format: { custom: MyNotRubyPrecompiler }`
37
37
 
38
38
  If the `precompile` method raises any errors while precompiling, a warning will be printed to stderr and the file will be skipped
39
+
40
+ To test the output of the precompiler you can use the `--view-compiled` flag with a list of paths or path patterns, like so:
41
+
42
+ `bundle exec leftovers --view-compiled '*.not_rb'`
43
+
44
+
data/leftovers.gemspec CHANGED
@@ -44,6 +44,7 @@ Gem::Specification.new do |spec|
44
44
  spec.add_development_dependency 'rubocop-performance'
45
45
  spec.add_development_dependency 'rubocop-rake'
46
46
  spec.add_development_dependency 'rubocop-rspec'
47
+ spec.add_development_dependency 'ruby-prof'
47
48
  spec.add_development_dependency 'simplecov', '>= 0.18.5'
48
49
  spec.add_development_dependency 'simplecov-console'
49
50
  spec.add_development_dependency 'slim'
@@ -51,7 +52,7 @@ Gem::Specification.new do |spec|
51
52
  spec.add_development_dependency 'tty_string', '>= 0.2.1'
52
53
 
53
54
  spec.add_development_dependency 'spellr', '>= 0.8.1'
54
- spec.add_dependency 'fast_ignore', '>= 0.15.1'
55
+ spec.add_dependency 'fast_ignore', '>= 0.17.0'
55
56
  spec.add_dependency 'parallel'
56
57
  spec.add_dependency 'parser'
57
58
  end
@@ -0,0 +1,36 @@
1
+ # https://guides.rubyonrails.org/action_cable_overview.html
2
+ gems:
3
+ - activesupport
4
+ - actionpack
5
+
6
+ keep:
7
+ # https://guides.rubyonrails.org/action_cable_overview.html#server-side-components-channels-subscriptions
8
+ # https://api.rubyonrails.org/v7.0.2.2/classes/ActionCable/Channel/Base.html#method-i-subscribed
9
+ # it's for overriding
10
+ - subscribed
11
+ # https://api.rubyonrails.org/v7.0.2.2/classes/ActionCable/Channel/Base.html#method-i-unsubscribed
12
+ # it's for overriding
13
+ - unsubscribed
14
+
15
+ # https://api.rubyonrails.org/v7.0.2.2/classes/ActionCable/Channel/Base.html
16
+ - type: Method
17
+ privacy: public
18
+ path: /app/channels/**/*_channel.rb
19
+
20
+ - path: /app/channels/**/*_channel.rb
21
+ has_suffix: Channel
22
+
23
+
24
+ dynamic:
25
+ # https://guides.rubyonrails.org/action_cable_overview.html#connection-setup
26
+ # it's just attr_accessor
27
+ - names: identified_by
28
+ define:
29
+ - argument: '*'
30
+ transforms:
31
+ - original
32
+ - add_suffix: '='
33
+ call:
34
+ - argument: '*'
35
+ add_prefix: '@'
36
+
@@ -0,0 +1,28 @@
1
+ # https://guides.rubyonrails.org/action_mailbox_basics.html
2
+
3
+ gems:
4
+ - activesupport
5
+ - activerecord
6
+ - activestorage
7
+ - activejob
8
+ - actionpack
9
+
10
+ keep:
11
+ # https://api.rubyonrails.org/v7.0.2.2/classes/ActionMailbox/Base.html
12
+ # Overwrite in subclasses
13
+ - process
14
+
15
+ dynamic:
16
+ # https://api.rubyonrails.org/v7.0.2.2/classes/ActionMailbox/Base.html
17
+ - names: [before_processing, after_processing, around_processing]
18
+ calls: ['*', if, unless]
19
+
20
+ # https://guides.rubyonrails.org/action_mailbox_basics.html#examples
21
+ # i'm guessing a lot about how this is supposed to work
22
+ - names: routing
23
+ calls:
24
+ arguments: '**'
25
+ camelize: true
26
+ add_suffix: Mailbox
27
+
28
+
@@ -1,22 +1,98 @@
1
- # THIS IS INCOMPLETE (you can help by expanding it)
2
- # rails is _really complicated_ and has a lot of magic which calls methods for you.
3
- # some is currently impossible to handle (with_options).
4
- # Some is just corners of rails I haven't hit yet.
1
+ # https://edgeapi.rubyonrails.org/classes/ActionMailer/Base.html
2
+ # https://guides.rubyonrails.org/action_mailer_basics.html
3
+ gems:
4
+ - activesupport
5
+ - actionpack
6
+ - actionview
7
+ - activejob
8
+
5
9
  keep:
10
+ # https://guides.rubyonrails.org/action_mailer_basics.html
6
11
  - has_suffix: Preview
7
- path: '**/mailers/previews/**/*_preview.rb'
12
+ path: '/test/mailers/previews/**/*_preview.rb'
13
+ # this path is the default
14
+ # if it's overridden copy this into .leftovers.yml with
15
+ # whatever it was overridden as
16
+
17
+ # https://guides.rubyonrails.org/action_mailer_basics.html#intercepting-emails
8
18
  - delivering_email
19
+
20
+ # https://guides.rubyonrails.org/action_mailer_basics.html#observing-emails
9
21
  - delivered_email
10
22
 
11
23
  dynamic:
12
- - names:
13
- - deliver_now
14
- - deliver_later
15
- calls:
16
- value:
17
- deliver
24
+ # https://guides.rubyonrails.org/action_mailer_basics.html#action-mailer-callbacks
18
25
  - names:
19
26
  - before_action
20
27
  - after_action
21
28
  - around_action
22
29
  calls: ['*', if, unless]
30
+
31
+ # https://guides.rubyonrails.org/action_mailer_basics.html#intercepting-emails
32
+ - names: interceptors=
33
+ has_receiver: action_mailer
34
+ calls:
35
+ argument: 0
36
+ nested: '*'
37
+ split: '::'
38
+
39
+ # https://edgeapi.rubyonrails.org/classes/ActionMailer/Base.html#method-c-register_interceptor
40
+ - names: register_interceptor
41
+ calls:
42
+ argument: 0
43
+ camelize: true
44
+ split: '::'
45
+
46
+ # https://edgeapi.rubyonrails.org/classes/ActionMailer/Base.html#method-c-register_interceptors
47
+ - names: register_interceptors
48
+ calls:
49
+ argument: '*'
50
+ camelize: true
51
+ split: '::'
52
+
53
+
54
+ # https://guides.rubyonrails.org/action_mailer_basics.html#observing-emails
55
+ - names: observers=
56
+ has_receiver: action_mailer
57
+ calls:
58
+ argument: 0
59
+ nested: '*'
60
+ split: '::'
61
+
62
+ # https://edgeapi.rubyonrails.org/classes/ActionMailer/Base.html#method-c-register_observer
63
+ - names: register_observer
64
+ calls:
65
+ argument: 0
66
+ camelize: true
67
+ split: '::'
68
+
69
+ # https://edgeapi.rubyonrails.org/classes/ActionMailer/Base.html#method-c-register_observers
70
+ - names: register_observers
71
+ calls:
72
+ argument: '*'
73
+ camelize: true
74
+ split: '::'
75
+
76
+ # https://edgeapi.rubyonrails.org/classes/ActionMailer/DeliveryMethods/ClassMethods.html#method-i-add_delivery_method
77
+ # i'm going to skip this because it immediately calls the method it creates
78
+ # - names: add_delivery_method
79
+ # defines:
80
+ # argument: 0
81
+ # transforms:
82
+ # - add_suffix: _settings=
83
+ # - add_suffix: _settings
84
+ # calls:
85
+ # argument: 0
86
+ # add_suffix: _settings=
87
+
88
+ # https://edgeapi.rubyonrails.org/classes/ActionMailer/Previews/ClassMethods.html#method-i-register_preview_interceptor
89
+ - names: register_preview_interceptor
90
+ calls:
91
+ argument: 0
92
+ split: '::'
93
+
94
+ # https://edgeapi.rubyonrails.org/classes/ActionMailer/Previews/ClassMethods.html#method-i-register_preview_interceptors
95
+ - names: register_preview_interceptors
96
+ calls:
97
+ argument: '*'
98
+ split: '::'