rubocop-vicenzo 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +1 -1
- data/.rubocop.yml +2 -22
- data/CHANGELOG.md +24 -0
- data/README.md +26 -1
- data/Rakefile +2 -2
- data/config/default.yml +57 -0
- data/config/style.yml +228 -0
- data/lib/rubocop/cop/vicenzo/naming/anonymous_unused_name.rb +164 -0
- data/lib/rubocop/cop/vicenzo/naming/short_name.rb +133 -0
- data/lib/rubocop/cop/vicenzo/rspec/describe_inside_context.rb +94 -0
- data/lib/rubocop/cop/vicenzo/rspec/dynamic_example_generation.rb +19 -4
- data/lib/rubocop/cop/vicenzo/rspec/let_aliasing_subject.rb +121 -0
- data/lib/rubocop/cop/vicenzo/rspec/let_is_method_result.rb +11 -30
- data/lib/rubocop/cop/vicenzo/rspec/mixin/described_method.rb +7 -21
- data/lib/rubocop/cop/vicenzo/rspec/mixin/subject_reference.rb +61 -0
- data/lib/rubocop/cop/vicenzo/rspec/mutated_premises.rb +13 -2
- data/lib/rubocop/cop/vicenzo/rspec/nested_let_redefinition.rb +1 -1
- data/lib/rubocop/cop/vicenzo/rspec/nested_subject_redefinition.rb +1 -1
- data/lib/rubocop/cop/vicenzo/rspec/returned_chain.rb +71 -0
- data/lib/rubocop/cop/vicenzo/rspec/subject_is_method_result.rb +37 -5
- data/lib/rubocop/cop/vicenzo/rspec/unnested_context_improper_start.rb +89 -0
- data/lib/rubocop/cop/vicenzo/style/prefer_many_over_size_comparison.rb +77 -0
- data/lib/rubocop/cop/vicenzo_cops.rb +6 -0
- data/lib/rubocop/vicenzo/version.rb +1 -1
- data/rakelib/docs.rake +35 -10
- metadata +11 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4f7a8f58f53c6f2e6b50f1645a55cb401cd33b1f2654c793eaecd52cbf879153
|
|
4
|
+
data.tar.gz: f2eaba7a6bbb615190abf109a64681372988e3f8cea255c6055f6ae40698c7e2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '0258853f6e8d32fb88d7d4c53fb5520e2c828bd31d5968be91008ab34c13a729188c802e91539ef95eef937c56dc584cb59c7dbb9ddcc8c50e3cd6e991eb49a1'
|
|
7
|
+
data.tar.gz: c8a4a8d41af0c5d5f294acfd9361f1226f002590b051508b97a6fbcb9f3f36dbe695a6ae6efbccb7c122395bc9dd76e83f7cffc9a026f3d822954e20236483df
|
data/.rubocop.yml
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
inherit_from: config/style.yml
|
|
2
|
+
|
|
1
3
|
plugins:
|
|
2
4
|
- rubocop-performance
|
|
3
5
|
- rubocop-rake
|
|
@@ -5,39 +7,17 @@ plugins:
|
|
|
5
7
|
- rubocop-vicenzo
|
|
6
8
|
- rubocop-internal_affairs
|
|
7
9
|
|
|
8
|
-
AllCops:
|
|
9
|
-
Exclude:
|
|
10
|
-
- 'bin/**/*'
|
|
11
|
-
- 'vendor/**/*'
|
|
12
|
-
NewCops: enable
|
|
13
|
-
|
|
14
10
|
InternalAffairs/UndefinedConfig: # False positive because conflicts with Rubocop Layout namespace
|
|
15
11
|
Exclude:
|
|
16
12
|
- 'lib/rubocop/cop/vicenzo/layout/**/*'
|
|
17
13
|
|
|
18
|
-
Metrics/BlockLength:
|
|
19
|
-
Exclude:
|
|
20
|
-
- 'rakelib/**/*'
|
|
21
|
-
- 'Rakefile'
|
|
22
|
-
|
|
23
14
|
Naming/FileName:
|
|
24
15
|
Exclude:
|
|
25
16
|
- lib/rubocop-vicenzo.rb
|
|
26
17
|
|
|
27
|
-
RSpec/ContextWording:
|
|
28
|
-
Prefixes:
|
|
29
|
-
- and
|
|
30
|
-
- but
|
|
31
|
-
- when
|
|
32
|
-
- with
|
|
33
|
-
- without
|
|
34
|
-
|
|
35
18
|
RSpec/ExampleLength:
|
|
36
19
|
Enabled: false
|
|
37
20
|
|
|
38
|
-
RSpec/NestedGroups:
|
|
39
|
-
Enabled: false
|
|
40
|
-
|
|
41
21
|
Vicenzo/RSpec/LeakyDefinition:
|
|
42
22
|
Exclude:
|
|
43
23
|
- 'spec/support/**/*'
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.10.0](https://github.com/bvicenzo/rubocop-vicenzo/compare/v0.9.0...v0.10.0) (2026-10-23)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* add Vicenzo/RSpec/LetAliasingSubject cop ([#44](https://github.com/bvicenzo/rubocop-vicenzo/issues/44)) ([a8cebd3](https://github.com/bvicenzo/rubocop-vicenzo/commit/a8cebd3c0237e8805a58ff9efa7ca34f6beb34b0)), closes [#42](https://github.com/bvicenzo/rubocop-vicenzo/issues/42)
|
|
9
|
+
* add Vicenzo/Style/PreferManyOverSizeComparison cop ([#38](https://github.com/bvicenzo/rubocop-vicenzo/issues/38)) ([910ea02](https://github.com/bvicenzo/rubocop-vicenzo/commit/910ea026f7e4c46f9de27db580e6330cf845bfe7))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* report subjects that derive from an allowed method in SubjectIsMethodResult ([#41](https://github.com/bvicenzo/rubocop-vicenzo/issues/41)) ([a5efd33](https://github.com/bvicenzo/rubocop-vicenzo/commit/a5efd3330b32dd24b4291121a64e378091297a57)), closes [#40](https://github.com/bvicenzo/rubocop-vicenzo/issues/40)
|
|
15
|
+
* see subjects declared in shared groups in LetIsMethodResult and LetAliasingSubject ([#45](https://github.com/bvicenzo/rubocop-vicenzo/issues/45)) ([a98039e](https://github.com/bvicenzo/rubocop-vicenzo/commit/a98039e2cbea568267d8b7832b4717b763678d14)), closes [#43](https://github.com/bvicenzo/rubocop-vicenzo/issues/43)
|
|
16
|
+
|
|
17
|
+
## [0.9.0](https://github.com/bvicenzo/rubocop-vicenzo/compare/v0.8.0...v0.9.0) (2026-09-23)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* add Vicenzo/Naming/AnonymousUnusedName cop ([#33](https://github.com/bvicenzo/rubocop-vicenzo/issues/33)) ([fabbad6](https://github.com/bvicenzo/rubocop-vicenzo/commit/fabbad655dac0c362924dd0aaf245abd2c7023e1))
|
|
23
|
+
* add Vicenzo/Naming/ShortName cop and an opinionated config/style.yml ([#35](https://github.com/bvicenzo/rubocop-vicenzo/issues/35)) ([1b67f46](https://github.com/bvicenzo/rubocop-vicenzo/commit/1b67f4643b4348f5768a8fbb3b88cea35046e5e2))
|
|
24
|
+
* add Vicenzo/RSpec/DescribeInsideContext cop ([#37](https://github.com/bvicenzo/rubocop-vicenzo/issues/37)) ([3f3d6ae](https://github.com/bvicenzo/rubocop-vicenzo/commit/3f3d6aeb95d087e32594e8ded3d1ce0e3715dee7))
|
|
25
|
+
* add Vicenzo/RSpec/UnnestedContextImproperStart cop ([#36](https://github.com/bvicenzo/rubocop-vicenzo/issues/36)) ([0a8fb0f](https://github.com/bvicenzo/rubocop-vicenzo/commit/0a8fb0fec62370ac331b9a3275b95a0b22998b1d))
|
|
26
|
+
|
|
3
27
|
## [0.8.0](https://github.com/bvicenzo/rubocop-vicenzo/compare/v0.7.0...v0.8.0) (2026-09-09)
|
|
4
28
|
|
|
5
29
|
|
data/README.md
CHANGED
|
@@ -11,7 +11,7 @@ Add it to the `development`/`test` group of your `Gemfile`:
|
|
|
11
11
|
<!-- x-release-please-start-version -->
|
|
12
12
|
```ruby
|
|
13
13
|
group :development, :test do
|
|
14
|
-
gem 'rubocop-vicenzo', '~> 0.
|
|
14
|
+
gem 'rubocop-vicenzo', '~> 0.10.0', require: false
|
|
15
15
|
end
|
|
16
16
|
```
|
|
17
17
|
<!-- x-release-please-end-version -->
|
|
@@ -64,6 +64,31 @@ cops together with the standard cops.
|
|
|
64
64
|
rubocop --plugin rubocop-vicenzo
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
## Opinionated style guide
|
|
68
|
+
|
|
69
|
+
Loading the plugin gives you the `Vicenzo/*` cops and nothing else: their defaults
|
|
70
|
+
live in `config/default.yml` and are applied automatically.
|
|
71
|
+
|
|
72
|
+
The gem also ships `config/style.yml`, an opinionated configuration of the cops the
|
|
73
|
+
`Vicenzo/*` ones build on — line length, multiline layout, metrics, and the naming
|
|
74
|
+
rules that back `Vicenzo/Naming/ShortName` (notably `Naming/BlockParameterName`,
|
|
75
|
+
which RuboCop ships with `MinNameLength: 1` and which therefore never fires). It is
|
|
76
|
+
**opt-in**:
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
inherit_gem:
|
|
80
|
+
rubocop-vicenzo: config/style.yml
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
That single line brings the configuration **and** the plugins it builds on
|
|
84
|
+
(`rubocop-rspec` and this gem's own cops), so there is no `plugins:` key left for you
|
|
85
|
+
to write.
|
|
86
|
+
|
|
87
|
+
> [!NOTE]
|
|
88
|
+
> `AllCops: CacheRootDirectory` is not inheritable. RuboCop reads it from the
|
|
89
|
+
> top-level config file before resolving `inherit_from`/`inherit_gem`, so it has to
|
|
90
|
+
> stay in your own `.rubocop.yml`.
|
|
91
|
+
|
|
67
92
|
## Development
|
|
68
93
|
|
|
69
94
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/Rakefile
CHANGED
|
@@ -4,8 +4,8 @@ require 'bundler/setup'
|
|
|
4
4
|
require 'bundler/gem_tasks'
|
|
5
5
|
require 'rspec/core/rake_task'
|
|
6
6
|
|
|
7
|
-
RSpec::Core::RakeTask.new(:spec) do |
|
|
8
|
-
|
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |rspec_task|
|
|
8
|
+
rspec_task.rspec_opts = '--format progress'
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
require 'rubocop/rake_task'
|
data/config/default.yml
CHANGED
|
@@ -5,6 +5,19 @@ Vicenzo/Layout/MultilineMethodCallLineBreaks:
|
|
|
5
5
|
IndentationWidth: 2
|
|
6
6
|
VersionAdded: '0.3.0'
|
|
7
7
|
|
|
8
|
+
Vicenzo/Naming/AnonymousUnusedName:
|
|
9
|
+
Description: 'An unused declaration must not be anonymous; name it after what it stands for.'
|
|
10
|
+
Enabled: true
|
|
11
|
+
Severity: convention
|
|
12
|
+
VersionAdded: '0.9.0'
|
|
13
|
+
|
|
14
|
+
Vicenzo/Naming/ShortName:
|
|
15
|
+
Description: 'A name too short to carry meaning; spell out whole words from the domain.'
|
|
16
|
+
Enabled: true
|
|
17
|
+
Severity: convention
|
|
18
|
+
MinNameLength: 3
|
|
19
|
+
VersionAdded: '0.9.0'
|
|
20
|
+
|
|
8
21
|
Vicenzo/Rails/EnumInclusionOfValidation:
|
|
9
22
|
Description: 'Check if the enum has the inclusion of validation defined.'
|
|
10
23
|
Enabled: true
|
|
@@ -45,6 +58,17 @@ Vicenzo/RSpec/DerivedPremises:
|
|
|
45
58
|
- '**/spec/factories/**/*'
|
|
46
59
|
VersionAdded: '0.6.0'
|
|
47
60
|
|
|
61
|
+
Vicenzo/RSpec/DescribeInsideContext:
|
|
62
|
+
Description: 'A describe must not be nested in a context, which is a scenario of the behaviour a describe names.'
|
|
63
|
+
Enabled: true
|
|
64
|
+
Severity: warning
|
|
65
|
+
Include:
|
|
66
|
+
- '**/spec/**/*_spec.rb'
|
|
67
|
+
Exclude:
|
|
68
|
+
- '**/spec/support/**/*'
|
|
69
|
+
- '**/spec/factories/**/*'
|
|
70
|
+
VersionAdded: '0.9.0'
|
|
71
|
+
|
|
48
72
|
Vicenzo/RSpec/DynamicExampleGeneration:
|
|
49
73
|
Description: 'Do not use iteration to dynamically generate example groups or examples.'
|
|
50
74
|
Enabled: true
|
|
@@ -103,6 +127,17 @@ Vicenzo/RSpec/LeakyDefinition:
|
|
|
103
127
|
- '**/spec/support/**/*'
|
|
104
128
|
- '**/spec/factories/**/*'
|
|
105
129
|
|
|
130
|
+
Vicenzo/RSpec/LetAliasingSubject:
|
|
131
|
+
Description: 'A let must not hold the subject itself under another name.'
|
|
132
|
+
Enabled: true
|
|
133
|
+
Severity: convention
|
|
134
|
+
Include:
|
|
135
|
+
- '**/spec/**/*_spec.rb'
|
|
136
|
+
Exclude:
|
|
137
|
+
- '**/spec/support/**/*'
|
|
138
|
+
- '**/spec/factories/**/*'
|
|
139
|
+
VersionAdded: '0.10.0'
|
|
140
|
+
|
|
106
141
|
Vicenzo/RSpec/LetIsMethodResult:
|
|
107
142
|
Description: 'A let under an example group describing a method must not hold the result of calling that method on the subject.'
|
|
108
143
|
Enabled: true
|
|
@@ -194,6 +229,21 @@ Vicenzo/RSpec/TopLevelSubject:
|
|
|
194
229
|
- '**/spec/factories/**/*'
|
|
195
230
|
VersionAdded: '0.8.0'
|
|
196
231
|
|
|
232
|
+
Vicenzo/RSpec/UnnestedContextImproperStart:
|
|
233
|
+
Description: 'Check if a context with no parent scenario starts with a conjunction.'
|
|
234
|
+
Enabled: true
|
|
235
|
+
Severity: convention
|
|
236
|
+
ForbiddenPrefixes:
|
|
237
|
+
- and
|
|
238
|
+
- but
|
|
239
|
+
- however
|
|
240
|
+
Include:
|
|
241
|
+
- '**/spec/**/*_spec.rb'
|
|
242
|
+
Exclude:
|
|
243
|
+
- '**/spec/support/**/*'
|
|
244
|
+
- '**/spec/factories/**/*'
|
|
245
|
+
VersionAdded: '0.9.0'
|
|
246
|
+
|
|
197
247
|
Vicenzo/Style/JsonParseSymbolizeNames:
|
|
198
248
|
Description: 'Enforces passing `symbolize_names: true` to `JSON.parse` so keys are symbols.'
|
|
199
249
|
Enabled: true
|
|
@@ -205,3 +255,10 @@ Vicenzo/Style/MultilineMethodCallParentheses:
|
|
|
205
255
|
Enabled: true
|
|
206
256
|
AllowedMethods: []
|
|
207
257
|
VersionAdded: '0.3.0'
|
|
258
|
+
|
|
259
|
+
Vicenzo/Style/PreferManyOverSizeComparison:
|
|
260
|
+
Description: 'Use many? instead of comparing size or length with one.'
|
|
261
|
+
Enabled: true
|
|
262
|
+
Severity: convention
|
|
263
|
+
SafeAutoCorrect: false
|
|
264
|
+
VersionAdded: '0.10.0'
|
data/config/style.yml
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
plugins:
|
|
2
|
+
- rubocop-vicenzo
|
|
3
|
+
- rubocop-rspec
|
|
4
|
+
|
|
5
|
+
AllCops:
|
|
6
|
+
SuggestExtensions: false
|
|
7
|
+
NewCops: enable
|
|
8
|
+
Exclude:
|
|
9
|
+
- 'node_modules/**/*'
|
|
10
|
+
- 'vendor/**/*'
|
|
11
|
+
- 'bin/**/*'
|
|
12
|
+
- '.git/**/*'
|
|
13
|
+
- 'db/**/*'
|
|
14
|
+
|
|
15
|
+
##### LAYOUT #####
|
|
16
|
+
|
|
17
|
+
Layout/ArgumentAlignment:
|
|
18
|
+
Enabled: true
|
|
19
|
+
EnforcedStyle: with_fixed_indentation
|
|
20
|
+
|
|
21
|
+
Layout/CaseIndentation:
|
|
22
|
+
Enabled: true
|
|
23
|
+
EnforcedStyle: end
|
|
24
|
+
|
|
25
|
+
Layout/EndAlignment:
|
|
26
|
+
Enabled: true
|
|
27
|
+
EnforcedStyleAlignWith: variable
|
|
28
|
+
|
|
29
|
+
Layout/FirstArgumentIndentation:
|
|
30
|
+
Enabled: true
|
|
31
|
+
EnforcedStyle: consistent
|
|
32
|
+
|
|
33
|
+
Layout/FirstArrayElementIndentation:
|
|
34
|
+
Enabled: true
|
|
35
|
+
EnforcedStyle: consistent
|
|
36
|
+
|
|
37
|
+
Layout/FirstHashElementIndentation:
|
|
38
|
+
Enabled: true
|
|
39
|
+
EnforcedStyle: consistent
|
|
40
|
+
|
|
41
|
+
Layout/FirstMethodArgumentLineBreak:
|
|
42
|
+
Enabled: true
|
|
43
|
+
|
|
44
|
+
Layout/LineLength:
|
|
45
|
+
Max: 120
|
|
46
|
+
# (\A|\s) -> Start of line or whitespace
|
|
47
|
+
# # -> The hash character
|
|
48
|
+
# (?!\{) -> Negative lookahead: NOT followed by `{` (prevents matching interpolation)
|
|
49
|
+
AllowedPatterns: ['(\A|\s)#(?!\{)']
|
|
50
|
+
|
|
51
|
+
Layout/MultilineMethodArgumentLineBreaks:
|
|
52
|
+
Enabled: true
|
|
53
|
+
|
|
54
|
+
Layout/MultilineMethodCallBraceLayout:
|
|
55
|
+
Enabled: true
|
|
56
|
+
EnforcedStyle: new_line
|
|
57
|
+
|
|
58
|
+
Layout/MultilineMethodCallIndentation:
|
|
59
|
+
Enabled: true
|
|
60
|
+
EnforcedStyle: indented
|
|
61
|
+
|
|
62
|
+
Layout/FirstArrayElementLineBreak:
|
|
63
|
+
Enabled: true
|
|
64
|
+
|
|
65
|
+
Layout/MultilineArrayLineBreaks:
|
|
66
|
+
Enabled: true
|
|
67
|
+
|
|
68
|
+
Layout/MultilineArrayBraceLayout:
|
|
69
|
+
Enabled: true
|
|
70
|
+
EnforcedStyle: new_line
|
|
71
|
+
|
|
72
|
+
Layout/FirstHashElementLineBreak:
|
|
73
|
+
Enabled: true
|
|
74
|
+
|
|
75
|
+
Layout/MultilineHashKeyLineBreaks:
|
|
76
|
+
Enabled: true
|
|
77
|
+
|
|
78
|
+
Layout/MultilineHashBraceLayout:
|
|
79
|
+
Enabled: true
|
|
80
|
+
EnforcedStyle: new_line
|
|
81
|
+
|
|
82
|
+
##### STYLE #####
|
|
83
|
+
|
|
84
|
+
Style/PreferredHashMethods:
|
|
85
|
+
Enabled: true
|
|
86
|
+
Safe: false
|
|
87
|
+
EnforcedStyle: verbose
|
|
88
|
+
|
|
89
|
+
Style/SymbolArray:
|
|
90
|
+
Enabled: true
|
|
91
|
+
EnforcedStyle: percent
|
|
92
|
+
MinSize: 3
|
|
93
|
+
|
|
94
|
+
Style/WordArray:
|
|
95
|
+
Enabled: true
|
|
96
|
+
EnforcedStyle: percent
|
|
97
|
+
MinSize: 3
|
|
98
|
+
|
|
99
|
+
Style/MultilineBlockChain:
|
|
100
|
+
Enabled: false
|
|
101
|
+
|
|
102
|
+
Style/Lambda:
|
|
103
|
+
Enabled: true
|
|
104
|
+
EnforcedStyle: literal
|
|
105
|
+
|
|
106
|
+
Style/LambdaCall:
|
|
107
|
+
Enabled: false
|
|
108
|
+
|
|
109
|
+
Style/Documentation:
|
|
110
|
+
Enabled: false
|
|
111
|
+
|
|
112
|
+
##### LINT #####
|
|
113
|
+
|
|
114
|
+
Lint/MissingSuper:
|
|
115
|
+
Enabled: false
|
|
116
|
+
|
|
117
|
+
##### NAMING #####
|
|
118
|
+
|
|
119
|
+
Naming/InclusiveLanguage:
|
|
120
|
+
Enabled: false
|
|
121
|
+
|
|
122
|
+
Naming/PredicatePrefix:
|
|
123
|
+
ForbiddenPrefixes:
|
|
124
|
+
- is_
|
|
125
|
+
- have_
|
|
126
|
+
# allows `has_` predicate
|
|
127
|
+
|
|
128
|
+
# A single letter says nothing about what was rescued.
|
|
129
|
+
Naming/RescuedExceptionsVariableName:
|
|
130
|
+
Enabled: true
|
|
131
|
+
PreferredName: error
|
|
132
|
+
|
|
133
|
+
# Vicenzo/Naming/ShortName covers local variables. Block parameters are the core
|
|
134
|
+
# cop's job, but it ships with MinNameLength: 1 and therefore never fires — raise
|
|
135
|
+
# it so both halves of the rule agree.
|
|
136
|
+
Naming/BlockParameterName:
|
|
137
|
+
MinNameLength: 3
|
|
138
|
+
|
|
139
|
+
###### METRICS #####
|
|
140
|
+
|
|
141
|
+
Metrics/AbcSize:
|
|
142
|
+
Enabled: true
|
|
143
|
+
Max: 22
|
|
144
|
+
|
|
145
|
+
Metrics/BlockLength:
|
|
146
|
+
Enabled: true
|
|
147
|
+
CountComments: false
|
|
148
|
+
CountAsOne:
|
|
149
|
+
- array
|
|
150
|
+
- hash
|
|
151
|
+
- heredoc
|
|
152
|
+
- method_call
|
|
153
|
+
AllowedMethods:
|
|
154
|
+
- 'describe'
|
|
155
|
+
- 'context'
|
|
156
|
+
- 'it'
|
|
157
|
+
- 'let'
|
|
158
|
+
- 'subject'
|
|
159
|
+
- 'namespace'
|
|
160
|
+
- 'task'
|
|
161
|
+
- 'configure'
|
|
162
|
+
Exclude:
|
|
163
|
+
- '**/*.gemspec'
|
|
164
|
+
- 'Rakefile'
|
|
165
|
+
- 'rakelib/**/*'
|
|
166
|
+
- 'spec/**/*'
|
|
167
|
+
|
|
168
|
+
Metrics/ClassLength:
|
|
169
|
+
Enabled: true
|
|
170
|
+
Max: 200
|
|
171
|
+
CountAsOne:
|
|
172
|
+
- array
|
|
173
|
+
- hash
|
|
174
|
+
- heredoc
|
|
175
|
+
- method_call
|
|
176
|
+
|
|
177
|
+
Metrics/MethodLength:
|
|
178
|
+
Enabled: true
|
|
179
|
+
CountAsOne:
|
|
180
|
+
- array
|
|
181
|
+
- hash
|
|
182
|
+
- heredoc
|
|
183
|
+
- method_call
|
|
184
|
+
Max: 20
|
|
185
|
+
|
|
186
|
+
Metrics/ModuleLength:
|
|
187
|
+
Enabled: true
|
|
188
|
+
Max: 200
|
|
189
|
+
CountAsOne:
|
|
190
|
+
- array
|
|
191
|
+
- hash
|
|
192
|
+
- heredoc
|
|
193
|
+
- method_call
|
|
194
|
+
|
|
195
|
+
##### RSPEC #####
|
|
196
|
+
|
|
197
|
+
RSpec/ContextWording:
|
|
198
|
+
Prefixes:
|
|
199
|
+
- and
|
|
200
|
+
- but
|
|
201
|
+
- when
|
|
202
|
+
- with
|
|
203
|
+
- without
|
|
204
|
+
|
|
205
|
+
RSpec/ExampleLength:
|
|
206
|
+
Max: 20
|
|
207
|
+
CountAsOne:
|
|
208
|
+
- array
|
|
209
|
+
- hash
|
|
210
|
+
- heredoc
|
|
211
|
+
- method_call
|
|
212
|
+
|
|
213
|
+
RSpec/MultipleMemoizedHelpers:
|
|
214
|
+
Max: 10
|
|
215
|
+
|
|
216
|
+
RSpec/NestedGroups:
|
|
217
|
+
Enabled: false
|
|
218
|
+
|
|
219
|
+
RSpec/PredicateMatcher:
|
|
220
|
+
Strict: false
|
|
221
|
+
|
|
222
|
+
##### VICENZO #####
|
|
223
|
+
|
|
224
|
+
Vicenzo/Style/MultilineMethodCallParentheses:
|
|
225
|
+
AllowedMethods:
|
|
226
|
+
- to
|
|
227
|
+
- not_to
|
|
228
|
+
- to_not
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Vicenzo
|
|
6
|
+
module Naming
|
|
7
|
+
# Requires every declaration to carry a name, even when the value it
|
|
8
|
+
# holds is not used.
|
|
9
|
+
#
|
|
10
|
+
# A bare `_` states that a value is being ignored, but erases what that
|
|
11
|
+
# value is. Unused today does not mean unusable tomorrow: when the code
|
|
12
|
+
# grows, nobody reading the signature can tell whether the discarded
|
|
13
|
+
# value is the one the new problem needs.
|
|
14
|
+
#
|
|
15
|
+
# The cop only demands that a name exists — it cannot judge whether a
|
|
16
|
+
# name is a good one. That is the author's call, and the offense message
|
|
17
|
+
# asks for a name taken from the domain (`_previous_owner`) rather than
|
|
18
|
+
# one taken from the shape of the value (`_value`, `_key`, `_item`).
|
|
19
|
+
#
|
|
20
|
+
# Anonymous forwarding parameters (`*`, `**`, `&`, `...`) are ignored:
|
|
21
|
+
# they forward arguments instead of discarding them, and `Style/ArgumentsForwarding`
|
|
22
|
+
# actively pushes code towards that form.
|
|
23
|
+
#
|
|
24
|
+
# @example block parameters
|
|
25
|
+
# # bad
|
|
26
|
+
# catalog.each { |_, copies| copies.each(&:reserve) }
|
|
27
|
+
#
|
|
28
|
+
# # good
|
|
29
|
+
# catalog.each { |_isbn, copies| copies.each(&:reserve) }
|
|
30
|
+
#
|
|
31
|
+
# @example destructured block parameters
|
|
32
|
+
# # bad
|
|
33
|
+
# entries.each { |(_, id)| track(id) }
|
|
34
|
+
#
|
|
35
|
+
# # good
|
|
36
|
+
# entries.each { |(_label, id)| track(id) }
|
|
37
|
+
#
|
|
38
|
+
# @example method parameters
|
|
39
|
+
# # bad
|
|
40
|
+
# def notify(reader, _)
|
|
41
|
+
# reader.deliver
|
|
42
|
+
# end
|
|
43
|
+
#
|
|
44
|
+
# # good
|
|
45
|
+
# def notify(reader, _delivery_channel)
|
|
46
|
+
# reader.deliver
|
|
47
|
+
# end
|
|
48
|
+
#
|
|
49
|
+
# @example multiple assignment
|
|
50
|
+
# # bad
|
|
51
|
+
# title, _ = line.split(';')
|
|
52
|
+
#
|
|
53
|
+
# # good
|
|
54
|
+
# title, _author = line.split(';')
|
|
55
|
+
#
|
|
56
|
+
# @example rescued errors
|
|
57
|
+
# # bad
|
|
58
|
+
# begin
|
|
59
|
+
# shelf.reorder
|
|
60
|
+
# rescue ShelfLocked => _
|
|
61
|
+
# shelf.skip
|
|
62
|
+
# end
|
|
63
|
+
#
|
|
64
|
+
# # good
|
|
65
|
+
# begin
|
|
66
|
+
# shelf.reorder
|
|
67
|
+
# rescue ShelfLocked => _lock_conflict
|
|
68
|
+
# shelf.skip
|
|
69
|
+
# end
|
|
70
|
+
#
|
|
71
|
+
# @example anonymous forwarding (ignored)
|
|
72
|
+
# # good
|
|
73
|
+
# def notify(*)
|
|
74
|
+
# channel.deliver(*)
|
|
75
|
+
# end
|
|
76
|
+
#
|
|
77
|
+
# # good
|
|
78
|
+
# def notify(...)
|
|
79
|
+
# channel.deliver(...)
|
|
80
|
+
# end
|
|
81
|
+
class AnonymousUnusedName < Base
|
|
82
|
+
MSG = 'Name this %<subject>s: an unused value still means something, and `_` hides what. ' \
|
|
83
|
+
'Name it after what it stands for in the domain (`_previous_owner`), not after its ' \
|
|
84
|
+
'shape (`_value`, `_key`, `_item`) — that tells the next reader nothing.'
|
|
85
|
+
|
|
86
|
+
BLOCK_PARAMETER = 'block parameter'
|
|
87
|
+
METHOD_PARAMETER = 'method parameter'
|
|
88
|
+
DISCARDED_VALUE = 'discarded value'
|
|
89
|
+
RESCUED_ERROR = 'rescued error'
|
|
90
|
+
|
|
91
|
+
ANONYMOUS_NAME_PATTERN = /\A_+\z/
|
|
92
|
+
|
|
93
|
+
NAMED_ARGUMENT_TYPES = %i[arg optarg restarg kwarg kwoptarg kwrestarg blockarg shadowarg].freeze
|
|
94
|
+
DEFAULT_VALUE_ARGUMENT_TYPES = %i[optarg kwoptarg].freeze
|
|
95
|
+
|
|
96
|
+
# Numbered (`_1`) and implicit (`it`) block parameters are never
|
|
97
|
+
# declared, so they carry no name to check — both node types answer
|
|
98
|
+
# `arguments` with an empty list.
|
|
99
|
+
def on_block(node)
|
|
100
|
+
check_arguments(node.arguments, BLOCK_PARAMETER)
|
|
101
|
+
end
|
|
102
|
+
alias on_numblock on_block
|
|
103
|
+
alias on_itblock on_block
|
|
104
|
+
|
|
105
|
+
def on_def(node)
|
|
106
|
+
check_arguments(node.arguments, METHOD_PARAMETER)
|
|
107
|
+
end
|
|
108
|
+
alias on_defs on_def
|
|
109
|
+
|
|
110
|
+
def on_masgn(node)
|
|
111
|
+
node.lhs.assignments.each do |assignment|
|
|
112
|
+
next unless assignment.respond_to?(:lvasgn_type?) && assignment.lvasgn_type?
|
|
113
|
+
|
|
114
|
+
register_offense(assignment, DISCARDED_VALUE) if anonymous_name?(assignment.children.first)
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def on_resbody(node)
|
|
119
|
+
error = node.exception_variable
|
|
120
|
+
return if error.nil?
|
|
121
|
+
|
|
122
|
+
register_offense(error, RESCUED_ERROR) if anonymous_name?(error.children.first)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def check_arguments(arguments, subject)
|
|
128
|
+
arguments.each do |argument|
|
|
129
|
+
if argument.mlhs_type?
|
|
130
|
+
check_arguments(argument.children, subject)
|
|
131
|
+
elsif anonymous_argument?(argument)
|
|
132
|
+
register_offense(argument_range(argument), subject)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
# An anonymous forwarding parameter (`*`, `**`, `&`) carries no name
|
|
138
|
+
# child at all, and `...` is a `forward_arg`, outside the listed types.
|
|
139
|
+
# Both fall through as allowed.
|
|
140
|
+
def anonymous_argument?(argument)
|
|
141
|
+
NAMED_ARGUMENT_TYPES.include?(argument.type) && anonymous_name?(argument.children.first)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# An argument carrying a default value spans the whole expression, so
|
|
145
|
+
# only its name is highlighted; every other form is short enough that
|
|
146
|
+
# showing it whole (`*_`, `**_`, `&_`) tells the reader more.
|
|
147
|
+
def argument_range(argument)
|
|
148
|
+
return argument.loc.name if DEFAULT_VALUE_ARGUMENT_TYPES.include?(argument.type)
|
|
149
|
+
|
|
150
|
+
argument.source_range
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def anonymous_name?(name)
|
|
154
|
+
!name.nil? && ANONYMOUS_NAME_PATTERN.match?(name.to_s)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def register_offense(node, subject)
|
|
158
|
+
add_offense(node, message: format(MSG, subject: subject))
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
end
|