leftovers 0.7.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (227) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -0
  3. data/README.md +8 -7
  4. data/docs/Configuration.md +187 -93
  5. data/docs/Custom-Precompilers.md +44 -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 -32
  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 +422 -89
  16. data/lib/config/activestorage.yml +26 -0
  17. data/lib/config/activesupport.yml +167 -24
  18. data/lib/config/haml.yml +4 -2
  19. data/lib/config/leftovers.yml +48 -0
  20. data/lib/config/rails.yml +7 -3
  21. data/lib/config/railties.yml +7 -0
  22. data/lib/config/ruby.yml +439 -95
  23. data/lib/config/slim.yml +4 -2
  24. data/lib/config/test-unit.yml +8 -0
  25. data/lib/leftovers/ast/array_node.rb +12 -0
  26. data/lib/leftovers/ast/block_node.rb +12 -0
  27. data/lib/leftovers/ast/builder.rb +24 -5
  28. data/lib/leftovers/ast/casgn_node.rb +20 -0
  29. data/lib/leftovers/ast/const_node.rb +15 -0
  30. data/lib/leftovers/ast/def_node.rb +15 -0
  31. data/lib/leftovers/ast/defs_node.rb +15 -0
  32. data/lib/leftovers/ast/false_node.rb +24 -0
  33. data/lib/leftovers/ast/has_arguments.rb +31 -0
  34. data/lib/leftovers/ast/hash_node.rb +17 -0
  35. data/lib/leftovers/ast/module_node.rb +16 -0
  36. data/lib/leftovers/ast/nil_node.rb +23 -0
  37. data/lib/leftovers/ast/node.rb +33 -90
  38. data/lib/leftovers/ast/numeric_node.rb +22 -0
  39. data/lib/leftovers/ast/send_node.rb +25 -0
  40. data/lib/leftovers/ast/str_node.rb +24 -0
  41. data/lib/leftovers/ast/sym_node.rb +25 -0
  42. data/lib/leftovers/ast/true_node.rb +24 -0
  43. data/lib/leftovers/ast/var_node.rb +14 -0
  44. data/lib/leftovers/ast/vasgn_node.rb +20 -0
  45. data/lib/leftovers/ast.rb +18 -0
  46. data/lib/leftovers/cli.rb +12 -1
  47. data/lib/leftovers/collector.rb +2 -1
  48. data/lib/leftovers/comparable_instance.rb +18 -0
  49. data/lib/leftovers/config.rb +2 -18
  50. data/lib/leftovers/config_loader/argument_position_schema.rb +5 -3
  51. data/lib/leftovers/config_loader/array_schema.rb +53 -0
  52. data/lib/leftovers/config_loader/attribute.rb +36 -10
  53. data/lib/leftovers/config_loader/built_in_precompiler_schema.rb +13 -0
  54. data/lib/leftovers/config_loader/document_schema.rb +33 -5
  55. data/lib/leftovers/config_loader/dynamic_schema.rb +1 -0
  56. data/lib/leftovers/config_loader/has_argument_schema.rb +2 -2
  57. data/lib/leftovers/config_loader/has_receiver_schema.rb +15 -0
  58. data/lib/leftovers/config_loader/has_value_schema.rb +7 -3
  59. data/lib/leftovers/config_loader/inherit_schema_attributes.rb +22 -0
  60. data/lib/leftovers/config_loader/keep_test_only_schema.rb +2 -2
  61. data/lib/leftovers/config_loader/keyword_argument_schema.rb +13 -0
  62. data/lib/leftovers/config_loader/object_schema.rb +33 -105
  63. data/lib/leftovers/config_loader/precompile_schema.rb +12 -0
  64. data/lib/leftovers/config_loader/precompiler_schema.rb +11 -0
  65. data/lib/leftovers/config_loader/privacy_processor_schema.rb +0 -2
  66. data/lib/leftovers/config_loader/regexp_schema.rb +27 -0
  67. data/lib/leftovers/config_loader/require_schema.rb +3 -3
  68. data/lib/leftovers/config_loader/rule_pattern_schema.rb +3 -1
  69. data/lib/leftovers/config_loader/scalar_value_schema.rb +8 -0
  70. data/lib/leftovers/config_loader/schema.rb +12 -0
  71. data/lib/leftovers/config_loader/string_enum_schema.rb +1 -1
  72. data/lib/leftovers/config_loader/string_pattern_schema.rb +3 -3
  73. data/lib/leftovers/config_loader/string_value_processor_schema.rb +2 -2
  74. data/lib/leftovers/config_loader/transform_schema.rb +10 -6
  75. data/lib/leftovers/config_loader/value_matcher_condition_schema.rb +13 -0
  76. data/lib/leftovers/config_loader/value_matcher_schema.rb +6 -3
  77. data/lib/leftovers/config_loader/value_or_array_schema.rb +2 -32
  78. data/lib/leftovers/config_loader/value_or_object_schema.rb +40 -0
  79. data/lib/leftovers/config_loader/value_processor_schema.rb +4 -4
  80. data/lib/leftovers/config_loader.rb +15 -3
  81. data/lib/leftovers/definition_collection.rb +37 -0
  82. data/lib/leftovers/definition_node.rb +8 -14
  83. data/lib/leftovers/definition_node_set.rb +10 -2
  84. data/lib/leftovers/file.rb +8 -54
  85. data/lib/leftovers/file_collector/comments_processor.rb +57 -0
  86. data/lib/leftovers/file_collector/node_processor.rb +131 -0
  87. data/lib/leftovers/file_collector.rb +56 -223
  88. data/lib/leftovers/file_list.rb +3 -2
  89. data/lib/leftovers/matcher_builders/and.rb +26 -9
  90. data/lib/leftovers/matcher_builders/and_not.rb +7 -5
  91. data/lib/leftovers/matcher_builders/name.rb +18 -17
  92. data/lib/leftovers/matcher_builders/node.rb +60 -34
  93. data/lib/leftovers/matcher_builders/node_has_argument.rb +48 -52
  94. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +16 -11
  95. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +29 -15
  96. data/lib/leftovers/matcher_builders/node_has_receiver.rb +12 -3
  97. data/lib/leftovers/matcher_builders/node_pair_key.rb +16 -0
  98. data/lib/leftovers/matcher_builders/node_type.rb +10 -10
  99. data/lib/leftovers/matcher_builders/node_value.rb +46 -25
  100. data/lib/leftovers/matcher_builders/or.rb +64 -49
  101. data/lib/leftovers/matcher_builders/path.rb +3 -1
  102. data/lib/leftovers/matcher_builders/string_pattern.rb +1 -1
  103. data/lib/leftovers/matcher_builders.rb +1 -1
  104. data/lib/leftovers/matchers/all.rb +4 -0
  105. data/lib/leftovers/matchers/and.rb +4 -0
  106. data/lib/leftovers/matchers/any.rb +2 -0
  107. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +7 -4
  108. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +5 -4
  109. data/lib/leftovers/matchers/node_has_any_receiver.rb +13 -0
  110. data/lib/leftovers/matchers/node_has_positional_argument.rb +5 -1
  111. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +6 -1
  112. data/lib/leftovers/matchers/node_has_receiver.rb +4 -0
  113. data/lib/leftovers/matchers/node_is_proc.rb +13 -0
  114. data/lib/leftovers/matchers/node_name.rb +9 -3
  115. data/lib/leftovers/matchers/node_pair_key.rb +23 -0
  116. data/lib/leftovers/matchers/node_pair_value.rb +7 -3
  117. data/lib/leftovers/matchers/node_path.rb +7 -3
  118. data/lib/leftovers/matchers/node_privacy.rb +7 -3
  119. data/lib/leftovers/matchers/node_scalar_value.rb +6 -1
  120. data/lib/leftovers/matchers/node_type.rb +7 -3
  121. data/lib/leftovers/matchers/not.rb +2 -0
  122. data/lib/leftovers/matchers/or.rb +2 -0
  123. data/lib/leftovers/matchers/path.rb +21 -0
  124. data/lib/leftovers/matchers.rb +4 -1
  125. data/lib/leftovers/merged_config.rb +28 -47
  126. data/lib/leftovers/parser.rb +7 -4
  127. data/lib/leftovers/precompilers/erb.rb +22 -0
  128. data/lib/leftovers/precompilers/haml.rb +15 -0
  129. data/lib/leftovers/precompilers/json.rb +27 -0
  130. data/lib/leftovers/precompilers/precompiler.rb +28 -0
  131. data/lib/leftovers/precompilers/slim.rb +15 -0
  132. data/lib/leftovers/precompilers/yaml.rb +75 -0
  133. data/lib/leftovers/precompilers.rb +50 -0
  134. data/lib/leftovers/processor_builders/action.rb +69 -42
  135. data/lib/leftovers/processor_builders/add_prefix.rb +18 -10
  136. data/lib/leftovers/processor_builders/add_suffix.rb +18 -10
  137. data/lib/leftovers/processor_builders/argument.rb +28 -14
  138. data/lib/leftovers/processor_builders/dynamic.rb +37 -31
  139. data/lib/leftovers/processor_builders/each.rb +83 -11
  140. data/lib/leftovers/processor_builders/itself.rb +2 -2
  141. data/lib/leftovers/processor_builders/keyword.rb +9 -9
  142. data/lib/leftovers/processor_builders/keyword_argument.rb +4 -2
  143. data/lib/leftovers/processor_builders/receiver.rb +13 -0
  144. data/lib/leftovers/processor_builders/transform.rb +55 -44
  145. data/lib/leftovers/processor_builders/transform_chain.rb +16 -8
  146. data/lib/leftovers/processor_builders/transform_set.rb +16 -32
  147. data/lib/leftovers/processor_builders/value.rb +4 -4
  148. data/lib/leftovers/processor_builders.rb +1 -3
  149. data/lib/leftovers/processors/add_call.rb +14 -0
  150. data/lib/leftovers/processors/add_definition_node.rb +16 -0
  151. data/lib/leftovers/processors/add_dynamic_prefix.rb +29 -0
  152. data/lib/leftovers/processors/add_dynamic_suffix.rb +29 -0
  153. data/lib/leftovers/{value_processors → processors}/add_prefix.rb +7 -3
  154. data/lib/leftovers/{value_processors → processors}/add_suffix.rb +7 -3
  155. data/lib/leftovers/processors/append_sym.rb +13 -0
  156. data/lib/leftovers/{value_processors → processors}/camelize.rb +7 -3
  157. data/lib/leftovers/{value_processors → processors}/capitalize.rb +7 -3
  158. data/lib/leftovers/{value_processors → processors}/deconstantize.rb +7 -3
  159. data/lib/leftovers/{value_processors → processors}/delete_after.rb +9 -5
  160. data/lib/leftovers/processors/delete_after_last.rb +26 -0
  161. data/lib/leftovers/processors/delete_before.rb +27 -0
  162. data/lib/leftovers/processors/delete_before_last.rb +27 -0
  163. data/lib/leftovers/{value_processors → processors}/delete_prefix.rb +7 -3
  164. data/lib/leftovers/{value_processors → processors}/delete_suffix.rb +7 -3
  165. data/lib/leftovers/{value_processors → processors}/demodulize.rb +7 -3
  166. data/lib/leftovers/{value_processors → processors}/downcase.rb +7 -3
  167. data/lib/leftovers/processors/each.rb +25 -0
  168. data/lib/leftovers/processors/each_for_definition_set.rb +33 -0
  169. data/lib/leftovers/processors/each_keyword.rb +29 -0
  170. data/lib/leftovers/processors/each_keyword_argument.rb +29 -0
  171. data/lib/leftovers/processors/each_positional_argument.rb +27 -0
  172. data/lib/leftovers/processors/each_positional_argument_from.rb +30 -0
  173. data/lib/leftovers/processors/eval.rb +16 -0
  174. data/lib/leftovers/processors/itself.rb +21 -0
  175. data/lib/leftovers/{value_processors → processors}/keyword_argument.rb +9 -11
  176. data/lib/leftovers/processors/match_current_node.rb +26 -0
  177. data/lib/leftovers/processors/match_matched_node.rb +26 -0
  178. data/lib/leftovers/{value_processors → processors}/parameterize.rb +7 -3
  179. data/lib/leftovers/{value_processors → processors}/placeholder.rb +5 -4
  180. data/lib/leftovers/{value_processors → processors}/pluralize.rb +7 -3
  181. data/lib/leftovers/{value_processors → processors}/positional_argument.rb +8 -6
  182. data/lib/leftovers/processors/receiver.rb +24 -0
  183. data/lib/leftovers/{value_processors → processors}/replace_value.rb +7 -3
  184. data/lib/leftovers/processors/set_default_privacy.rb +21 -0
  185. data/lib/leftovers/processors/set_privacy.rb +23 -0
  186. data/lib/leftovers/{value_processors → processors}/singularize.rb +7 -3
  187. data/lib/leftovers/{value_processors → processors}/split.rb +8 -4
  188. data/lib/leftovers/{value_processors → processors}/swapcase.rb +7 -3
  189. data/lib/leftovers/{value_processors → processors}/titleize.rb +7 -3
  190. data/lib/leftovers/{value_processors → processors}/underscore.rb +7 -3
  191. data/lib/leftovers/{value_processors → processors}/upcase.rb +7 -3
  192. data/lib/leftovers/processors.rb +49 -0
  193. data/lib/leftovers/rake_task.rb +1 -1
  194. data/lib/leftovers/version.rb +1 -1
  195. data/lib/leftovers.rb +34 -8
  196. metadata +116 -58
  197. data/lib/leftovers/dynamic_processors/call.rb +0 -22
  198. data/lib/leftovers/dynamic_processors/call_definition.rb +0 -34
  199. data/lib/leftovers/dynamic_processors/definition.rb +0 -27
  200. data/lib/leftovers/dynamic_processors/each.rb +0 -19
  201. data/lib/leftovers/dynamic_processors/null.rb +0 -9
  202. data/lib/leftovers/dynamic_processors/set_default_privacy.rb +0 -18
  203. data/lib/leftovers/dynamic_processors/set_privacy.rb +0 -23
  204. data/lib/leftovers/dynamic_processors.rb +0 -13
  205. data/lib/leftovers/erb.rb +0 -20
  206. data/lib/leftovers/haml.rb +0 -21
  207. data/lib/leftovers/json.rb +0 -28
  208. data/lib/leftovers/matcher_builders/node_pair_name.rb +0 -18
  209. data/lib/leftovers/matchers/predicate.rb +0 -19
  210. data/lib/leftovers/processor_builders/each_action.rb +0 -51
  211. data/lib/leftovers/processor_builders/each_dynamic.rb +0 -54
  212. data/lib/leftovers/processor_builders/each_for_definition_set.rb +0 -36
  213. data/lib/leftovers/slim.rb +0 -21
  214. data/lib/leftovers/value_processors/add_dynamic_prefix.rb +0 -31
  215. data/lib/leftovers/value_processors/add_dynamic_suffix.rb +0 -31
  216. data/lib/leftovers/value_processors/delete_before.rb +0 -22
  217. data/lib/leftovers/value_processors/each.rb +0 -21
  218. data/lib/leftovers/value_processors/each_for_definition_set.rb +0 -26
  219. data/lib/leftovers/value_processors/each_keyword.rb +0 -27
  220. data/lib/leftovers/value_processors/each_keyword_argument.rb +0 -27
  221. data/lib/leftovers/value_processors/each_positional_argument.rb +0 -24
  222. data/lib/leftovers/value_processors/itself.rb +0 -17
  223. data/lib/leftovers/value_processors/keyword.rb +0 -32
  224. data/lib/leftovers/value_processors/return_definition_node.rb +0 -14
  225. data/lib/leftovers/value_processors/return_sym.rb +0 -14
  226. data/lib/leftovers/value_processors.rb +0 -40
  227. data/lib/leftovers/yaml.rb +0 -73
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f27830ef42bcbcec33a78126a3b47582fa394714e1d137e802cd5ab166e35df5
4
- data.tar.gz: a111ed33a8345fe8dc5d43cb92206d52cbc47a03bc8e961baee8558d677542b6
3
+ metadata.gz: f2cb691dc74d8b0d43765f899ea718a4d06c1ba8fa36ea3a68c44ece27531920
4
+ data.tar.gz: e24ade3f01a888de2e9438736d71b0e4f2d159a6783b3278e8ec7e58e7c8c626
5
5
  SHA512:
6
- metadata.gz: e14c6c1b74d4c13ebcbb4d1184d50257d6aacaf05e8e6708282633f61ea1988374156880d66bb26a037bf4b67b58381246f12357bdaa99ff9248db620d94c152
7
- data.tar.gz: 34e766e6ca2374858ee6da35e924287641bc4441d8f642e4d08285a0066185aa865724567b90f91de34b17f340f3f182e9b3f326c5fc63bf6abc414c0dc058b3
6
+ metadata.gz: a734ec1916762c5bc51fc212bfc254eb3d4083c968e6bcd128aa0c10ee9085762c6edbd86eb8afd3dd17ac5fa8b883d343bf34df3a3caaea1b84db5bc720bfaa
7
+ data.tar.gz: 7b80b90518a6a3e45aa3739394c18f4c7884ea07d75021dc919c62d23d6d110714c9969ab78b8078d6c219bfd9289a821bb4b828bc4e248a82a63f235cb7758f
data/CHANGELOG.md CHANGED
@@ -1,3 +1,42 @@
1
+ # v0.10.0
2
+ - Fixed an issue with t.belongs_to (within the migration generated by rails active_storage:install - thanks @veganstraightedge)
3
+ - this was two issues:
4
+ 1. it was raising an error because the DefinitionNode didn't act enough like an AST::Node, now it does
5
+ 2. this should never have been defining anything anyway as the activerecord method was being assumed to be used, now if there's an explicit receiver for belongs_to/has_many etc, don't consider them the active record association methods.
6
+
7
+ - now `has_receiver: true` and `has_receiver: false/nil` act differently, they refer to the presence or absence of any receiver, instead of the receiver being literally true or false or nil.
8
+ - to have the previous behaviour, use the new `has_receiver: { literal: true }` or `literal: false` or `literal: null`
9
+
10
+ # v0.9.0
11
+ - Automatically test the config examples in the documentation, and fix the errors
12
+ - simplify the `type: Proc` matcher
13
+ - Update FastIgnore dependency, make fewer filesystem calls
14
+ - Comprehensively describe all of ruby core and rails
15
+ This required/revealed a number of additions to the config
16
+ - Improve the performance of large config files by squash the config matching more
17
+ - Add `names:` and `has_arguments:` to `has_value:`.
18
+ - Fix error when positional `has_arguments:`/`has_value: at:` checks a node without arguments
19
+ - Add `eval` as a processing type, alongside `calls:` and `defines:`, this will process allow processing literal calls to instance_eval etc.
20
+ - Allow calling or defining based on the `receiver:`
21
+ - `all: []` & `any: []` arguments to dynamic/keep/test_only
22
+ - add `arguments: 1+` or `has_arguments: { at: 1+, has_value: true }` to match arguments from that position onward
23
+ - 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.
24
+ - allow `has_arguments.at` and `arguments:` to have a `type:` to distinguish between e.g. symbol keys and string keys.
25
+ - Add a way to test custom precompilers with --view-compiled [PATH_PATTERNS...]
26
+
27
+ # v0.8.0
28
+ - Allow custom precompilers
29
+ ```yml
30
+ require: './path/to/my_precompiler'
31
+ precompile:
32
+ - paths: '*.myCustomFormat'
33
+ format: { custom: 'MyPrecompiler' }
34
+ ```
35
+ the built in precompilers have moved into this system too, with `format: haml` etc. `haml_paths` etc are now deprecated
36
+ - a lot of refactoring, which revealed some edge cases i was handling
37
+ - collect a call to :my_method= with receiver&.my_method ||= (and += etc)
38
+ - if `add_prefix:` or `add_suffix:` points to another argument for a name that we can't use because it's a variable, it now just don't return the value, rather than returning the value but without the affix
39
+
1
40
  # v0.7.0
2
41
  - Rewrite the config parser/validation
3
42
  - to provide clearer error messages with line numbers and everything
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
 
@@ -166,6 +166,7 @@ Its presence is optional and all of these settings are optional.
166
166
  - [`exclude_paths:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#exclude_paths)
167
167
  - [`test_paths:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#test_paths)
168
168
  - [`requires:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#requires)
169
+ - [`precompile:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#precompile)
169
170
  - [`gems:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#gems)
170
171
  - [`keep:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#keep)
171
172
  - [`test_only:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#test_only)
@@ -200,7 +201,7 @@ To install this gem onto your local machine, run `bundle exec rake install`.
200
201
 
201
202
  Bug reports and pull requests are welcome on GitHub at https://github.com/robotdana/leftovers.
202
203
 
203
- 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.
204
205
  The file should be named `[rubygems name].yml` and its structure is identical to the [project config](#configuration)
205
206
 
206
207
  ## License
@@ -6,11 +6,7 @@ Its presence is optional and all of these settings are optional.
6
6
  - [`include_paths:`](#include_paths)
7
7
  - [`exclude_paths:`](#exclude_paths)
8
8
  - [`test_paths:`](#test_paths)
9
- - [`haml_paths:`](#haml_paths)
10
- - [`slim_paths:`](#slim_paths)
11
- - [`erb_paths:`](#erb_paths)
12
- - [`yaml_paths:`](#yaml_paths)
13
- - [`json_paths:`](#json_paths)
9
+ - [`precompile:`](#precompile)
14
10
  - [`requires:`](#requires)
15
11
  - [`gems:`](#gems)
16
12
  - [`keep:`](#keep)
@@ -88,59 +84,36 @@ test_paths:
88
84
 
89
85
  Arrays are not necessary for single values
90
86
 
91
- ## `haml_paths:`
92
-
93
- list filenames/paths of test directories that are in the haml format
94
- Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
87
+ ## `precompile:`
95
88
 
96
89
  ```yml
97
- haml_paths:
98
- - '*.haml'
90
+ require: './path/my_project/my_precompiler'
91
+ precompile:
92
+ - paths: '*.myCustomFormat'
93
+ format: { custom: 'MyProject::MyPrecompiler' }
94
+ - paths: '*.my.json'
95
+ format: json
99
96
  ```
100
97
 
101
- Arrays are not necessary for single values. `*.haml` is recognized by default
98
+ Define any precompilers and the paths they affect.
102
99
 
103
- ## `slim_paths:`
104
-
105
- list filenames/paths of test directories that are in the slim format
106
- Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
107
-
108
- ```yml
109
- slim_paths:
110
- - '*.slim'
111
- ```
112
-
113
- Arrays are not necessary for single values. `*.slim` is recognized by default
114
-
115
- ## `erb_paths:`
116
-
117
- list filenames/paths of test directories that are in the erb format
118
- Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
119
-
120
- ```yml
121
- erb_paths:
122
- - '*.erb'
123
- ```
100
+ `paths:` are defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
124
101
 
125
- Arrays are not necessary for single values. `*.erb` is recognized by default
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
+ (use [`require:`](#requires) to have leftovers load its file)
126
104
 
127
- ## `yaml_paths:`
105
+ See [Custom precompilers](https://github.com/robotdana/leftovers/blob/main/docs/Custom-Precompilers.md) for more details on the custom precompiler class
128
106
 
129
- list filenames/paths of test directories that are in the yaml format
130
- Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
107
+ Arrays are not necessary for single values.
131
108
 
132
- ```yml
133
- include:
134
- - 'config/*.yml'
135
- yaml_paths:
136
- - '*.yml'
137
- ```
109
+ ### `format: yaml`
138
110
 
139
- These documents will consider yaml tags like `!ruby/class 'MyClass'` to be a call to `MyClass` and render the structure of the yaml as arguments for the [`document:true`](#document-true) rule.
111
+ The yaml precompiler considers yaml tags like `!ruby/class 'MyClass'` to be a call to `MyClass`.
112
+ and renders the structure of the yaml document as arguments for the [`document:true`](#document-true) rule.
140
113
 
141
114
  so you could, e.g. read the class name out of a yaml document like:
142
115
 
143
- ```yml
116
+ ```
144
117
  class_name: MyClass
145
118
  ```
146
119
 
@@ -159,21 +132,11 @@ dynamic:
159
132
 
160
133
  [`nested:`](#nested) may be useful for more complex yaml structures
161
134
 
162
- ## `json_paths:`
163
-
164
- list filenames/paths of test directories that are in the json format
165
- Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
166
-
167
- ```yml
168
- include:
169
- - 'config/*.json'
170
- json_paths:
171
- - '*.json'
172
- ```
135
+ ### `format: json`
173
136
 
174
- These documents render the structure of the yaml as arguments for the [`document:true`](#document-true) rule.
137
+ The json precompiler renders the structure of the json document as arguments for the [`document:true`](#document-true) rule.
175
138
 
176
- so you could, e.g. read the class name out of a yaml document like:
139
+ so you could, e.g. read the class name out of a json document like:
177
140
 
178
141
  ```json
179
142
  { "class_name": "MyClass" }
@@ -224,7 +187,9 @@ Each entry can be a string (an exact match for a method, constant, or variable n
224
187
  - [`has_receiver:`](#has_receiver)
225
188
  - [`type:`](#type)
226
189
  - [`privacy:`](#privacy)
227
- - [`unless`](#unless)
190
+ - [`unless:`](#unless)
191
+ - [`all:`](#any-all)
192
+ - [`any:`](#any-all)
228
193
 
229
194
  Arrays are not necessary for single values
230
195
 
@@ -235,7 +200,6 @@ keep:
235
200
  - ssl_configured?
236
201
  - has_suffix: Helper
237
202
  path: /app/helpers
238
- ...
239
203
  ```
240
204
 
241
205
  Alternatively, you can mark method/constants/variables in-place using [magic comments](https://github.com/robotdana/leftovers/tree/main/README.md#magic-comments).
@@ -252,7 +216,12 @@ Each entry can be a string (an exact match for a method, constant, or variable n
252
216
  - [`matches:`](#matches)
253
217
  - [`paths:`](#paths)
254
218
  - [`has_arguments:`](#has_arguments)
219
+ - [`has_receiver:`](#has_receiver)
220
+ - [`type:`](#type)
221
+ - [`privacy:`](#privacy)
255
222
  - [`unless`](#unless)
223
+ - [`all:`](#any-all)
224
+ - [`any:`](#any-all)
256
225
 
257
226
  Arrays are not necessary for single values
258
227
 
@@ -263,7 +232,6 @@ test_only:
263
232
  - ssl_configured?
264
233
  - has_suffix: Helper
265
234
  path: /app/helpers
266
- ...
267
235
  ```
268
236
 
269
237
  Alternatively, you can mark method/constants/variables in-place using [magic comments](https://github.com/robotdana/leftovers/tree/main/README.md#magic-comments).
@@ -278,17 +246,22 @@ Each entry must have at least one of the following properties to restrict which
278
246
  - [`has_prefix:`](#has_prefix)
279
247
  - [`has_suffix:`](#has_suffix)
280
248
  - [`matches:`](#matches)
249
+ - [`document: true`](#document-true)
281
250
  - [`paths:`](#paths)
282
251
  - [`has_arguments:`](#has_arguments)
283
252
  - [`has_receiver:`](#has_receiver)
253
+ - [`type:`](#type)
254
+ - [`privacy:`](#privacy)
284
255
  - [`unless:`](#unless)
285
- - [`document: true`](#document-true)
256
+ - [`all:`](#any-all)
257
+ - [`any:`](#any-all)
286
258
 
287
259
  And must have at least one of
288
260
  - ['calls:`](#calls-defines)
289
261
  - [`defines:`](#calls-defines)
290
262
  - [`set_privacy:](#set-privacy)
291
263
  - [`set_default_privacy:`](#set-default-privacy)
264
+ - [`eval:`](#eval)
292
265
 
293
266
  Arrays are not necessary for single values.
294
267
 
@@ -303,7 +276,6 @@ dynamic:
303
276
  calls:
304
277
  arguments: '*'
305
278
  add_prefix: '@'
306
- ...
307
279
  ```
308
280
 
309
281
  ## `names:`
@@ -326,7 +298,6 @@ keep:
326
298
  - names:
327
299
  has_suffix: Helper
328
300
  path: /app/helpers
329
- ...
330
301
  ```
331
302
 
332
303
  ## `has_prefix:`, `has_suffix:`
@@ -388,7 +359,7 @@ Instructs to consider the whole document. this is useful when parsing [YAML](#ya
388
359
  e.g.
389
360
 
390
361
  ```yml
391
- includes: /config/roles.yml
362
+ include_paths: /config/roles.yml
392
363
  dynamic:
393
364
  - document: true
394
365
  path: /config/roles.yml
@@ -399,7 +370,7 @@ dynamic:
399
370
  ```
400
371
 
401
372
  will parse "config/roles.yml"
402
- ```yml
373
+ ```
403
374
  - build_house
404
375
  - drive_car
405
376
  ```
@@ -430,8 +401,10 @@ also there may be any or all of these properties:
430
401
  - [`add_suffix:`](#add_prefix-add_suffix)
431
402
  - [`delete_prefix:`](#delete_prefix-delete_suffix)
432
403
  - [`delete_suffix:`](#delete_prefix-delete_suffix)
433
- - [`delete_before:`](#delete_before-delete_after)
434
- - [`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)
435
408
  - [`split:`](#split)
436
409
  - [`downcase:`](#downcase-upcase-capitalize-swapcase)
437
410
  - [`upcase:`](#downcase-upcase-capitalize-swapcase)
@@ -454,13 +427,13 @@ dynamic:
454
427
  - send
455
428
  calls:
456
429
  arguments:
457
- - 1
430
+ - 0
458
431
  ```
459
432
  is equivalent to:
460
433
  ```yml
461
434
  dynamic:
462
435
  name: send
463
- calls: 1
436
+ calls: 0
464
437
  ```
465
438
 
466
439
  ## `set_privacy:`
@@ -500,6 +473,27 @@ dynamic:
500
473
 
501
474
  these methods could then be filtered using the [`privacy:`](#privacy) method in another [`dynamic:`](#dynamic) or [`keep:`](#keep) rule.
502
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
+
503
497
  ## `arguments:`
504
498
  _alias `argument:`_
505
499
 
@@ -510,7 +504,7 @@ and when used in:
510
504
 
511
505
  It can have any of these properties:
512
506
  - [`at:`](#at)
513
- - [`has_value:`](#has_value_has_receiver)
507
+ - [`has_value:`](#has_value)
514
508
 
515
509
  Arrays are not necessary for single values and if the rule contains only `at:` it can be omitted, and the values moved up a level.
516
510
 
@@ -528,7 +522,7 @@ The method call/constant variable/assignment will be considered matching if it h
528
522
 
529
523
  It can have any of these properties:
530
524
  - [`at:`](#at)
531
- - [`has_value:`](#has_value_has_receiver)
525
+ - [`has_value:`](#has_value)
532
526
 
533
527
  Arrays are not necessary for single values and if the rule contains only `at:` it can be omitted, and the values moved up a level
534
528
 
@@ -540,11 +534,11 @@ When the keyword argument **keywords** are the thing being called.
540
534
  ```yml
541
535
  dynamic:
542
536
  - name: validates
543
- calls:
544
- - arguments: '*'
545
- - keywords: '**'
546
- camelize: true
547
- add_suffix: Validator
537
+ calls:
538
+ - arguments: '*'
539
+ - keywords: '**'
540
+ camelize: true
541
+ add_suffix: Validator
548
542
  ```
549
543
  ```ruby
550
544
  validates :first_name, :surname, presence: true
@@ -563,7 +557,9 @@ This can be used in:
563
557
  Each entry can be any of:
564
558
  - `'*'`: matches all positional arguments/array positions
565
559
  - `'**'`: matches all keyword arguments/hash positions
566
- - 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
567
563
  - any other String: matches the keyword argument or hash value, where the keyword/hash key string or symbol
568
564
  - or have at least one of the following properties to match the keyword/hash key string or symbol:
569
565
  - [`has_prefix:`](#has_prefix)
@@ -572,9 +568,44 @@ Each entry can be any of:
572
568
 
573
569
  Arrays are not necessary for single values
574
570
 
575
- ## `has_value:`, `has_receiver:`
571
+ ## `any:`, `all:`
576
572
 
577
- filter [`arguments:`](#arguments), [`has_arguments:`](#has_arguments), and [`keywords:`](#keywords), by the argument/assigned/receiver value
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
+
606
+ ## `has_value:`
607
+
608
+ filter [`arguments:`](#arguments), [`has_arguments:`](#has_arguments), and [`keywords:`](#keywords), by the argument/assigned value
578
609
 
579
610
  Each entry can be one of
580
611
  - `true`, `false`, `nil`, or an Integer. matches the literal value
@@ -585,11 +616,33 @@ Each entry can be one of
585
616
  - [`matches:`](#matches)
586
617
  - or have at least one of the following properties to match within an array or hash:
587
618
  - [`at`](#at)
588
- - [`has_value`](#has_value_has_receiver)
619
+ - [`has_value`](#has_value)
589
620
  - or have the following property to match the value type
590
621
  - [`type`](#type)
591
622
  - or have the following property to match the receiver
592
- - [`has_receiver`](#has_value_has_receiver)
623
+ - [`has_receiver`](#has_receiver)
624
+
625
+ ## `has_receiver:`
626
+
627
+ filter [`dynamic:`](#dynamic), and [`keep:`](#keep), by the receiver presence or value
628
+
629
+ Each entry can be one of
630
+ - `true`, `false`, matches the presence of any receiver or not
631
+ - an Integer. matches the literal value
632
+ - a String. matches the literal string or symbol value
633
+ - or have at least one of the following properties to match the name:
634
+ - [`has_prefix:`](#has_prefix)
635
+ - [`has_suffix:`](#has_suffix)
636
+ - [`matches:`](#matches)
637
+ - or have at least one of the following properties to match the literal value or match within an array or hash:
638
+ - [`at`](#at)
639
+ - [`has_value`](#has_value)
640
+ - or have the following property to match the value type
641
+ - [`type`](#type)
642
+ - or have the following property to match the receiver of the receiver
643
+ - [`has_receiver`](#has_receiver)
644
+ - or have the following property to match a literal true, false, or nil value:
645
+ - `literal: true`, or `literal: false`, or `literal: nil`
593
646
 
594
647
  ## `privacy:`
595
648
 
@@ -643,7 +696,7 @@ e.g.
643
696
  dynamic:
644
697
  - names: my_method
645
698
  calls:
646
- argument: 2
699
+ argument: 1
647
700
  nested:
648
701
  argument: '*'
649
702
  nested:
@@ -680,6 +733,7 @@ The original method/constant/variable name will continue to be called/defined as
680
733
  This can be used in [`calls:`](#calls-defines) and [`defines:`](#calls-defines)
681
734
 
682
735
  ```yml
736
+ dynamic:
683
737
  - name:
684
738
  has_prefix: be_
685
739
  calls:
@@ -698,6 +752,7 @@ Will supply a literal string value method/constant/variable name itself as the t
698
752
  This can be used in [`calls:`](#calls-defines) and [`defines:`](#calls-defines).
699
753
 
700
754
  ```yml
755
+ dynamic:
701
756
  - name: perform_async
702
757
  calls:
703
758
  value: perform
@@ -720,8 +775,10 @@ Each entry can have a string that is an argumentless transform (e.g. capitalize)
720
775
  - [`add_suffix:`](#add_prefix-add_suffix)
721
776
  - [`delete_prefix:`](#delete_prefix-delete_suffix)
722
777
  - [`delete_suffix:`](#delete_prefix-delete_suffix)
723
- - [`delete_before:`](#delete_before-delete_after)
724
- - [`delete_after:`](#delete_before-delete_after)
778
+ - [`delete_before:`](#delete_before-delete_after-delete_before_last-delete_after_last)
779
+ - [`delete_after:`](#delete_before-delete_after-delete_before_last-delete_after_last)
780
+ - [`delete_before_last:`](#delete_before-delete_after-delete_before_last-delete_after_last)
781
+ - [`delete_after_last:`](#delete_before-delete_after-delete_before_last-delete_after_last)
725
782
  - [`split:`](#split)
726
783
  - [`downcase`](#downcase-upcase-capitalize-swapcase) or `downcase: true`
727
784
  - [`upcase`](#downcase-upcase-capitalize-swapcase) or `upcase: true`
@@ -736,26 +793,43 @@ Each entry can have a string that is an argumentless transform (e.g. capitalize)
736
793
  - [`deconstantize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `deconstantize: true`
737
794
  - [`titleize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `titleize: true`
738
795
  - [`parameterize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `parameterize: true`
796
+ - `transforms:`
739
797
 
740
798
  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.
741
799
 
742
800
  ```yml
801
+ dynamic:
743
802
  - name: attribute
744
- defines:
745
- - argument: 1
746
- transforms:
747
- - original # no transformation
748
- - add_suffix: '?'
749
- - add_suffix: '='
803
+ defines:
804
+ - argument: 0
805
+ transforms:
806
+ - original # no transformation
807
+ - add_suffix: '?'
808
+ - add_suffix: '='
750
809
  ```
751
810
  ```ruby
752
811
  attribute :first_name
753
812
  ```
754
813
  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.
755
814
 
815
+ ```yml
816
+ dynamic:
817
+ - name: attr_accessor
818
+ defines:
819
+ - argument: '*'
820
+ - argument: '*'
821
+ transforms:
822
+ add_suffix: '='
823
+ ```
824
+ ```ruby
825
+ attr_accessor :first_name
826
+ ```
827
+ 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.
828
+
756
829
  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.
757
830
 
758
831
  ```yml
832
+ dynamic:
759
833
  - name: attr_writer
760
834
  defines:
761
835
  - argument: '*'
@@ -766,6 +840,21 @@ attr_writer :first_name, :surname
766
840
  ```
767
841
  will count as the definition of `first_name=`, and `surname=`
768
842
 
843
+ Multiple transform arguments will be applied sequentially
844
+ ```yml
845
+ dynamic:
846
+ - name: has_many
847
+ calls:
848
+ - argument: 0
849
+ singularize: true
850
+ camelize: true
851
+ split: '::'
852
+ ```
853
+ ```ruby
854
+ has_many :users
855
+ ```
856
+ counts as a call to `User`
857
+
769
858
  ## `original`
770
859
 
771
860
  Can be used in the [`transforms:`](#transforms) list, if used in a hash `true` can be used as a placeholder value
@@ -795,11 +884,16 @@ if multiple transform results are possible (from multiple entries), then all res
795
884
 
796
885
  Arrays are not necessary for single values
797
886
 
798
- ## `delete_before:`, `delete_after:`
887
+ ## `delete_before:`, `delete_after:`, `delete_before_last:`, `delete_after_last:`
799
888
 
800
889
  Can be used in the [`transforms:`](#transforms) list (or anywhere `transforms:` is able to be omitted).
801
890
 
802
- 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
891
+ 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).
892
+
893
+ - `delete_before:` will delete everything before and including the _first_ occurrence
894
+ - `delete_after:` will delete everything after and including the _first_ occurrence
895
+ - `delete_before_last:` will delete everything before and including the _last_ occurrence
896
+ - `delete_after_last:` will delete everything after and including the _last_ occurrence
803
897
 
804
898
  if multiple transform results are possible (from multiple entries), then all results will be used.
805
899
 
@@ -0,0 +1,44 @@
1
+ # Custom Precompilers
2
+
3
+ In addition to the built in precompilers, it's possible to add a custom precompiler
4
+
5
+ It must be a class or module with a singleton method `precompile`. take a string of whatever code it likes, and return a string of valid ruby.
6
+
7
+ ```ruby
8
+ require 'not_ruby' # require the gem that does the actual transformation
9
+
10
+ module MyNotRubyPrecompiler
11
+ def self.precompile(not_ruby_content)
12
+ # not_ruby_content is a string of (hopefully) valid precompilable code
13
+ NotRuby::Parser.parse(not_ruby_content).to_ruby # output a string of valid ruby
14
+ end
15
+ end
16
+ ```
17
+
18
+ See the [build in precompilers](https://github.com/robotdana/leftovers/tree/main/lib/precompilers) for other examples.
19
+
20
+ To configure the precompiler to be used by leftovers, add something similar to this to the `.leftovers.yml` file
21
+
22
+ ```yml
23
+ include_paths:
24
+ - 'lib/**/*.not_rb'
25
+ require: './path/to/my_not_ruby_precompiler'
26
+ precompile:
27
+ - paths: '*.not_rb'
28
+ format: { custom: MyNotRubyPrecompiler }
29
+ ```
30
+
31
+ Ensure any necessary extension patterns are added to to [`include_paths:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#include_paths) for those particular files you wish to check.
32
+
33
+ Require the custom precompiler using [`require:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#requires)
34
+
35
+ Define which paths use the custom precompiler using [`precompile:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#precompile),
36
+ reference the name of the precompiler with `format: { custom: MyNotRubyPrecompiler }`
37
+
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
+