leftovers 0.2.3 → 0.4.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +39 -0
- data/README.md +65 -49
- data/docs/Configuration.md +627 -0
- data/exe/leftovers +2 -2
- data/leftovers.gemspec +13 -6
- 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 +126 -107
- 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 +4 -8
- data/lib/config/will_paginate.yml +12 -14
- data/lib/leftovers.rb +66 -54
- 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 +27 -15
- data/lib/leftovers/collector.rb +8 -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 +79 -61
- data/lib/leftovers/file_list.rb +9 -15
- 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 +29 -14
- data/lib/leftovers/parser.rb +1 -4
- 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 +56 -4
- data/lib/leftovers/todo_reporter.rb +124 -0
- 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 +201 -25
- 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: aa735d4aa3320b0225d0d256c296b5b3b284593f285d1257a4b8e6bd74a0dd74
|
4
|
+
data.tar.gz: ebaaa2f4c2e93780788e36d961a623a015b1f8d11c0a9799882e5a21a45552f4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88cf80851cdb71a94a3d5497fa80ab4b020447e6aa23b1a9074ef19789bcdc77b576275aad066ac23170b1d2d18687f0b07322b24792cd31a163f2e70f3d637e
|
7
|
+
data.tar.gz: '0167915df5ad01dcf2368e72a98171cad57b22e4df7d6c8e5bc29b1e8e053b8a9e522746836102d769ca80745105021bbeb297d038ab8cd58410a2d797c34d04'
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,42 @@
|
|
1
|
+
# v0.4.3
|
2
|
+
- add --write-todo so you can add this to your project without
|
3
|
+
immediately fixing everything.
|
4
|
+
|
5
|
+
# v0.4.2
|
6
|
+
- Make sorbet happy with this as a dependency
|
7
|
+
# v0.4.1
|
8
|
+
- add `test_only:` to mark methods/constants/assignments as test_only in the config rather than just with magic comments
|
9
|
+
|
10
|
+
# v0.4.0
|
11
|
+
- add `requires:` to .leftovers.yml config to e.g. load inflections in a different place than `config/initializers/inflections`
|
12
|
+
- REFACTORED EVERYTHING for a codebase i actually can extend
|
13
|
+
- 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
|
14
|
+
- `rules.names` with `rules.skip: true` is now `keep.names` (see config/parser.yml)
|
15
|
+
- `rules.calls` and `rules.defines` is now `dynamic.calls` and `dynamic.defines`
|
16
|
+
- `rules.calls/defines.arguments.if` is now `keep/dynamic.calls/defines.has_arguments:` (see config/graphql.yml field)
|
17
|
+
- `rules.calls/defines.arguments.unless` is now `keep/dynamic.unless.has_arguments` (see config/graphql.yml field)
|
18
|
+
- `rules.calls/defines.transforms.replace_with` is now `keep/dynamic.calls/defines.value` (see custom_config_spec.rb html)
|
19
|
+
- `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)
|
20
|
+
- `rules.calls/defines.transforms.add_suffix.from_argument/joiner:` is now `dynamic.calls/defines.transforms.add_suffix.argument/add_prefix`
|
21
|
+
- `rules.calls/defines.key: true` is now `dynamic.calls/defines.keywords: '**'`
|
22
|
+
- `rules.calls/defines.arguments.if.arguments.value` is now `keep/dynamic.has_arguments.has_value`
|
23
|
+
- `rules.calls/defines.arguments.if.arguments.value.type` is now `keep/dynamic.has_arguments.has_value_type`
|
24
|
+
- `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)
|
25
|
+
- `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)
|
26
|
+
- argument positions are now 0-indexed rather than 1-indexed
|
27
|
+
- no more automatic recursion, there's now two new keywords:
|
28
|
+
- `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)
|
29
|
+
- `dynamic.calls/defines.arguments/keywords` with `dynamic.calls/defines.recursive: true` will use the arguments & keywords layers recursively (see config/rails.yml permit)
|
30
|
+
- no more automatic splitting on ':' and '.', there's now a `dynamic.calls/defines.transforms.split: '::'` (see config/rails.yml resource)
|
31
|
+
|
32
|
+
# v0.3.0
|
33
|
+
- Add simplecov, fix a handful of bugs it found
|
34
|
+
- update fast_ignore
|
35
|
+
|
36
|
+
# v0.2.4
|
37
|
+
- use the right name for selenium-webdriver gem, so the bundler magic can work
|
38
|
+
- handle yaml syntax errors.
|
39
|
+
|
1
40
|
# v0.2.3
|
2
41
|
- restore ability to handle syntax errors. I really need to add coverage to this project
|
3
42
|
- Fix bug with delete_after on an empty string
|
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
|
|
@@ -55,11 +56,42 @@ lib/hello_world.rb:18:6 another_tested_unused_method def another_tested_unused_m
|
|
55
56
|
Not directly called at all:
|
56
57
|
lib/hello_world.rb:6:6 generated_method= attr_accessor :generated_method
|
57
58
|
lib/hello_world.rb:6:6 generated_method attr_accessor :generated_method
|
59
|
+
|
60
|
+
how to resolve: https://github.com/robotdana/leftovers/tree/main/Readme.md#how_to_resolve
|
58
61
|
```
|
59
62
|
|
63
|
+
if there is an overwhelming number of results, try using [`--write-todo`](#write-todo)
|
64
|
+
|
65
|
+
## How to resolve
|
66
|
+
|
67
|
+
When running `leftovers` you'll be given a list of method, constant, and variable definitions it thinks are unused. Now what?
|
68
|
+
|
69
|
+
they were unintentionally left when removing their calls:
|
70
|
+
- remove their definitions. (they're still there in your git etc history if you want them back)
|
71
|
+
|
72
|
+
they are called dynamically:
|
73
|
+
- define how they're called dynamically in the [.leftovers.yml](#configuration-file); or
|
74
|
+
- mark the calls with [`# leftovers:call my_unused_method`](#leftovers-call); or
|
75
|
+
- mark the definition with [`# leftovers:keep`](#leftovers-keep)
|
76
|
+
|
77
|
+
they're defined intentionally to only be used by tests:
|
78
|
+
- add [`# leftovers:test_only`](#leftovers-test-only)
|
79
|
+
|
80
|
+
they're from a file that shouldn't be checked by leftovers:
|
81
|
+
- add the paths to the [`exclude_paths:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#exclude_paths) list in the [.leftovers.yml](#configuration-file) file
|
82
|
+
|
83
|
+
if there are too many to address when first adding leftovers to your project, try running [`leftovers --write-todo`](#write-todo),
|
84
|
+
|
85
|
+
### --write-todo
|
86
|
+
|
87
|
+
running `leftovers --write-todo` will generate a supplemental configuration file allowing all the currently detected uncalled definitions, which will be read on subsequent runs of `leftovers` without alerting any of the items mentioned in it.
|
88
|
+
|
89
|
+
commit this file so you/your team can gradually address these items while still having leftovers alert you to any newly unused items.
|
90
|
+
|
60
91
|
## Magic comments
|
61
92
|
|
62
93
|
### `# leftovers:keep`
|
94
|
+
_aliases `leftovers:keeps`, `leftovers:skip`, `leftovers:skips`, `leftovers:skipped`, `leftovers:allow`, `leftovers:allows`, `leftovers:allowed`_
|
63
95
|
To mark a method definition as not unused, add the comment `# leftovers:keep` on the same line as the definition
|
64
96
|
|
65
97
|
```ruby
|
@@ -70,15 +102,16 @@ class MyClass
|
|
70
102
|
end
|
71
103
|
```
|
72
104
|
This would report `MyClass` is unused, but not my_method
|
73
|
-
To do this for all definitions of this name, add the name
|
105
|
+
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
106
|
|
75
|
-
### `# leftovers:
|
107
|
+
### `# leftovers:test_only`
|
108
|
+
_aliases `leftovers:for_test`, `leftovers:for_tests`, `leftovers:test`, `leftovers:tests`, `leftovers:testing`_
|
76
109
|
|
77
|
-
To mark a definition from a non-test dir, as intentionally only used by tests, use `leftovers:
|
110
|
+
To mark a definition from a non-test dir, as intentionally only used by tests, use `leftovers:test_only`
|
78
111
|
```ruby
|
79
112
|
# app/my_class.rb
|
80
113
|
class MyClass
|
81
|
-
def my_method # leftovers:
|
114
|
+
def my_method # leftovers:test_only
|
82
115
|
true
|
83
116
|
end
|
84
117
|
end
|
@@ -92,61 +125,44 @@ end
|
|
92
125
|
|
93
126
|
This would consider `my_method` to be used, even though it is only called by tests.
|
94
127
|
|
128
|
+
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).
|
129
|
+
|
95
130
|
### `# leftovers:call`
|
131
|
+
_aliases `leftovers:calls`_
|
96
132
|
To mark a dynamic call that doesn't use literal values, use `leftovers:call` with the method name listed
|
97
133
|
```ruby
|
98
|
-
method = [:puts, :warn].sample
|
99
|
-
send(method, 'text')
|
134
|
+
method = [:puts, :warn].sample # leftovers:call puts, warn
|
135
|
+
send(method, 'text')
|
100
136
|
```
|
101
137
|
|
102
138
|
This would consider `puts` and `warn` to both have been called
|
103
139
|
|
104
|
-
## Configuration
|
140
|
+
## Configuration file
|
105
141
|
|
106
142
|
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:`
|
143
|
+
Its presence is optional and all of these settings are optional.
|
144
|
+
|
145
|
+
- [`include_paths:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#include_paths)
|
146
|
+
- [`exclude_paths:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#exclude_paths)
|
147
|
+
- [`test_paths:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#test_paths)
|
148
|
+
- [`requires:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#requires)
|
149
|
+
- [`gems:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#gems)
|
150
|
+
- [`keep:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#keep)
|
151
|
+
- [`test_only:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#test_only)
|
152
|
+
- [`dynamic:`](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md#dynamic)
|
153
|
+
|
154
|
+
see the [complete config documentation](https://github.com/robotdana/leftovers/tree/main/docs/Configuration.md) for details.
|
155
|
+
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
156
|
|
141
157
|
## Limitations
|
142
158
|
|
143
159
|
- Leftovers will report methods/constants you define that are called outside your code (perhaps by gems) as unused
|
144
160
|
|
145
|
-
Add these names to the `
|
146
|
-
- Leftovers doesn't execute your code so isn't aware of
|
161
|
+
Add these names to the `keep:` list in the `.leftovers.yml` or add an inline comment with `# leftovers:allow my_method_name`
|
162
|
+
- 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
163
|
|
148
|
-
Add the method/pattern to the `
|
149
|
-
- Leftovers compares by name only, so multiple
|
164
|
+
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`.
|
165
|
+
- Leftovers compares by name only, so multiple definitions with the same name will count as used even if only one is.
|
150
166
|
- haml & erb line and column numbers will be wrong as the files have to be precompiled before checking.
|
151
167
|
|
152
168
|
## 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
|