leftovers 0.6.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -3
  3. data/README.md +8 -7
  4. data/docs/Configuration.md +241 -105
  5. data/docs/Custom-Precompilers.md +44 -0
  6. data/leftovers.gemspec +3 -2
  7. data/lib/config/actioncable.yml +36 -4
  8. data/lib/config/actionmailbox.yml +28 -0
  9. data/lib/config/actionmailer.yml +92 -16
  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 +397 -86
  16. data/lib/config/activestorage.yml +26 -0
  17. data/lib/config/activesupport.yml +168 -25
  18. data/lib/config/haml.yml +4 -2
  19. data/lib/config/leftovers.yml +48 -0
  20. data/lib/config/rails.yml +8 -4
  21. data/lib/config/railties.yml +18 -0
  22. data/lib/config/ruby.yml +473 -57
  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 +39 -91
  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 +3 -42
  50. data/lib/leftovers/config_loader/argument_position_schema.rb +13 -0
  51. data/lib/leftovers/config_loader/argumentless_transform_schema.rb +21 -0
  52. data/lib/leftovers/config_loader/array_schema.rb +53 -0
  53. data/lib/leftovers/config_loader/attribute.rb +56 -0
  54. data/lib/leftovers/config_loader/built_in_precompiler_schema.rb +13 -0
  55. data/lib/leftovers/config_loader/document_schema.rb +49 -0
  56. data/lib/leftovers/config_loader/dynamic_schema.rb +18 -0
  57. data/lib/leftovers/config_loader/has_argument_schema.rb +13 -0
  58. data/lib/leftovers/config_loader/has_value_schema.rb +22 -0
  59. data/lib/leftovers/config_loader/inherit_schema_attributes.rb +22 -0
  60. data/lib/leftovers/config_loader/keep_test_only_schema.rb +13 -0
  61. data/lib/leftovers/config_loader/keyword_argument_schema.rb +13 -0
  62. data/lib/leftovers/config_loader/node.rb +106 -0
  63. data/lib/leftovers/config_loader/object_schema.rb +117 -0
  64. data/lib/leftovers/config_loader/precompile_schema.rb +12 -0
  65. data/lib/leftovers/config_loader/precompiler_schema.rb +11 -0
  66. data/lib/leftovers/config_loader/privacy_processor_schema.rb +10 -0
  67. data/lib/leftovers/config_loader/privacy_schema.rb +15 -0
  68. data/lib/leftovers/config_loader/regexp_schema.rb +27 -0
  69. data/lib/leftovers/config_loader/require_schema.rb +11 -0
  70. data/lib/leftovers/config_loader/rule_pattern_schema.rb +20 -0
  71. data/lib/leftovers/config_loader/scalar_argument_schema.rb +14 -0
  72. data/lib/leftovers/config_loader/scalar_value_schema.rb +22 -0
  73. data/lib/leftovers/config_loader/schema.rb +33 -0
  74. data/lib/leftovers/config_loader/string_enum_schema.rb +62 -0
  75. data/lib/leftovers/config_loader/string_pattern_schema.rb +14 -0
  76. data/lib/leftovers/config_loader/string_schema.rb +14 -0
  77. data/lib/leftovers/config_loader/string_value_processor_schema.rb +11 -0
  78. data/lib/leftovers/config_loader/suggester.rb +22 -0
  79. data/lib/leftovers/config_loader/transform_schema.rb +32 -0
  80. data/lib/leftovers/config_loader/true_schema.rb +18 -0
  81. data/lib/leftovers/config_loader/value_matcher_condition_schema.rb +13 -0
  82. data/lib/leftovers/config_loader/value_matcher_schema.rb +21 -0
  83. data/lib/leftovers/config_loader/value_or_array_schema.rb +34 -0
  84. data/lib/leftovers/config_loader/value_or_object_schema.rb +40 -0
  85. data/lib/leftovers/config_loader/value_processor_schema.rb +14 -0
  86. data/lib/leftovers/config_loader/value_type_schema.rb +17 -0
  87. data/lib/leftovers/config_loader.rb +93 -0
  88. data/lib/leftovers/definition_collection.rb +37 -0
  89. data/lib/leftovers/definition_node.rb +6 -17
  90. data/lib/leftovers/definition_node_set.rb +19 -0
  91. data/lib/leftovers/definition_to_add.rb +31 -0
  92. data/lib/leftovers/file.rb +13 -55
  93. data/lib/leftovers/file_collector/comments_processor.rb +57 -0
  94. data/lib/leftovers/file_collector/node_processor.rb +131 -0
  95. data/lib/leftovers/file_collector.rb +62 -202
  96. data/lib/leftovers/file_list.rb +3 -2
  97. data/lib/leftovers/matcher_builders/and.rb +26 -9
  98. data/lib/leftovers/matcher_builders/and_not.rb +7 -5
  99. data/lib/leftovers/matcher_builders/name.rb +18 -17
  100. data/lib/leftovers/matcher_builders/node.rb +60 -30
  101. data/lib/leftovers/matcher_builders/node_has_argument.rb +48 -52
  102. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +16 -11
  103. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +29 -15
  104. data/lib/leftovers/matcher_builders/node_pair_key.rb +16 -0
  105. data/lib/leftovers/matcher_builders/node_privacy.rb +13 -0
  106. data/lib/leftovers/matcher_builders/node_type.rb +11 -11
  107. data/lib/leftovers/matcher_builders/node_value.rb +44 -25
  108. data/lib/leftovers/matcher_builders/or.rb +64 -49
  109. data/lib/leftovers/matcher_builders/path.rb +3 -1
  110. data/lib/leftovers/matcher_builders/string_pattern.rb +14 -5
  111. data/lib/leftovers/matcher_builders.rb +2 -1
  112. data/lib/leftovers/matchers/all.rb +4 -0
  113. data/lib/leftovers/matchers/and.rb +4 -0
  114. data/lib/leftovers/matchers/any.rb +2 -0
  115. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +7 -4
  116. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +5 -4
  117. data/lib/leftovers/matchers/node_has_positional_argument.rb +5 -1
  118. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +6 -1
  119. data/lib/leftovers/matchers/node_has_receiver.rb +4 -0
  120. data/lib/leftovers/matchers/node_is_proc.rb +13 -0
  121. data/lib/leftovers/matchers/node_name.rb +9 -3
  122. data/lib/leftovers/matchers/node_pair_key.rb +23 -0
  123. data/lib/leftovers/matchers/node_pair_value.rb +7 -3
  124. data/lib/leftovers/matchers/node_path.rb +7 -3
  125. data/lib/leftovers/matchers/node_privacy.rb +23 -0
  126. data/lib/leftovers/matchers/node_scalar_value.rb +6 -1
  127. data/lib/leftovers/matchers/node_type.rb +7 -3
  128. data/lib/leftovers/matchers/not.rb +2 -0
  129. data/lib/leftovers/matchers/or.rb +2 -0
  130. data/lib/leftovers/matchers/path.rb +21 -0
  131. data/lib/leftovers/matchers.rb +4 -1
  132. data/lib/leftovers/merged_config.rb +40 -75
  133. data/lib/leftovers/parser.rb +7 -4
  134. data/lib/leftovers/precompilers/erb.rb +22 -0
  135. data/lib/leftovers/precompilers/haml.rb +15 -0
  136. data/lib/leftovers/precompilers/json.rb +27 -0
  137. data/lib/leftovers/precompilers/precompiler.rb +28 -0
  138. data/lib/leftovers/precompilers/slim.rb +15 -0
  139. data/lib/leftovers/precompilers/yaml.rb +75 -0
  140. data/lib/leftovers/precompilers.rb +50 -0
  141. data/lib/leftovers/processor_builders/action.rb +69 -42
  142. data/lib/leftovers/processor_builders/add_prefix.rb +18 -10
  143. data/lib/leftovers/processor_builders/add_suffix.rb +18 -10
  144. data/lib/leftovers/processor_builders/argument.rb +28 -14
  145. data/lib/leftovers/processor_builders/dynamic.rb +57 -17
  146. data/lib/leftovers/processor_builders/each.rb +83 -11
  147. data/lib/leftovers/processor_builders/itself.rb +2 -2
  148. data/lib/leftovers/processor_builders/keyword.rb +9 -9
  149. data/lib/leftovers/processor_builders/keyword_argument.rb +4 -2
  150. data/lib/leftovers/processor_builders/receiver.rb +13 -0
  151. data/lib/leftovers/processor_builders/transform.rb +55 -44
  152. data/lib/leftovers/processor_builders/transform_chain.rb +16 -8
  153. data/lib/leftovers/processor_builders/transform_set.rb +16 -32
  154. data/lib/leftovers/processor_builders/value.rb +4 -4
  155. data/lib/leftovers/processor_builders.rb +1 -3
  156. data/lib/leftovers/processors/add_call.rb +14 -0
  157. data/lib/leftovers/processors/add_definition_node.rb +16 -0
  158. data/lib/leftovers/processors/add_dynamic_prefix.rb +29 -0
  159. data/lib/leftovers/processors/add_dynamic_suffix.rb +29 -0
  160. data/lib/leftovers/{value_processors → processors}/add_prefix.rb +7 -3
  161. data/lib/leftovers/{value_processors → processors}/add_suffix.rb +7 -3
  162. data/lib/leftovers/processors/append_sym.rb +13 -0
  163. data/lib/leftovers/{value_processors → processors}/camelize.rb +7 -3
  164. data/lib/leftovers/{value_processors → processors}/capitalize.rb +7 -3
  165. data/lib/leftovers/{value_processors → processors}/deconstantize.rb +7 -3
  166. data/lib/leftovers/{value_processors → processors}/delete_after.rb +9 -5
  167. data/lib/leftovers/processors/delete_after_last.rb +26 -0
  168. data/lib/leftovers/processors/delete_before.rb +27 -0
  169. data/lib/leftovers/processors/delete_before_last.rb +27 -0
  170. data/lib/leftovers/{value_processors → processors}/delete_prefix.rb +7 -3
  171. data/lib/leftovers/{value_processors → processors}/delete_suffix.rb +7 -3
  172. data/lib/leftovers/{value_processors → processors}/demodulize.rb +7 -3
  173. data/lib/leftovers/{value_processors → processors}/downcase.rb +7 -3
  174. data/lib/leftovers/processors/each.rb +25 -0
  175. data/lib/leftovers/processors/each_for_definition_set.rb +33 -0
  176. data/lib/leftovers/processors/each_keyword.rb +29 -0
  177. data/lib/leftovers/processors/each_keyword_argument.rb +29 -0
  178. data/lib/leftovers/processors/each_positional_argument.rb +27 -0
  179. data/lib/leftovers/processors/each_positional_argument_from.rb +30 -0
  180. data/lib/leftovers/processors/eval.rb +16 -0
  181. data/lib/leftovers/processors/itself.rb +21 -0
  182. data/lib/leftovers/{value_processors → processors}/keyword_argument.rb +9 -11
  183. data/lib/leftovers/processors/match_current_node.rb +26 -0
  184. data/lib/leftovers/processors/match_matched_node.rb +26 -0
  185. data/lib/leftovers/{value_processors → processors}/parameterize.rb +7 -3
  186. data/lib/leftovers/{value_processors → processors}/placeholder.rb +5 -4
  187. data/lib/leftovers/{value_processors → processors}/pluralize.rb +7 -3
  188. data/lib/leftovers/{value_processors → processors}/positional_argument.rb +8 -6
  189. data/lib/leftovers/processors/receiver.rb +24 -0
  190. data/lib/leftovers/{value_processors → processors}/replace_value.rb +7 -3
  191. data/lib/leftovers/processors/set_default_privacy.rb +21 -0
  192. data/lib/leftovers/processors/set_privacy.rb +23 -0
  193. data/lib/leftovers/{value_processors → processors}/singularize.rb +7 -3
  194. data/lib/leftovers/{value_processors → processors}/split.rb +8 -4
  195. data/lib/leftovers/{value_processors → processors}/swapcase.rb +7 -3
  196. data/lib/leftovers/{value_processors → processors}/titleize.rb +7 -3
  197. data/lib/leftovers/{value_processors → processors}/underscore.rb +7 -3
  198. data/lib/leftovers/{value_processors → processors}/upcase.rb +7 -3
  199. data/lib/leftovers/processors.rb +49 -0
  200. data/lib/leftovers/rake_task.rb +1 -1
  201. data/lib/leftovers/version.rb +1 -1
  202. data/lib/leftovers.rb +55 -20
  203. metadata +159 -72
  204. data/lib/leftovers/config_validator/error_processor.rb +0 -196
  205. data/lib/leftovers/config_validator/schema_hash.rb +0 -551
  206. data/lib/leftovers/config_validator.rb +0 -61
  207. data/lib/leftovers/dynamic_processors/call.rb +0 -21
  208. data/lib/leftovers/dynamic_processors/call_definition.rb +0 -27
  209. data/lib/leftovers/dynamic_processors/definition.rb +0 -22
  210. data/lib/leftovers/dynamic_processors/each.rb +0 -19
  211. data/lib/leftovers/dynamic_processors/null.rb +0 -9
  212. data/lib/leftovers/dynamic_processors.rb +0 -11
  213. data/lib/leftovers/erb.rb +0 -20
  214. data/lib/leftovers/haml.rb +0 -21
  215. data/lib/leftovers/json.rb +0 -28
  216. data/lib/leftovers/matcher_builders/node_pair_name.rb +0 -18
  217. data/lib/leftovers/matchers/predicate.rb +0 -19
  218. data/lib/leftovers/processor_builders/each_action.rb +0 -51
  219. data/lib/leftovers/processor_builders/each_dynamic.rb +0 -54
  220. data/lib/leftovers/processor_builders/each_for_definition_set.rb +0 -36
  221. data/lib/leftovers/slim.rb +0 -21
  222. data/lib/leftovers/value_processors/add_dynamic_prefix.rb +0 -31
  223. data/lib/leftovers/value_processors/add_dynamic_suffix.rb +0 -31
  224. data/lib/leftovers/value_processors/delete_before.rb +0 -22
  225. data/lib/leftovers/value_processors/each.rb +0 -21
  226. data/lib/leftovers/value_processors/each_for_definition_set.rb +0 -29
  227. data/lib/leftovers/value_processors/each_keyword.rb +0 -27
  228. data/lib/leftovers/value_processors/each_keyword_argument.rb +0 -27
  229. data/lib/leftovers/value_processors/each_positional_argument.rb +0 -24
  230. data/lib/leftovers/value_processors/itself.rb +0 -17
  231. data/lib/leftovers/value_processors/keyword.rb +0 -32
  232. data/lib/leftovers/value_processors/return_definition.rb +0 -22
  233. data/lib/leftovers/value_processors/return_string.rb +0 -14
  234. data/lib/leftovers/value_processors.rb +0 -40
  235. data/lib/leftovers/yaml.rb +0 -73
@@ -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)
@@ -59,12 +55,17 @@ List filenames/paths that you want to include
59
55
  Unlike other `paths:` configuration, each entry is **not** the gitignore pattern format.
60
56
  Instead it is strings that can be passed directly to ruby's `require` method (relative paths should start with `./`).
61
57
 
62
- Missing files/gems will be a warning, but not a LoadError.
58
+ ```yml
59
+ require: ./config/initializers/my_other_inflections_file
60
+ ```
63
61
 
64
- By default, the default [`gems: active_support`]() config `require: activesupport` and `gems: rails` will `require: ./config/initializers/inflections`
62
+ Missing files/gems will be a warning, but not a LoadError.
63
+ To avoid seeing the warning if the file isn't there use `quiet:`.
65
64
 
66
65
  ```yml
67
- require: ./config/initializers/my_other_inflections_file
66
+ requires:
67
+ - 'active_support/inflections' # will warn if it's missing
68
+ - quiet: './config/initializers/inflections' # will say nothing
68
69
  ```
69
70
 
70
71
  Arrays are not necessary for single values
@@ -83,59 +84,36 @@ test_paths:
83
84
 
84
85
  Arrays are not necessary for single values
85
86
 
86
- ## `haml_paths:`
87
-
88
- list filenames/paths of test directories that are in the haml format
89
- Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
87
+ ## `precompile:`
90
88
 
91
89
  ```yml
92
- haml_paths:
93
- - '*.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
94
96
  ```
95
97
 
96
- Arrays are not necessary for single values. `*.haml` is recognized by default
98
+ Define any precompilers and the paths they affect.
97
99
 
98
- ## `slim_paths:`
100
+ `paths:` are defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
99
101
 
100
- list filenames/paths of test directories that are in the slim format
101
- Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
102
-
103
- ```yml
104
- slim_paths:
105
- - '*.slim'
106
- ```
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)
107
104
 
108
- Arrays are not necessary for single values. `*.slim` is recognized by default
105
+ See [Custom precompilers](https://github.com/robotdana/leftovers/blob/main/docs/Custom-Precompilers.md) for more details on the custom precompiler class
109
106
 
110
- ## `erb_paths:`
111
-
112
- list filenames/paths of test directories that are in the erb format
113
- Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
114
-
115
- ```yml
116
- erb_paths:
117
- - '*.erb'
118
- ```
119
-
120
- Arrays are not necessary for single values. `*.erb` is recognized by default
121
-
122
- ## `yaml_paths:`
107
+ Arrays are not necessary for single values.
123
108
 
124
- list filenames/paths of test directories that are in the yaml format
125
- Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
109
+ ### `format: yaml`
126
110
 
127
- ```yml
128
- include:
129
- - 'config/*.yml'
130
- yaml_paths:
131
- - '*.yml'
132
- ```
133
-
134
- 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.
135
113
 
136
114
  so you could, e.g. read the class name out of a yaml document like:
137
115
 
138
- ```yml
116
+ ```
139
117
  class_name: MyClass
140
118
  ```
141
119
 
@@ -154,21 +132,11 @@ dynamic:
154
132
 
155
133
  [`nested:`](#nested) may be useful for more complex yaml structures
156
134
 
157
- ## `json_paths:`
158
-
159
- list filenames/paths of test directories that are in the json format
160
- Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
161
-
162
- ```yml
163
- include:
164
- - 'config/*.json'
165
- json_paths:
166
- - '*.json'
167
- ```
135
+ ### `format: json`
168
136
 
169
- 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.
170
138
 
171
- 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:
172
140
 
173
141
  ```json
174
142
  { "class_name": "MyClass" }
@@ -213,11 +181,15 @@ Each entry can be a string (an exact match for a method, constant, or variable n
213
181
  or the properties from `names:`
214
182
  - [`has_prefix:`](#has_prefix)
215
183
  - [`has_suffix:`](#has_suffix)
216
- - [`matches:`](#matches) (can't be used in the same entry as `has_prefix:` or `has_suffix:`)
184
+ - [`matches:`](#matches)
217
185
  - [`paths:`](#paths)
218
186
  - [`has_arguments:`](#has_arguments)
219
187
  - [`has_receiver:`](#has_receiver)
220
- - [`unless`](#unless)
188
+ - [`type:`](#type)
189
+ - [`privacy:`](#privacy)
190
+ - [`unless:`](#unless)
191
+ - [`all:`](#any-all)
192
+ - [`any:`](#any-all)
221
193
 
222
194
  Arrays are not necessary for single values
223
195
 
@@ -228,7 +200,6 @@ keep:
228
200
  - ssl_configured?
229
201
  - has_suffix: Helper
230
202
  path: /app/helpers
231
- ...
232
203
  ```
233
204
 
234
205
  Alternatively, you can mark method/constants/variables in-place using [magic comments](https://github.com/robotdana/leftovers/tree/main/README.md#magic-comments).
@@ -242,10 +213,15 @@ Each entry can be a string (an exact match for a method, constant, or variable n
242
213
  or the properties from `names:`
243
214
  - [`has_prefix:`](#has_prefix)
244
215
  - [`has_suffix:`](#has_suffix)
245
- - [`matches:`](#matches) (can't be used in the same entry as `has_prefix:` or `has_suffix:`)
216
+ - [`matches:`](#matches)
246
217
  - [`paths:`](#paths)
247
218
  - [`has_arguments:`](#has_arguments)
219
+ - [`has_receiver:`](#has_receiver)
220
+ - [`type:`](#type)
221
+ - [`privacy:`](#privacy)
248
222
  - [`unless`](#unless)
223
+ - [`all:`](#any-all)
224
+ - [`any:`](#any-all)
249
225
 
250
226
  Arrays are not necessary for single values
251
227
 
@@ -256,7 +232,6 @@ test_only:
256
232
  - ssl_configured?
257
233
  - has_suffix: Helper
258
234
  path: /app/helpers
259
- ...
260
235
  ```
261
236
 
262
237
  Alternatively, you can mark method/constants/variables in-place using [magic comments](https://github.com/robotdana/leftovers/tree/main/README.md#magic-comments).
@@ -271,15 +246,22 @@ Each entry must have at least one of the following properties to restrict which
271
246
  - [`has_prefix:`](#has_prefix)
272
247
  - [`has_suffix:`](#has_suffix)
273
248
  - [`matches:`](#matches)
249
+ - [`document: true`](#document-true)
274
250
  - [`paths:`](#paths)
275
251
  - [`has_arguments:`](#has_arguments)
276
252
  - [`has_receiver:`](#has_receiver)
253
+ - [`type:`](#type)
254
+ - [`privacy:`](#privacy)
277
255
  - [`unless:`](#unless)
278
- - [`document: true`](#document-true)
256
+ - [`all:`](#any-all)
257
+ - [`any:`](#any-all)
279
258
 
280
- And must have one or both of
259
+ And must have at least one of
281
260
  - ['calls:`](#calls-defines)
282
261
  - [`defines:`](#calls-defines)
262
+ - [`set_privacy:](#set-privacy)
263
+ - [`set_default_privacy:`](#set-default-privacy)
264
+ - [`eval:`](#eval)
283
265
 
284
266
  Arrays are not necessary for single values.
285
267
 
@@ -294,7 +276,6 @@ dynamic:
294
276
  calls:
295
277
  arguments: '*'
296
278
  add_prefix: '@'
297
- ...
298
279
  ```
299
280
 
300
281
  ## `names:`
@@ -305,7 +286,7 @@ This is a list of methods/constants/variables, and can be used in [`dynamic:`](#
305
286
  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
287
  - [`has_prefix:`](#has_prefix)
307
288
  - [`has_suffix:`](#has_suffix)
308
- - [`matches:`](#matches) (this can't be used in the same entry as `has_prefix:` or `has_suffix:`)
289
+ - [`matches:`](#matches)
309
290
 
310
291
  Arrays are not necessary for single values
311
292
 
@@ -317,7 +298,6 @@ keep:
317
298
  - names:
318
299
  has_suffix: Helper
319
300
  path: /app/helpers
320
- ...
321
301
  ```
322
302
 
323
303
  ## `has_prefix:`, `has_suffix:`
@@ -379,7 +359,7 @@ Instructs to consider the whole document. this is useful when parsing [YAML](#ya
379
359
  e.g.
380
360
 
381
361
  ```yml
382
- includes: /config/roles.yml
362
+ include_paths: /config/roles.yml
383
363
  dynamic:
384
364
  - document: true
385
365
  path: /config/roles.yml
@@ -390,7 +370,7 @@ dynamic:
390
370
  ```
391
371
 
392
372
  will parse "config/roles.yml"
393
- ```yml
373
+ ```
394
374
  - build_house
395
375
  - drive_car
396
376
  ```
@@ -402,7 +382,7 @@ and consider it to have created methods like `can_build_house?` and `can_drive_c
402
382
  ## `calls:`, `defines:`
403
383
  _aliases `call:`, `define:`_
404
384
 
405
- At least one of these must be used in each entry in [`dynamic:`](#dynamic)
385
+ These may be used as entries in [`dynamic:`](#dynamic)
406
386
 
407
387
  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
388
 
@@ -421,8 +401,10 @@ also there may be any or all of these properties:
421
401
  - [`add_suffix:`](#add_prefix-add_suffix)
422
402
  - [`delete_prefix:`](#delete_prefix-delete_suffix)
423
403
  - [`delete_suffix:`](#delete_prefix-delete_suffix)
424
- - [`delete_before:`](#delete_before-delete_after)
425
- - [`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)
426
408
  - [`split:`](#split)
427
409
  - [`downcase:`](#downcase-upcase-capitalize-swapcase)
428
410
  - [`upcase:`](#downcase-upcase-capitalize-swapcase)
@@ -445,15 +427,73 @@ dynamic:
445
427
  - send
446
428
  calls:
447
429
  arguments:
448
- - 1
430
+ - 0
449
431
  ```
450
432
  is equivalent to:
451
433
  ```yml
452
434
  dynamic:
453
435
  name: send
454
- calls: 1
436
+ calls: 0
455
437
  ```
456
438
 
439
+ ## `set_privacy:`
440
+
441
+ Set privacy has the same requirements as [`calls:` & `defines:`](#calls-defines).
442
+
443
+ additional it requires a `to:` with one of either `private`, `public`, or `protected`.
444
+
445
+ For example, from the ruby config:
446
+ ```yml
447
+ dynamic:
448
+ name: private_class_method
449
+ has_argument: 0
450
+ set_privacy:
451
+ argument: '*'
452
+ to: private
453
+ ```
454
+
455
+ which sets all methods named by the arguments to the privacy_class_method method to private.
456
+
457
+ these methods could then be filtered using the [`privacy:`](#privacy) method in another [`dynamic:`](#dynamic) or [`keep:`](#keep) rule.
458
+
459
+ Leftovers limits this to only affect methods defined in the same file.
460
+
461
+ ## `set_default_privacy:`
462
+
463
+ 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))
464
+
465
+ For example, from the default ruby config:
466
+ ```yml
467
+ dynamic:
468
+ name: private
469
+ unless:
470
+ has_argument: 0
471
+ set_default_privacy: private
472
+ ```
473
+
474
+ these methods could then be filtered using the [`privacy:`](#privacy) method in another [`dynamic:`](#dynamic) or [`keep:`](#keep) rule.
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
+
457
497
  ## `arguments:`
458
498
  _alias `argument:`_
459
499
 
@@ -494,11 +534,11 @@ When the keyword argument **keywords** are the thing being called.
494
534
  ```yml
495
535
  dynamic:
496
536
  - name: validates
497
- calls:
498
- - arguments: '*'
499
- - keywords: '**'
500
- camelize: true
501
- add_suffix: Validator
537
+ calls:
538
+ - arguments: '*'
539
+ - keywords: '**'
540
+ camelize: true
541
+ add_suffix: Validator
502
542
  ```
503
543
  ```ruby
504
544
  validates :first_name, :surname, presence: true
@@ -517,15 +557,52 @@ This can be used in:
517
557
  Each entry can be any of:
518
558
  - `'*'`: matches all positional arguments/array positions
519
559
  - `'**'`: matches all keyword arguments/hash positions
520
- - 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
521
563
  - any other String: matches the keyword argument or hash value, where the keyword/hash key string or symbol
522
564
  - or have at least one of the following properties to match the keyword/hash key string or symbol:
523
565
  - [`has_prefix:`](#has_prefix)
524
566
  - [`has_suffix:`](#has_suffix)
525
- - [`matches:`](#matches) (this can't be used in the same entry as `has_prefix:` or `has_suffix:`)
567
+ - [`matches:`](#matches)
526
568
 
527
569
  Arrays are not necessary for single values
528
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
+
529
606
  ## `has_value:`, `has_receiver:`
530
607
 
531
608
  filter [`arguments:`](#arguments), [`has_arguments:`](#has_arguments), and [`keywords:`](#keywords), by the argument/assigned/receiver value
@@ -533,10 +610,10 @@ filter [`arguments:`](#arguments), [`has_arguments:`](#has_arguments), and [`key
533
610
  Each entry can be one of
534
611
  - `true`, `false`, `nil`, or an Integer. matches the literal value
535
612
  - 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:
613
+ - or have at least one of the following properties to match the name:
537
614
  - [`has_prefix:`](#has_prefix)
538
615
  - [`has_suffix:`](#has_suffix)
539
- - [`matches:`](#matches) (this can't be used in the same entry as `has_prefix:` or `has_suffix:`)
616
+ - [`matches:`](#matches)
540
617
  - or have at least one of the following properties to match within an array or hash:
541
618
  - [`at`](#at)
542
619
  - [`has_value`](#has_value_has_receiver)
@@ -545,17 +622,35 @@ Each entry can be one of
545
622
  - or have the following property to match the receiver
546
623
  - [`has_receiver`](#has_value_has_receiver)
547
624
 
625
+ ## `privacy:`
626
+
627
+ filter [`dynamic:`](#dynamic) and [`keep:`](#keep) by method/constant privacy
628
+
629
+ e.g.
630
+
631
+ ```yml
632
+ keep:
633
+ - path: '**/generators/**/*_generator.rb'
634
+ privacy: public
635
+ type: Method
636
+ ```
637
+
638
+ considers all public methods defined in rails generators to be called.
639
+
548
640
  ## `type:`
549
641
 
550
- Filter [`has_value`](#has_value_has_receiver), by the argument/assigned value type
642
+ Filter by the literal type
551
643
 
552
644
  Each entry can be one of
553
- - `'String'`
554
- - `'Symbol'`
555
- - `'Integer'`
556
- - `'Float'`
557
- - `'Array'`
558
- - `'Hash'`
645
+ - `'String'` a literal string, defined with "" or '' (not String.new)
646
+ - `'Symbol'` a literal symbol
647
+ - `'Integer'` a literal integer
648
+ - `'Float'` a literal float
649
+ - `'Array'` a literal array defined with [] (not Array.new)
650
+ - `'Hash'` a literal hash, defined with {} (not Hash.new)
651
+ - `'Proc'` a literal proc/lambda, defined with lambda {}, proc {}, or -> {} (not Proc.new)
652
+ - `'Method'` a method call or definition defined with def, (not define_method {})
653
+ - `'Constant'` a constant assignment, or a literal module or class defined with keywords, (not Module/Class.new)
559
654
 
560
655
  Arrays are not necessary for single values
561
656
 
@@ -579,7 +674,7 @@ e.g.
579
674
  dynamic:
580
675
  - names: my_method
581
676
  calls:
582
- argument: 2
677
+ argument: 1
583
678
  nested:
584
679
  argument: '*'
585
680
  nested:
@@ -616,6 +711,7 @@ The original method/constant/variable name will continue to be called/defined as
616
711
  This can be used in [`calls:`](#calls-defines) and [`defines:`](#calls-defines)
617
712
 
618
713
  ```yml
714
+ dynamic:
619
715
  - name:
620
716
  has_prefix: be_
621
717
  calls:
@@ -634,6 +730,7 @@ Will supply a literal string value method/constant/variable name itself as the t
634
730
  This can be used in [`calls:`](#calls-defines) and [`defines:`](#calls-defines).
635
731
 
636
732
  ```yml
733
+ dynamic:
637
734
  - name: perform_async
638
735
  calls:
639
736
  value: perform
@@ -656,8 +753,10 @@ Each entry can have a string that is an argumentless transform (e.g. capitalize)
656
753
  - [`add_suffix:`](#add_prefix-add_suffix)
657
754
  - [`delete_prefix:`](#delete_prefix-delete_suffix)
658
755
  - [`delete_suffix:`](#delete_prefix-delete_suffix)
659
- - [`delete_before:`](#delete_before-delete_after)
660
- - [`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)
661
760
  - [`split:`](#split)
662
761
  - [`downcase`](#downcase-upcase-capitalize-swapcase) or `downcase: true`
663
762
  - [`upcase`](#downcase-upcase-capitalize-swapcase) or `upcase: true`
@@ -672,26 +771,43 @@ Each entry can have a string that is an argumentless transform (e.g. capitalize)
672
771
  - [`deconstantize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `deconstantize: true`
673
772
  - [`titleize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `titleize: true`
674
773
  - [`parameterize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `parameterize: true`
774
+ - `transforms:`
675
775
 
676
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.
677
777
 
678
778
  ```yml
779
+ dynamic:
679
780
  - name: attribute
680
- defines:
681
- - argument: 1
682
- transforms:
683
- - original # no transformation
684
- - add_suffix: '?'
685
- - add_suffix: '='
781
+ defines:
782
+ - argument: 0
783
+ transforms:
784
+ - original # no transformation
785
+ - add_suffix: '?'
786
+ - add_suffix: '='
686
787
  ```
687
788
  ```ruby
688
789
  attribute :first_name
689
790
  ```
690
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.
691
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
+
692
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.
693
808
 
694
809
  ```yml
810
+ dynamic:
695
811
  - name: attr_writer
696
812
  defines:
697
813
  - argument: '*'
@@ -702,6 +818,21 @@ attr_writer :first_name, :surname
702
818
  ```
703
819
  will count as the definition of `first_name=`, and `surname=`
704
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
+
705
836
  ## `original`
706
837
 
707
838
  Can be used in the [`transforms:`](#transforms) list, if used in a hash `true` can be used as a placeholder value
@@ -731,11 +862,16 @@ if multiple transform results are possible (from multiple entries), then all res
731
862
 
732
863
  Arrays are not necessary for single values
733
864
 
734
- ## `delete_before:`, `delete_after:`
865
+ ## `delete_before:`, `delete_after:`, `delete_before_last:`, `delete_after_last:`
735
866
 
736
867
  Can be used in the [`transforms:`](#transforms) list (or anywhere `transforms:` is able to be omitted).
737
868
 
738
- 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
739
875
 
740
876
  if multiple transform results are possible (from multiple entries), then all results will be used.
741
877
 
@@ -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
+
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'
@@ -43,6 +44,7 @@ Gem::Specification.new do |spec|
43
44
  spec.add_development_dependency 'rubocop-performance'
44
45
  spec.add_development_dependency 'rubocop-rake'
45
46
  spec.add_development_dependency 'rubocop-rspec'
47
+ spec.add_development_dependency 'ruby-prof'
46
48
  spec.add_development_dependency 'simplecov', '>= 0.18.5'
47
49
  spec.add_development_dependency 'simplecov-console'
48
50
  spec.add_development_dependency 'slim'
@@ -50,8 +52,7 @@ Gem::Specification.new do |spec|
50
52
  spec.add_development_dependency 'tty_string', '>= 0.2.1'
51
53
 
52
54
  spec.add_development_dependency 'spellr', '>= 0.8.1'
53
- spec.add_dependency 'fast_ignore', '>= 0.15.1'
54
- spec.add_dependency 'json_schemer'
55
+ spec.add_dependency 'fast_ignore', '>= 0.17.0'
55
56
  spec.add_dependency 'parallel'
56
57
  spec.add_dependency 'parser'
57
58
  end