leftovers 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/README.md +28 -45
  4. data/docs/Configuration.md +598 -0
  5. data/exe/leftovers +1 -1
  6. data/leftovers.gemspec +9 -6
  7. data/lib/config/attr_encrypted.yml +3 -4
  8. data/lib/config/audited.yml +9 -4
  9. data/lib/config/datagrid.yml +1 -1
  10. data/lib/config/flipper.yml +1 -3
  11. data/lib/config/graphql.yml +15 -13
  12. data/lib/config/okcomputer.yml +1 -3
  13. data/lib/config/parser.yml +89 -91
  14. data/lib/config/rails.yml +125 -107
  15. data/lib/config/redcarpet.yml +35 -38
  16. data/lib/config/rollbar.yml +1 -3
  17. data/lib/config/rspec.yml +18 -10
  18. data/lib/config/ruby.yml +40 -50
  19. data/lib/config/selenium-webdriver.yml +19 -21
  20. data/lib/config/sidekiq.yml +4 -8
  21. data/lib/config/will_paginate.yml +12 -14
  22. data/lib/leftovers.rb +38 -26
  23. data/lib/leftovers/ast.rb +8 -0
  24. data/lib/leftovers/ast/builder.rb +4 -4
  25. data/lib/leftovers/ast/node.rb +50 -77
  26. data/lib/leftovers/backports.rb +27 -23
  27. data/lib/leftovers/cli.rb +0 -3
  28. data/lib/leftovers/collector.rb +4 -8
  29. data/lib/leftovers/config.rb +19 -25
  30. data/lib/leftovers/config_validator.rb +60 -0
  31. data/lib/leftovers/config_validator/error_processor.rb +196 -0
  32. data/lib/leftovers/config_validator/schema_hash.rb +495 -0
  33. data/lib/leftovers/definition.rb +11 -36
  34. data/lib/leftovers/definition_set.rb +7 -17
  35. data/lib/leftovers/dynamic_processors.rb +11 -0
  36. data/lib/leftovers/dynamic_processors/call.rb +25 -0
  37. data/lib/leftovers/dynamic_processors/call_definition.rb +31 -0
  38. data/lib/leftovers/dynamic_processors/definition.rb +26 -0
  39. data/lib/leftovers/dynamic_processors/each.rb +19 -0
  40. data/lib/leftovers/dynamic_processors/null.rb +9 -0
  41. data/lib/leftovers/erb.rb +2 -2
  42. data/lib/leftovers/file.rb +3 -5
  43. data/lib/leftovers/file_collector.rb +65 -49
  44. data/lib/leftovers/file_list.rb +0 -1
  45. data/lib/leftovers/haml.rb +1 -1
  46. data/lib/leftovers/matcher_builders.rb +24 -0
  47. data/lib/leftovers/matcher_builders/and.rb +19 -0
  48. data/lib/leftovers/matcher_builders/and_not.rb +14 -0
  49. data/lib/leftovers/matcher_builders/argument_node_value.rb +21 -0
  50. data/lib/leftovers/matcher_builders/name.rb +29 -0
  51. data/lib/leftovers/matcher_builders/node.rb +40 -0
  52. data/lib/leftovers/matcher_builders/node_has_argument.rb +71 -0
  53. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +22 -0
  54. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +24 -0
  55. data/lib/leftovers/matcher_builders/node_name.rb +15 -0
  56. data/lib/leftovers/matcher_builders/node_pair_name.rb +18 -0
  57. data/lib/leftovers/matcher_builders/node_pair_value.rb +16 -0
  58. data/lib/leftovers/matcher_builders/node_path.rb +14 -0
  59. data/lib/leftovers/matcher_builders/node_type.rb +28 -0
  60. data/lib/leftovers/matcher_builders/or.rb +73 -0
  61. data/lib/leftovers/matcher_builders/path.rb +15 -0
  62. data/lib/leftovers/matcher_builders/string.rb +11 -0
  63. data/lib/leftovers/matcher_builders/string_pattern.rb +19 -0
  64. data/lib/leftovers/matcher_builders/unless.rb +13 -0
  65. data/lib/leftovers/matchers.rb +26 -0
  66. data/lib/leftovers/matchers/all.rb +25 -0
  67. data/lib/leftovers/matchers/and.rb +24 -0
  68. data/lib/leftovers/matchers/any.rb +27 -0
  69. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +28 -0
  70. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +25 -0
  71. data/lib/leftovers/matchers/node_has_positional_argument.rb +23 -0
  72. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +25 -0
  73. data/lib/leftovers/matchers/node_name.rb +23 -0
  74. data/lib/leftovers/matchers/node_pair_value.rb +23 -0
  75. data/lib/leftovers/matchers/node_path.rb +23 -0
  76. data/lib/leftovers/matchers/node_scalar_value.rb +25 -0
  77. data/lib/leftovers/matchers/node_type.rb +23 -0
  78. data/lib/leftovers/matchers/not.rb +23 -0
  79. data/lib/leftovers/matchers/or.rb +26 -0
  80. data/lib/leftovers/merged_config.rb +13 -8
  81. data/lib/leftovers/parser.rb +1 -4
  82. data/lib/leftovers/processor_builders.rb +22 -0
  83. data/lib/leftovers/processor_builders/action.rb +63 -0
  84. data/lib/leftovers/processor_builders/add_prefix.rb +20 -0
  85. data/lib/leftovers/processor_builders/add_suffix.rb +20 -0
  86. data/lib/leftovers/processor_builders/argument.rb +25 -0
  87. data/lib/leftovers/processor_builders/dynamic.rb +27 -0
  88. data/lib/leftovers/processor_builders/each.rb +36 -0
  89. data/lib/leftovers/processor_builders/each_action.rb +51 -0
  90. data/lib/leftovers/processor_builders/each_dynamic.rb +54 -0
  91. data/lib/leftovers/processor_builders/each_for_definition_set.rb +36 -0
  92. data/lib/leftovers/processor_builders/itself.rb +13 -0
  93. data/lib/leftovers/processor_builders/keyword.rb +24 -0
  94. data/lib/leftovers/processor_builders/keyword_argument.rb +14 -0
  95. data/lib/leftovers/processor_builders/transform.rb +55 -0
  96. data/lib/leftovers/processor_builders/transform_chain.rb +24 -0
  97. data/lib/leftovers/processor_builders/transform_set.rb +47 -0
  98. data/lib/leftovers/processor_builders/value.rb +13 -0
  99. data/lib/leftovers/rake_task.rb +1 -1
  100. data/lib/leftovers/reporter.rb +1 -1
  101. data/lib/leftovers/value_processors.rb +40 -0
  102. data/lib/leftovers/value_processors/add_dynamic_prefix.rb +31 -0
  103. data/lib/leftovers/value_processors/add_dynamic_suffix.rb +31 -0
  104. data/lib/leftovers/value_processors/add_prefix.rb +20 -0
  105. data/lib/leftovers/value_processors/add_suffix.rb +20 -0
  106. data/lib/leftovers/value_processors/camelize.rb +24 -0
  107. data/lib/leftovers/value_processors/capitalize.rb +19 -0
  108. data/lib/leftovers/value_processors/deconstantize.rb +24 -0
  109. data/lib/leftovers/value_processors/delete_after.rb +22 -0
  110. data/lib/leftovers/value_processors/delete_before.rb +22 -0
  111. data/lib/leftovers/value_processors/delete_prefix.rb +26 -0
  112. data/lib/leftovers/value_processors/delete_suffix.rb +26 -0
  113. data/lib/leftovers/value_processors/demodulize.rb +24 -0
  114. data/lib/leftovers/value_processors/downcase.rb +19 -0
  115. data/lib/leftovers/value_processors/each.rb +21 -0
  116. data/lib/leftovers/value_processors/each_for_definition_set.rb +33 -0
  117. data/lib/leftovers/value_processors/each_keyword.rb +27 -0
  118. data/lib/leftovers/value_processors/each_keyword_argument.rb +27 -0
  119. data/lib/leftovers/value_processors/each_positional_argument.rb +24 -0
  120. data/lib/leftovers/value_processors/itself.rb +17 -0
  121. data/lib/leftovers/value_processors/keyword.rb +36 -0
  122. data/lib/leftovers/value_processors/keyword_argument.rb +36 -0
  123. data/lib/leftovers/value_processors/parameterize.rb +24 -0
  124. data/lib/leftovers/value_processors/placeholder.rb +18 -0
  125. data/lib/leftovers/value_processors/pluralize.rb +24 -0
  126. data/lib/leftovers/value_processors/positional_argument.rb +26 -0
  127. data/lib/leftovers/value_processors/replace_value.rb +18 -0
  128. data/lib/leftovers/value_processors/return_definition.rb +24 -0
  129. data/lib/leftovers/value_processors/return_string.rb +14 -0
  130. data/lib/leftovers/value_processors/singularize.rb +24 -0
  131. data/lib/leftovers/value_processors/split.rb +22 -0
  132. data/lib/leftovers/value_processors/swapcase.rb +19 -0
  133. data/lib/leftovers/value_processors/titleize.rb +24 -0
  134. data/lib/leftovers/value_processors/underscore.rb +24 -0
  135. data/lib/leftovers/value_processors/upcase.rb +19 -0
  136. data/lib/leftovers/version.rb +1 -1
  137. metadata +143 -24
  138. data/lib/leftovers/argument_rule.rb +0 -229
  139. data/lib/leftovers/core_ext.rb +0 -15
  140. data/lib/leftovers/hash_rule.rb +0 -42
  141. data/lib/leftovers/name_rule.rb +0 -98
  142. data/lib/leftovers/rule.rb +0 -82
  143. data/lib/leftovers/transform_rule.rb +0 -169
  144. data/lib/leftovers/value_rule.rb +0 -57
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07755634c2f0119263912ecb6d90a64d37eea60aca5958f1c5f70555b5f63cb6
4
- data.tar.gz: ac46e0dc82c7ed6aa10ca1775ecd1d080a4496fd6cbac942631e065892d8742c
3
+ metadata.gz: 02f0f5136df6e16a7d27e47d118446f9118395f9242e29a32c91476ccd070591
4
+ data.tar.gz: fa438c525a212769b17cae1b2e2f05495c2772da5c9f3a05c9dd2d869743e969
5
5
  SHA512:
6
- metadata.gz: eb18eaa912ee5df99a96cb34eb9960e258aeec4e23fb00da879b7ea48cc8e42aaaa27d12dd21beb732e68257690ef2f1a8f71ab27f5402fd47c54768a4f895d4
7
- data.tar.gz: d13c59bb909652a4bd0a1b4d46a66fc2faf40625e995dcfea43e60aed2a5fd617d2faf1b02408337837fed630474d0ec5c8c46113013d249648c7271783be74b
6
+ metadata.gz: 3c88300e0a1e822f510dd22ff72a91ab1db5ed35ac7cdd323ec3fe194f347748faad08efd62ac727501ed6f854e5623b6958589e216a4e2389ed44f9fc878b54
7
+ data.tar.gz: '08deaf4ffb911b2a1d53960e5bfc6c46a3990d0a6197d28f18b8ccfc60031b48c3701dca1e1d1ffe7db5e1ab892b1630c9332e87706769326141b0793115a2d6'
@@ -1,3 +1,26 @@
1
+
2
+ # v0.4.0
3
+ - add `requires:` to .leftovers.yml config to e.g. load inflections in a different place than `config/initializers/inflections`
4
+ - REFACTORED EVERYTHING for a codebase i actually can extend
5
+ - Now with a very modified config api. After this i don't intend on every doing a rewrite like this again, so this is correcting all my bad decisions the first time through
6
+ - `rules.names` with `rules.skip: true` is now `keep.names` (see config/parser.yml)
7
+ - `rules.calls` and `rules.defines` is now `dynamic.calls` and `dynamic.defines`
8
+ - `rules.calls/defines.arguments.if` is now `keep/dynamic.calls/defines.has_arguments:` (see config/graphql.yml field)
9
+ - `rules.calls/defines.arguments.unless` is now `keep/dynamic.unless.has_arguments` (see config/graphql.yml field)
10
+ - `rules.calls/defines.transforms.replace_with` is now `keep/dynamic.calls/defines.value` (see custom_config_spec.rb html)
11
+ - `rules.calls/defines.transforms.add_prefix.from_argument/joiner:` is now `dynamic.calls/defines.transforms.add_prefix.argument/add_suffix` (see config/rails.yml delegate)
12
+ - `rules.calls/defines.transforms.add_suffix.from_argument/joiner:` is now `dynamic.calls/defines.transforms.add_suffix.argument/add_prefix`
13
+ - `rules.calls/defines.key: true` is now `dynamic.calls/defines.keywords: '**'`
14
+ - `rules.calls/defines.arguments.if.arguments.value` is now `keep/dynamic.has_arguments.has_value`
15
+ - `rules.calls/defines.arguments.if.arguments.value.type` is now `keep/dynamic.has_arguments.has_value_type`
16
+ - `rules.calls/defines.linked_transforms` is now `dynamic.calls/defines.transforms` (see config/rails.yml attribute). For the previous behaviour of the `transforms:` key simply add separate calls/defines entry. (see config/ruby.yml attr_accessor)
17
+ - `rules.calls/defines.keys: true` is now `dynamic.calls/defines.keywords: '**'` and can be given name patterns (e.g. unless:. see config/rails.yml validates)
18
+ - argument positions are now 0-indexed rather than 1-indexed
19
+ - no more automatic recursion, there's now two new keywords:
20
+ - `dynamic.calls/defines.arguments/keywords` with `dynamic.calls/defines.nested.arguments/keywords` will define the next layer of arguments to collect (see config/rails.yml validates)
21
+ - `dynamic.calls/defines.arguments/keywords` with `dynamic.calls/defines.recursive: true` will use the arguments & keywords layers recursively (see config/rails.yml permit)
22
+ - no more automatic splitting on ':' and '.', there's now a `dynamic.calls/defines.transforms.split: '::'` (see config/rails.yml resource)
23
+
1
24
  # v0.3.0
2
25
  - Add simplecov, fix a handful of bugs it found
3
26
  - update fast_ignore
data/README.md CHANGED
@@ -1,16 +1,17 @@
1
1
  # Leftovers
2
- [![travis](https://travis-ci.org/robotdana/leftovers.svg?branch=master)](https://travis-ci.org/robotdana/leftovers)
2
+ [![travis](https://travis-ci.com/robotdana/leftovers.svg?branch=main)](https://travis-ci.com/robotdana/leftovers)
3
+ [![Gem Version](https://badge.fury.io/rb/leftovers.svg)](https://rubygems.org/gems/leftovers)
3
4
 
4
5
  Find unused `methods`, `Classes`, `CONSTANTS`, `@instance_variables`, `@@class_variables`, and `$global_variables` in your ruby projects.
5
6
 
6
7
  ## Why?
7
8
 
8
- Code that never gets executed is code that you shouldn't need to maintain.
9
+ Code that never gets executed is code that you shouldn't need to maintain
9
10
 
10
11
  - Leftovers from refactoring
11
12
  - Partially removed features
12
13
  - Typos and THIS NEVER WOULD HAVE WORKED code
13
- - Code that you only keep around because there are tests of it.
14
+ - Code that you only keep around because there are tests of it
14
15
 
15
16
  Leftovers will use static analysis to find these bits of code for you.
16
17
 
@@ -29,7 +30,7 @@ It's aware of how some gems call methods for you, including (still somewhat inco
29
30
  Add this line to your application's Gemfile:
30
31
 
31
32
  ```ruby
32
- gem 'leftovers'
33
+ gem 'leftovers', require: false
33
34
  ```
34
35
 
35
36
  And then execute:
@@ -42,7 +43,7 @@ Or install it yourself as:
42
43
 
43
44
  ## Usage
44
45
 
45
- Run `leftovers` in your terminal in the root of your project.
46
+ Run `leftovers` in your command line in the root of your project.
46
47
  This will output progress as it collects the calls/references and definitions in your project.
47
48
  Then it will output any defined methods (or classes etc) which are not called.
48
49
 
@@ -60,6 +61,7 @@ lib/hello_world.rb:6:6 generated_method attr_accessor :generated_method
60
61
  ## Magic comments
61
62
 
62
63
  ### `# leftovers:keep`
64
+ _aliases `leftovers:keeps`, `leftovers:skip`, `leftovers:skips`, `leftovers:skipped`, `leftovers:allow`, `leftovers:allows`, `leftovers:allowed`_
63
65
  To mark a method definition as not unused, add the comment `# leftovers:keep` on the same line as the definition
64
66
 
65
67
  ```ruby
@@ -73,6 +75,7 @@ This would report `MyClass` is unused, but not my_method
73
75
  To do this for all definitions of this name, add the name with `skip: true` in the configuration file.
74
76
 
75
77
  ### `# leftovers:test`
78
+ _aliases `leftovers:for_test`, `leftovers:for_tests`, `leftovers:test`, `leftovers:tests`, `leftovers:testing`_
76
79
 
77
80
  To mark a definition from a non-test dir, as intentionally only used by tests, use `leftovers:test`
78
81
  ```ruby
@@ -93,60 +96,40 @@ end
93
96
  This would consider `my_method` to be used, even though it is only called by tests.
94
97
 
95
98
  ### `# leftovers:call`
99
+ _aliases `leftovers:calls`_
96
100
  To mark a dynamic call that doesn't use literal values, use `leftovers:call` with the method name listed
97
101
  ```ruby
98
- method = [:puts, :warn].sample
99
- send(method, 'text') # leftovers:call puts, warn
102
+ method = [:puts, :warn].sample # leftovers:call puts, warn
103
+ send(method, 'text')
100
104
  ```
101
105
 
102
106
  This would consider `puts` and `warn` to both have been called
103
107
 
104
- ## Configuration
108
+ ## Configuration file
105
109
 
106
110
  The configuration is read from `.leftovers.yml` in your project root.
107
- Its presence is optional and all of these settings are optional:
108
-
109
- see the [complete config documentation](https://github.com/robotdana/leftovers/tree/master/Configuration.md) for details.
110
- see the [built in config files](https://github.com/robotdana/leftovers/tree/master/lib/config) for examples.
111
-
112
- - [`include_paths:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#include_paths)
113
- - [`exclude_paths:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#exclude_paths)
114
- - [`test_paths:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#test_paths)
115
- - [`gems:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#gems)
116
- - [`rules:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#rules)
117
- - [`names:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#names)
118
- - [`has_prefix:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#has_prefix-has_suffix)
119
- - [`has_suffix:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#has_prefix-has_suffix)
120
- - [`matches:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#matches)
121
- - [`paths:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#paths)
122
- - [`skip:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#skip)
123
- - [`calls:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#calls-defines), [`defines:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#calls-defines)
124
- - [`arguments:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#arguments), [`keys:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#keys-), [`itself:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#itself-true)
125
- - [`transforms:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#transforms), [`linked_transforms:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#linked_transforms)
126
- - `original:`, `add_prefix:`, `add_suffix:`, `delete_prefix:`, `delete_suffix:`, `replace_with:`
127
- - `delete_before:`, `delete_after:`, `downcase:`, `upcase:`, `capitalize:`, `swapcase:`
128
- - `pluralize`, `singularize`, `camelize`, `underscore`, `demodulize`, `deconstantize`
129
- - [`if:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#if-unless), [`unless:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#if-unless)
130
- - [`has_argument:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#has_argument)
131
- - `keyword:`
132
- - [`has_prefix:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#has_prefix-has_suffix)
133
- - [`has_suffix:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#has_prefix-has_suffix)
134
- - [`matches:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#matches)
135
- - `value:`
136
- - [`has_prefix:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#has_prefix-has_suffix)
137
- - [`has_suffix:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#has_prefix-has_suffix)
138
- - [`matches:`](https://github.com/robotdana/leftovers/tree/master/Configuration.md#matches)
139
- - `type:`
111
+ Its presence is optional and all of these settings are optional.
112
+
113
+ - [`include_paths:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#include_paths)
114
+ - [`exclude_paths:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#exclude_paths)
115
+ - [`test_paths:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#test_paths)
116
+ - [`requires:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#requires)
117
+ - [`gems:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#gems)
118
+ - [`keep:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#keep)
119
+ - [`dynamic:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#dynamic)
120
+
121
+ see the [complete config documentation](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md) for details.
122
+ see the [built in config files](https://github.com/robotdana/leftovers/tree/main/lib/config) or [this repo's own config](https://github.com/robotdana/leftovers/tree/main/.leftovers.yml) for examples.
140
123
 
141
124
  ## Limitations
142
125
 
143
126
  - Leftovers will report methods/constants you define that are called outside your code (perhaps by gems) as unused
144
127
 
145
- Add these names to the `rules:` list with `skip: true` in the `.leftovers.yml` or add an inline comment with `# leftovers:allow my_method_name`
146
- - Leftovers doesn't execute your code so isn't aware of dynamic calls to `send` (e.g. `send(variable_method_name)`). (it is aware of static calls (e.g. `send(:my_method_name)`), so using send to bypass method privacy is "fine")
128
+ Add these names to the `keep:` list in the `.leftovers.yml` or add an inline comment with `# leftovers:allow my_method_name`
129
+ - Leftovers doesn't execute your code so isn't aware of e.g. variables in calls to `send` (e.g. `send(variable_method_name)`). (it is aware of static calls (e.g. `send(:my_method_name)`), so using send to bypass method privacy is "fine")
147
130
 
148
- Add the method/pattern to the `rules:` list with `skip: true` in the `.leftovers.yml`, or add an inline comment with the list of possibilities `# leftovers:call my_method_1, my_method_2`.
149
- - Leftovers compares by name only, so multiple methods with the same name will count as used even if only one is.
131
+ Add the method/pattern to the `dynamic:` list with `skip: true` in the `.leftovers.yml`, or add an inline comment with the list of possibilities `# leftovers:call my_method_1, my_method_2`.
132
+ - Leftovers compares by name only, so multiple definitions with the same name will count as used even if only one is.
150
133
  - haml & erb line and column numbers will be wrong as the files have to be precompiled before checking.
151
134
 
152
135
  ## Other tools
@@ -0,0 +1,598 @@
1
+ # Configuration
2
+
3
+ The configuration is read from `.leftovers.yml` in your project root.
4
+ Its presence is optional and all of these settings are optional.
5
+
6
+ - [`include_paths:`](#include_paths)
7
+ - [`exclude_paths:`](#exclude_paths)
8
+ - [`test_paths:`](#test_paths)
9
+ - [`requires:`](#requires)
10
+ - [`gems:`](#gems)
11
+ - [`keep:`](#keep)
12
+ - [`dynamic:`](#dynamic)
13
+
14
+ see the [built in config files](https://github.com/robotdana/leftovers/tree/main/lib/config) or [this repo's own config](https://github.com/robotdana/leftovers/tree/main/.leftovers.yml) for examples.
15
+
16
+ ## `include_paths:`
17
+ _alias `include_path:`_
18
+
19
+ List filenames/paths in the gitignore format of files to be checked
20
+ Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
21
+
22
+ By default leftovers will already check all `*.rb` files, and files with no extension and a shebang containing `ruby` e.g. (`#!/usr/bin/env ruby`)
23
+ Also the config added in [`gems:`](#gems) may add to this list, e.g. `gems: rake` adds `Rakefile` and `*.rake` to be checked.
24
+
25
+ ```yml
26
+ include_paths:
27
+ - '*.rb'
28
+ - '*.rake'
29
+ - Gemfile
30
+ ```
31
+
32
+ Arrays are not necessary for single values
33
+
34
+ ## `exclude_paths:`
35
+ _alias `exclude_path:`_
36
+
37
+ List filenames/paths that match the above that you might want to exclude
38
+ Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
39
+
40
+ By default leftovers will already read your project's .gitignore file and ignore anything there.
41
+
42
+ ```yml
43
+ exclude_paths:
44
+ - /some/long/irrelevant/generated/file
45
+ ```
46
+
47
+ Arrays are not necessary for single values
48
+
49
+ ## `requires:` # TODO
50
+ _alias `require`_
51
+
52
+ List filenames/paths that you want to include
53
+ Unlike other `paths:` configuration, each entry is **not** the gitignore pattern format.
54
+ Instead it is strings that can be passed directly to ruby's `require` method (relative paths should start with `./`).
55
+
56
+ Missing files/gems will be a warning, but not a LoadError.
57
+
58
+ By default, the default [`gems: active_support`]() config `require: activesupport` and `gems: rails` will `require: ./config/initializers/inflections`
59
+
60
+ ```yml
61
+ require: ./config/initializers/my_other_inflections_file
62
+ ```
63
+
64
+ Arrays are not necessary for single values
65
+
66
+ ## `test_paths:`
67
+ _alias `test_path:`_
68
+
69
+ list filenames/paths of test directories that will be used to determine if a method/etc is only tested but not otherwise used.
70
+ Defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
71
+
72
+ ```yml
73
+ test_paths:
74
+ - /test/
75
+ - /spec/
76
+ ```
77
+
78
+ Arrays are not necessary for single values
79
+
80
+ ## `gems:`
81
+ _alias `gem:`_
82
+
83
+ By default Leftovers will look at your `Gemfile.lock` file to find all gem dependencies
84
+
85
+ If you don't use bundler, you can still take advantage of the built in handling for certain gems. The arguments should exactly match the gems name. not all gems are supported yet.
86
+
87
+ ```yml
88
+ gems:
89
+ - rspec
90
+ - rails
91
+ ```
92
+
93
+ Arrays are not necessary for single values
94
+
95
+ ## `keep:`
96
+
97
+ This is a list of methods/constants/variables that are ok to be defined and not used, because they're your public api, or called by a gem on your behalf or etc.
98
+
99
+ 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:
100
+ - [`names:`](#names)
101
+ or the properties from `names:`
102
+ - [`has_prefix:`](#has_prefix)
103
+ - [`has_suffix:`](#has_suffix)
104
+ - [`matches:`](#matches) (can't be used in the same entry as `has_prefix:` or `has_suffix:`)
105
+ - [`paths:`](#paths)
106
+ - [`has_arguments:`](#has_arguments)
107
+ - [`unless`](#unless)
108
+
109
+ Arrays are not necessary for single values
110
+
111
+ example from rails.yml
112
+ ```yml
113
+ keep:
114
+ - APP_PATH
115
+ - ssl_configured?
116
+ - has_suffix: Helper
117
+ path: /app/helpers
118
+ ...
119
+ ```
120
+
121
+ Alternatively, you can mark method/constants/variables in-place using [magic comments](https://github.com/robotdana/leftovers/tree/main/README.md#magic-comments).
122
+
123
+ ## `dynamic:`
124
+
125
+ This is a list of methods, constants, or variables whose called arguments or assigned value/s are used to dynamically `call:` or define (`define:`) other methods, constants, or variables
126
+
127
+ Each entry must have at least one of the following properties to restrict which method/constant/variable this applies to:
128
+ - [`names:`](#names)
129
+ or the properties from `names:`
130
+ - [`has_prefix:`](#has_prefix)
131
+ - [`has_suffix:`](#has_suffix)
132
+ - [`matches:`](#matches)
133
+ - [`paths:`](#paths)
134
+ - [`has_arguments:`](#has_arguments)
135
+ - [`unless`](#unless)
136
+
137
+ And must have one or both of
138
+ - ['calls:`](#calls-defines)
139
+ - [`defines:`](#calls-defines)
140
+
141
+ Arrays are not necessary for single values.
142
+
143
+ example from the default ruby.yml
144
+ ```yml
145
+ dynamic:
146
+ - name: attr_accessor
147
+ defines:
148
+ - arguments: '*'
149
+ add_suffix: '='
150
+ - arguments: '*'
151
+ calls:
152
+ arguments: '*'
153
+ add_prefix: '@'
154
+ ...
155
+ ```
156
+
157
+ ## `names:`
158
+ _alias `name:`_
159
+
160
+ This is a list of methods/constants/variables, and can be used in [`dynamic:`](#dynamic) and [`keep:`](#keep)
161
+
162
+ 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:
163
+ - [`has_prefix:`](#has_prefix)
164
+ - [`has_suffix:`](#has_suffix)
165
+ - [`matches:`](#matches) (this can't be used in the same entry as `has_prefix:` or `has_suffix:`)
166
+
167
+ Arrays are not necessary for single values
168
+
169
+ example from rails.yml
170
+ ```yml
171
+ keep:
172
+ - APP_PATH
173
+ - ssl_configured?
174
+ - names:
175
+ has_suffix: Helper
176
+ path: /app/helpers
177
+ ...
178
+ ```
179
+
180
+ ## `has_prefix:`, `has_suffix:`
181
+
182
+ To match strings other than exact strings, you can use has_suffix or has_prefix or both if you're feeling fancy.
183
+
184
+ This can be in entries in:
185
+ - [`dynamic:`](#dynamic), [`keep:`](#keep), [`names:`](#names) to match method/constant/variable names
186
+ - [`has_arguments:`](#has_arguments), [`arguments:`](#arguments), [`keywords:`](#keywords), [`at:`](#at) to match keyword argument names (whether they're symbols or strings)
187
+ - [`has_values:`](#has_values) to match argument/assigned values (whether they're symbols or strings)
188
+
189
+ ```yml
190
+ keep:
191
+ - has_suffix: Helper # will match Helper, LinkHelper FormHelper, etc
192
+ - has_prefix: be_ # will match be_equal, be_invalid, etc
193
+ - { has_prefix: is_, has_suffix: '?' } # will match is_invalid?, is_equal? etc
194
+ ```
195
+
196
+ ## `matches:`
197
+ _alias `match:`_
198
+
199
+ if [`has_suffix:`](#has_prefix-has_suffix) and [`has_prefix:`](#has_prefix-has_suffix) isn't enough, you can use `matches:` to supply a regex
200
+
201
+ This string is converted into an anchored ruby regexp and must match the whole string, see [ruby's regex documentation](https://ruby-doc.org/core-2.7.2/Regexp.html#class-Regexp-label-Metacharacters+and+Escapes) for the syntax.
202
+
203
+ This can be in used for entries in:
204
+ - [`dynamic:`](#dynamic), [`keep:`](#keep), [`names:`](#names) to match method/constant/variable names
205
+ - [`has_arguments:`](#has_arguments), [`arguments:`](#arguments), [`keywords:`](#keywords) to match keyword argument names (whether they're symbols or strings in the code)
206
+
207
+ ```yml
208
+ dynamic:
209
+ - names:
210
+ matches: 'row_\d+' # will match row_1, row_2, row_99, but not row_1a, or crow_1, or etc.
211
+ calls:
212
+ argument:
213
+ matches: 'column_\d+' # will match column_1, column_2, column_99, but not column_first etc
214
+ ```
215
+
216
+ ## `paths:`
217
+ _alias `path:`_
218
+
219
+ An list of paths, defined using the [.gitignore pattern format](https://git-scm.com/docs/gitignore#_pattern_format)
220
+
221
+ This can be used in entries in [`dynamic:`](#dynamic), [`keep:`](#keep)
222
+
223
+ Arrays are not necessary for single values
224
+
225
+ ```yml
226
+ keep:
227
+ - name:
228
+ - has_suffix: Helper
229
+ path: /app/helpers
230
+ ```
231
+
232
+ ## `calls:`, `defines:`
233
+ _aliases `call:`, `define:`_
234
+
235
+ At least one of these must be used in each entry in [`dynamic:`](#dynamic)
236
+
237
+ 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.
238
+
239
+ Each entry must be have at least one the these properties:
240
+ - [`arguments:`](#arguments)
241
+ - [`keywords:`](#keywords) keyword argument keywords, and assigned hash keys
242
+ - [`itself: true`](#itself-true) the matched name (intended to be used with `transforms:`, as the untransformed matched name will already be tracked)
243
+ - [`value:`](#value) a literal string to be called/defined
244
+
245
+ also there may be any or all of these properties:
246
+ - [`nested:`](#nested) (only with `arguments:`)
247
+ - [`recursive: true`](#recursive-true) (only with `arguments:`)
248
+ - [`transforms:`](#transforms)
249
+ - or any these properties for `transform:`
250
+ - [`add_prefix:`](#add_prefix-add_suffix)
251
+ - [`add_suffix:`](#add_prefix-add_suffix)
252
+ - [`delete_prefix:`](#delete_prefix-delete_suffix)
253
+ - [`delete_suffix:`](#delete_prefix-delete_suffix)
254
+ - [`delete_before:`](#delete_before-delete_after)
255
+ - [`delete_after:`](#delete_before-delete_after)
256
+ - [`split:`](#split)
257
+ - [`downcase:`](#downcase-upcase-capitalize-swapcase)
258
+ - [`upcase:`](#downcase-upcase-capitalize-swapcase)
259
+ - [`capitalize:`](#downcase-upcase-capitalize-swapcase)
260
+ - [`swapcase:`](#downcase-upcase-capitalize-swapcase)
261
+ - [`pluralize:`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore)
262
+ - [`singularize:`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore)
263
+ - [`camelize:`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore)
264
+ - [`underscore:`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore)
265
+ - [`demodulize:`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore)
266
+ - [`deconstantize:`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore)
267
+ - [`titleize:`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore)
268
+ - [`parameterize:`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore)
269
+
270
+ Arrays are not necessary for single values and if the rule contains only `arguments:` the keyword can be omitted, and everything moved up a level
271
+
272
+ ```yml
273
+ dynamic:
274
+ - name:
275
+ - send
276
+ calls:
277
+ arguments:
278
+ - 1
279
+ ```
280
+ is equivalent to:
281
+ ```yml
282
+ dynamic:
283
+ name: send
284
+ calls: 1
285
+ ```
286
+
287
+ ## `arguments:`
288
+ _alias `argument:`_
289
+
290
+ Each entry indicates the position or keyword of the value or values in either a list of method call arguments, or a literal array or hash
291
+ and when used in:
292
+ - [`calls:`](#calls-defines), [`defines:`](#calls-defines) or [`nested:`](#nested) to filter method/constant/variable names are supplied [`transforms:`](#transforms), or [`nested:`](#nested)
293
+ - [`add_prefix:`](#add_prefix), [`add_suffix:`](#add_suffix) the argument value can be used as the prefix/suffix rather than a literal string
294
+
295
+ It can have any of these properties:
296
+ - [`at:`](#at)
297
+ - [`has_value:`](#has_value)
298
+ - [`has_value_type:`](#has_value_type)
299
+
300
+ 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
301
+
302
+ ## `has_arguments:`
303
+ _alias `has_argument:`_
304
+
305
+ Each entry indicates the position or keyword of the value or values in either a list of method call arguments, or a literal array or hash
306
+ and when used in:
307
+ - [`dynamic:`](#dynamic) it uses the presence of matching arguments to filter which methods calls/constant/variable assignments are processed
308
+ - [`keep:`](#keep) it uses the presence of matching arguments to filter which methods calls/constant/variable assignments are skipped
309
+
310
+ The method call/constant variable/assignment will be considered matching if it has **any** of these arguments/assigned values.
311
+
312
+ It can have any of these properties:
313
+ - [`at:`](#at)
314
+ - [`has_value:`](#has_value) # TODO
315
+ - [`has_value_type:`](#has_value_type) # TODO
316
+
317
+ 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
318
+
319
+ ## `keywords:`
320
+ When the keyword argument **keywords** are the thing being called.
321
+
322
+ ```yml
323
+ dynamic:
324
+ - name: validates
325
+ calls:
326
+ - arguments: '*'
327
+ - keywords: '**'
328
+ camelize: true
329
+ add_suffix: Validator
330
+ ```
331
+ ```ruby
332
+ validates :first_name, :surname, presence: true
333
+ ```
334
+ will count calls for `validates`, `first_name`, `surname`, and `PresenceValidator`
335
+
336
+ ## `at:`
337
+
338
+ Each entry indicates the position or keyword of the value or values in either a list of method call arguments, or a literal array or hash.
339
+
340
+ This can be used in:
341
+ - [`has_arguments`](#has_arguments) to filter method calls/constant/variable assignments by the presence of this argument
342
+ - [`arguments:`](#arguments) to select positional argument values and keyword **values** to be processed
343
+ - [`keywords:`](#keywords) to select **keywords** and hash **keys** to be processed
344
+
345
+ Each entry can be any of:
346
+ - `'*'`: matches all positional arguments/array positions
347
+ - `'**'`: matches all keyword arguments/hash positions
348
+ - any positive Integer: matches the 1-indexed argument position/array position
349
+ - any other String: matches the keyword argument or hash value, where the keyword/hash key string or symbol
350
+ - or have at least one of the following properties to match the keyword/hash key string or symbol:
351
+ - [`has_prefix:`](#has_prefix)
352
+ - [`has_suffix:`](#has_suffix)
353
+ - [`matches:`](#matches) (this can't be used in the same entry as `has_prefix:` or `has_suffix:`)
354
+
355
+ Arrays are not necessary for single values
356
+
357
+ ## `has_value:`
358
+
359
+ filter [`arguments:`](#arguments), [`has_arguments:`](#has_arguments), and [`keywords:`](#keywords), by the argument/assigned value
360
+
361
+ Each entry can be one of
362
+ - `true`, `false`, `nil`, or an Integer. matches the literal value
363
+ - a String. matches the literal string or symbol value
364
+ - or have at least one of the following properties to match a string or symbol:
365
+ - [`has_prefix:`](#has_prefix)
366
+ - [`has_suffix:`](#has_suffix)
367
+ - [`matches:`](#matches) (this can't be used in the same entry as `has_prefix:` or `has_suffix:`)
368
+
369
+ ## `has_value_type:`
370
+
371
+ Filter [`arguments:`](#arguments), [`has_arguments:`](#has_arguments), and [`keywords:`](#keywords), by the argument/assigned value
372
+
373
+ Each entry can be one of
374
+ - `'String'`
375
+ - `'Symbol'`
376
+ - `'Integer'`
377
+ - `'Float'`
378
+
379
+ Arrays are not necessary for single values
380
+
381
+ ## `nested:`
382
+
383
+ To process an argument that is an array you will need to supply which entries in the array need processing.
384
+
385
+ This can be used in [`calls:`](#calls-defines), [`defines:`](#calls-defines) or within a preceding `nested:` entry
386
+
387
+ Each entry must be have at least one the these properties:
388
+ - [`arguments:`](#arguments)
389
+ - [`keywords:`](#keywords) keyword argument keywords, and assigned hash keys
390
+ And may additionally have any of these properties:
391
+ - [`nested:`](#nested)
392
+ - [`recursive: true`](#recursive-true)
393
+
394
+ It will filter the arrays/hashes found by its sibling properties `arguments:`, and `keywords:`, using its own child properties.
395
+
396
+ e.g.
397
+ ```yml
398
+ dynamic:
399
+ - names: my_method
400
+ calls:
401
+ argument: 2
402
+ nested:
403
+ argument: '*'
404
+ nested:
405
+ argument: name
406
+ ```
407
+ ```ruby
408
+ my_method([{name: :name_1}, {name: :name_2}, [{name: :name_3, value: :value_1}, {name: :name_4, value: :value_2}])
409
+ ```
410
+ will count `name_3`, and `name_4` (but not `name_1` and `name_2` because they're within the first positional argument, and not `value_1`, or `value_2`)
411
+
412
+ Arrays are not necessary for single values
413
+
414
+ ## `recursive: true`
415
+
416
+ This can be used in [`calls:`](#calls-defines), [`defines:`](#calls-defines) or within a preceding [`nested:`](#nested) entry
417
+
418
+ Similar to [`nested:`](#nested), this processes arrays hashes found by its sibling [`arguments:`](#arguments) and [`keywords:`](#keywords) properties, with those same properties, recursively.
419
+
420
+ e.g. rails' ActiveRecord::Base#joins method can call association methods using all positional arguments values, keyword argument keywords and values, and recursively all values arrays and hash keys and values
421
+ ```yml
422
+ dynamic:
423
+ name: [joins, left_joins]
424
+ calls:
425
+ arguments: ['*', '**']
426
+ keywords: '**'
427
+ recursive: true
428
+ ```
429
+
430
+ ## `itself: true`
431
+
432
+ Will supply the method/constant/variable name itself as the thing to be transformed.
433
+ The original method/constant/variable name will continue to be called/defined as normal
434
+
435
+ This can be used in [`calls:`](#calls-defines) and [`defines:`](#calls-defines)
436
+
437
+ ```yml
438
+ - name:
439
+ has_prefix: be_
440
+ calls:
441
+ itself: true
442
+ delete_prefix: be_
443
+ add_suffix: '?'
444
+ ```
445
+ ```ruby
446
+ expect(value).to be_empty
447
+ ```
448
+ will count `be_empty` as a call to `empty?`
449
+
450
+ ## `value:`
451
+
452
+ Will supply a literal string value method/constant/variable name itself as the thing to be called/defined.
453
+ This can be used in [`calls:`](#calls-defines) and [`defines:`](#calls-defines).
454
+
455
+ ```yml
456
+ - name: perform_async
457
+ calls:
458
+ value: perform
459
+ ```
460
+ ```ruby
461
+ MyWorker.perform_async
462
+ ```
463
+ will count `perform_async` as a call to `perform`
464
+
465
+ ## `transforms:`
466
+
467
+ Sometimes the method/class being called is modified from the literal argument, sometimes that's just appending an `=` and sometimes it's more complex:
468
+
469
+ Each entry can have a string that is an argumentless transform (e.g. capitalize) or a hash with transform keywords. This can be in used for entries in:
470
+ - [`defines:`](#calls-defines), [`calls:`](#calls-defines) to modify values filtered by the sibling keys [`arguments:`](#arguments), [`keywords:`](#keywords) and [`itself: true`](#itself-true) (also [`value:`](#value) but as that's a literal value anyway, why would you)
471
+ - [`add_prefix:`](#add_prefix-add_suffix), [`add_suffix:`](#add_prefix-add_suffix) to modify the selected `argument:` or `keyword:` for dynamic prefixes and suffixes
472
+
473
+ - [`original`](#original) or `original: true`
474
+ - [`add_prefix:`](#add_prefix-add_suffix)
475
+ - [`add_suffix:`](#add_prefix-add_suffix)
476
+ - [`delete_prefix:`](#delete_prefix-delete_suffix)
477
+ - [`delete_suffix:`](#delete_prefix-delete_suffix)
478
+ - [`delete_before:`](#delete_before-delete_after)
479
+ - [`delete_after:`](#delete_before-delete_after)
480
+ - [`split:`](#split)
481
+ - [`downcase`](#downcase-upcase-capitalize-swapcase) or `downcase: true`
482
+ - [`upcase`](#downcase-upcase-capitalize-swapcase) or `upcase: true`
483
+ - [`capitalize`](#downcase-upcase-capitalize-swapcase) or `capitalize: true`
484
+ - [`swapcase`](#downcase-upcase-capitalize-swapcase) or `swapcase: true`
485
+ - Also, if you have the active_support gem available:
486
+ - [`pluralize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `pluralize: true`
487
+ - [`singularize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `singularize: true`
488
+ - [`camelize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `camelize: true`
489
+ - [`underscore`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `underscore: true`
490
+ - [`demodulize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `demodulize: true`
491
+ - [`deconstantize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `deconstantize: true`
492
+ - [`titleize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `titleize: true`
493
+ - [`parameterize`](#pluralize-singularize-camelize-demodulize-deconstantize-parameterize-titleize-underscore) or `parameterize: true`
494
+
495
+ 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.
496
+
497
+ ```yml
498
+ - name: attribute
499
+ defines:
500
+ - argument: 1
501
+ transforms:
502
+ - original # no transformation
503
+ - add_suffix: '?'
504
+ - add_suffix: '='
505
+ ```
506
+ ```ruby
507
+ attribute :first_name
508
+ ```
509
+ 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.
510
+
511
+ 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.
512
+
513
+ ```yml
514
+ - name: attr_writer
515
+ defines:
516
+ - argument: '*'
517
+ add_suffix: '='
518
+ ```
519
+ ```ruby
520
+ attr_writer :first_name, :surname
521
+ ```
522
+ will count as the definition of `first_name=`, and `surname=`
523
+
524
+ ## `original`
525
+
526
+ Can be used in the [`transforms:`](#transforms) list, if used in a hash `true` can be used as a placeholder value
527
+
528
+ This performs no change, and is only useful when grouped with other transforms
529
+
530
+ ## `add_prefix:`, `add_suffix:`
531
+
532
+ Can be used in the [`transforms:`](#transforms) list (or anywhere `transforms:` is able to be omitted).
533
+
534
+ Each entry is one of:
535
+ - a literal string
536
+ - [`argument:`](#argument) or [`keyword:`](#keyword) matching arguments/assignments from the original method call/method definition
537
+ - Optionally [`transform:`] or any of the `transform:` properties, to transform the value(s) from `argument:` and `keyword:`.
538
+
539
+ if multiple transform results are possible (from multiple entries, or multiple matching arguments or etc), then all results will be used.
540
+
541
+ Arrays are not necessary for single values
542
+
543
+ ## `delete_prefix:`, `delete_suffix:`
544
+
545
+ Can be used in the [`transforms:`](#transforms) list (or anywhere `transforms:` is able to be omitted).
546
+
547
+ Each entry is a literal string, and _if present_ the matching prefix or suffix will be removed (if it's not present, this transform will continue to the next transform/result unmodified)
548
+
549
+ if multiple transform results are possible (from multiple entries), then all results will be used.
550
+
551
+ Arrays are not necessary for single values
552
+
553
+ ## `delete_before:`, `delete_after:`
554
+
555
+ Can be used in the [`transforms:`](#transforms) list (or anywhere `transforms:` is able to be omitted).
556
+
557
+ 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
558
+
559
+ if multiple transform results are possible (from multiple entries), then all results will be used.
560
+
561
+ Arrays are not necessary for single values
562
+
563
+ ## `split:`
564
+
565
+ Can be used in the [`transforms:`](#transforms) list (or anywhere `transforms:` is able to be omitted).
566
+
567
+ Each entry is a literal string, and _if present_ the incoming value will string will be split on this value. (if it's not present, this transform will continue to the next transform/result unmodified)
568
+
569
+ if multiple transform results are possible (from multiple entries), then all results will be used.
570
+
571
+ Arrays are not necessary for single values
572
+
573
+ ## `downcase`, `upcase`, `capitalize`, `swapcase`
574
+
575
+ Can be used in the [`transforms:`](#transforms) list (or anywhere `transforms:` is able to be omitted).
576
+ if used in a hash `true` can be used as a placeholder value
577
+
578
+ the incoming value will be transformed using the [core ruby String method](https://ruby-doc.org/core-2.6/String.html#method-i-capitalize)
579
+
580
+ ## `pluralize`, `singularize`, `camelize`, `demodulize`, `deconstantize`, `parameterize`, `titleize`, `underscore`
581
+ _aliases `camelcase`, `titlecase`_
582
+
583
+ Can be used in the [`transforms:`](#transforms) list (or anywhere `transforms:` is able to be omitted).
584
+ if used in a hash `true` can be used as a placeholder value
585
+
586
+ the incoming value will be transformed using the [active_support String core extensions](https://edgeguides.rubyonrails.org/active_support_core_extensions.html#inflections)
587
+ and if using [gems:](#gems) with `active_support` or `rails` then your `config/initializers/inflections.rb` will be loaded. if you have inflections in another file, then supply that to [`requires:`](#requires).
588
+
589
+ If the `active_support` gem is not available this will raise an error.
590
+
591
+ ## `unless:`
592
+
593
+ It will filter the values found by its sibling properties, whatever they are, removing anything that matches its own child properties.
594
+ if it has no sibling properties, then it's filtering everything to remove anything that matches it's own child properties.
595
+
596
+ Each entry is able to have child properties drawn from whatever the unless keyword's sibling properties are able to be
597
+
598
+ Arrays are not necessary for single values