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