rubocop 1.75.8 → 1.76.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/README.md +19 -13
- data/config/default.yml +48 -5
- data/config/obsoletion.yml +6 -3
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +2 -2
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +1 -0
- data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- data/lib/rubocop/cop/lint/literal_as_condition.rb +16 -24
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +87 -0
- data/lib/rubocop/cop/lint/useless_or.rb +98 -0
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_method.rb +216 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +2 -2
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -4
- data/lib/rubocop/cop/style/it_block_parameter.rb +33 -14
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +48 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +16 -5
- data/lib/rubocop/cop/style/safe_navigation.rb +10 -7
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +6 -1
- metadata +12 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 236bdf0fa5879274099388142e17b886fc852cdc1e762d50c74a31254c7c6136
|
4
|
+
data.tar.gz: 03011b196c686aa5ce1cc617d56c19041dbdc76ba237626316048be9e75dc62c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 91eb23282705c816206704923efdea2cb45ad09677a5d72a8741a565d9ed96146ad688aa54c1dc5be7f6d83c6e4d099605bdd91cb941d0d2b1fb36ace05b02a8
|
7
|
+
data.tar.gz: 6ff783d52e62e4dda5cae1c78f8648ef8af4078c5f052134a23c9229018e33d29a21d3ecaa80bfdc74d382b73a1a666f67d9e1b3436b1dfb5745a96861cf92ec
|
data/README.md
CHANGED
@@ -36,10 +36,11 @@ Working on RuboCop is often fun, but it also requires a great deal of time and e
|
|
36
36
|
**RuboCop**'s installation is pretty standard:
|
37
37
|
|
38
38
|
```sh
|
39
|
-
|
39
|
+
gem install rubocop
|
40
40
|
```
|
41
41
|
|
42
|
-
If you'd rather install RuboCop using `bundler`, add a line for it in your
|
42
|
+
If you'd rather install RuboCop using `bundler`, add a line for it in your
|
43
|
+
`Gemfile` (but set the `require` option to `false`, as it is a standalone tool):
|
43
44
|
|
44
45
|
```rb
|
45
46
|
gem 'rubocop', require: false
|
@@ -52,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
|
|
52
53
|
in your `Gemfile`:
|
53
54
|
|
54
55
|
```rb
|
55
|
-
gem 'rubocop', '~> 1.
|
56
|
+
gem 'rubocop', '~> 1.76', require: false
|
56
57
|
```
|
57
58
|
|
58
59
|
See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
|
@@ -61,12 +62,15 @@ See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) fo
|
|
61
62
|
|
62
63
|
Just type `rubocop` in a Ruby project's folder and watch the magic happen.
|
63
64
|
|
64
|
-
```
|
65
|
-
|
66
|
-
|
65
|
+
```sh
|
66
|
+
cd my/cool/ruby/project
|
67
|
+
rubocop
|
67
68
|
```
|
68
69
|
|
69
|
-
|
70
|
+
> [!TIP]
|
71
|
+
>
|
72
|
+
> You can also use this magic in your favorite editor with RuboCop's
|
73
|
+
> [built-in LSP server](https://docs.rubocop.org/rubocop/usage/lsp.html).
|
70
74
|
|
71
75
|
## Documentation
|
72
76
|
|
@@ -79,7 +83,7 @@ RuboCop officially supports the following runtime Ruby implementations:
|
|
79
83
|
* MRI 2.7+
|
80
84
|
* JRuby 9.4+
|
81
85
|
|
82
|
-
|
86
|
+
It targets Ruby 2.0+ for code analysis.
|
83
87
|
|
84
88
|
See the [compatibility documentation](https://docs.rubocop.org/rubocop/compatibility.html) for further details.
|
85
89
|
|
@@ -91,7 +95,6 @@ If you use RuboCop in your project, you can include one of these badges in your
|
|
91
95
|
|
92
96
|
[](https://rubystyle.guide)
|
93
97
|
|
94
|
-
|
95
98
|
Here are the Markdown snippets for the two badges:
|
96
99
|
|
97
100
|
``` markdown
|
@@ -157,8 +160,8 @@ wide array of funding channels to account for your preferences
|
|
157
160
|
currently [Open Collective](https://opencollective.com/rubocop) is our
|
158
161
|
preferred funding platform).
|
159
162
|
|
160
|
-
**If you're working in a company that's making significant use of RuboCop we'd
|
161
|
-
to become a RuboCop sponsor.**
|
163
|
+
**If you're working in a company that's making significant use of RuboCop we'd
|
164
|
+
appreciate it if you suggest to your company to become a RuboCop sponsor.**
|
162
165
|
|
163
166
|
You can support the development of RuboCop via
|
164
167
|
[GitHub Sponsors](https://github.com/sponsors/bbatsov),
|
@@ -168,8 +171,11 @@ You can support the development of RuboCop via
|
|
168
171
|
and [Tidelift](https://tidelift.com/subscription/pkg/rubygems-rubocop?utm_source=rubygems-rubocop&utm_medium=referral&utm_campaign=readme)
|
169
172
|
.
|
170
173
|
|
171
|
-
|
172
|
-
|
174
|
+
> [!NOTE]
|
175
|
+
>
|
176
|
+
> If doing a sponsorship in the form of donation is problematic for your company
|
177
|
+
> from an accounting standpoint, we'd recommend the use of Tidelift, where you
|
178
|
+
> can get a support-like subscription instead.
|
173
179
|
|
174
180
|
### Open Collective for Individuals
|
175
181
|
|
data/config/default.yml
CHANGED
@@ -1923,7 +1923,7 @@ Lint/EmptyInterpolation:
|
|
1923
1923
|
Enabled: true
|
1924
1924
|
AutoCorrect: contextual
|
1925
1925
|
VersionAdded: '0.20'
|
1926
|
-
VersionChanged: '1.
|
1926
|
+
VersionChanged: '1.76'
|
1927
1927
|
|
1928
1928
|
Lint/EmptyWhen:
|
1929
1929
|
Description: 'Checks for `when` branches with empty bodies.'
|
@@ -2423,8 +2423,9 @@ Lint/ShadowingOuterLocalVariable:
|
|
2423
2423
|
Description: >-
|
2424
2424
|
Do not use the same name as outer local variable
|
2425
2425
|
for block arguments or block local variables.
|
2426
|
-
Enabled:
|
2426
|
+
Enabled: false
|
2427
2427
|
VersionAdded: '0.9'
|
2428
|
+
VersionChanged: '1.76'
|
2428
2429
|
|
2429
2430
|
Lint/SharedMutableDefault:
|
2430
2431
|
Description: 'Checks for mutable literals used as default arguments during Hash initialization.'
|
@@ -2612,6 +2613,13 @@ Lint/UselessConstantScoping:
|
|
2612
2613
|
Enabled: pending
|
2613
2614
|
VersionAdded: '1.72'
|
2614
2615
|
|
2616
|
+
Lint/UselessDefaultValueArgument:
|
2617
|
+
Description: 'Checks for usage of `fetch` or `Array.new` with default value argument and block.'
|
2618
|
+
Enabled: pending
|
2619
|
+
VersionAdded: '1.76'
|
2620
|
+
Safe: false
|
2621
|
+
AllowedReceivers: []
|
2622
|
+
|
2615
2623
|
Lint/UselessDefined:
|
2616
2624
|
Description: 'Checks for calls to `defined?` with strings and symbols. The result of such a call will always be truthy.'
|
2617
2625
|
Enabled: pending
|
@@ -2636,6 +2644,11 @@ Lint/UselessNumericOperation:
|
|
2636
2644
|
Enabled: pending
|
2637
2645
|
VersionAdded: '1.66'
|
2638
2646
|
|
2647
|
+
Lint/UselessOr:
|
2648
|
+
Description: 'Checks for useless OR expressions.'
|
2649
|
+
Enabled: pending
|
2650
|
+
VersionAdded: '1.76'
|
2651
|
+
|
2639
2652
|
Lint/UselessRescue:
|
2640
2653
|
Description: 'Checks for useless `rescue`s.'
|
2641
2654
|
Enabled: pending
|
@@ -3046,8 +3059,20 @@ Naming/MethodParameterName:
|
|
3046
3059
|
# Forbidden names that will register an offense
|
3047
3060
|
ForbiddenNames: []
|
3048
3061
|
|
3049
|
-
Naming/
|
3050
|
-
Description: '
|
3062
|
+
Naming/PredicateMethod:
|
3063
|
+
Description: 'Checks that predicate methods end with `?` and non-predicate methods do not.'
|
3064
|
+
Enabled: pending
|
3065
|
+
VersionAdded: '1.76'
|
3066
|
+
# In `aggressive` mode, the cop will register an offense for predicate methods that
|
3067
|
+
# may return a non-boolean value.
|
3068
|
+
# In `conservative` mode, the cop will *not* register an offense for predicate methods
|
3069
|
+
# that may return a non-boolean value.
|
3070
|
+
Mode: conservative
|
3071
|
+
AllowedMethods:
|
3072
|
+
- call
|
3073
|
+
|
3074
|
+
Naming/PredicatePrefix:
|
3075
|
+
Description: 'Predicate method names should not be prefixed and end with a `?`.'
|
3051
3076
|
StyleGuide: '#bool-methods-qmark'
|
3052
3077
|
Enabled: true
|
3053
3078
|
VersionAdded: '0.50'
|
@@ -3939,6 +3964,16 @@ Style/EmptyMethod:
|
|
3939
3964
|
- compact
|
3940
3965
|
- expanded
|
3941
3966
|
|
3967
|
+
Style/EmptyStringInsideInterpolation:
|
3968
|
+
Description: 'Checks for empty strings being assigned inside string interpolation.'
|
3969
|
+
StyleGuide: '#empty-strings-in-interpolation'
|
3970
|
+
Enabled: pending
|
3971
|
+
EnforcedStyle: trailing_conditional
|
3972
|
+
SupportedStyles:
|
3973
|
+
- trailing_conditional
|
3974
|
+
- ternary
|
3975
|
+
VersionAdded: '1.76'
|
3976
|
+
|
3942
3977
|
Style/Encoding:
|
3943
3978
|
Description: 'Use UTF-8 as the source file encoding.'
|
3944
3979
|
StyleGuide: '#utf-8'
|
@@ -4433,12 +4468,14 @@ Style/ItAssignment:
|
|
4433
4468
|
Style/ItBlockParameter:
|
4434
4469
|
Description: 'Checks for blocks with one argument where `it` block parameter can be used.'
|
4435
4470
|
Enabled: pending
|
4436
|
-
EnforcedStyle:
|
4471
|
+
EnforcedStyle: allow_single_line
|
4437
4472
|
SupportedStyles:
|
4473
|
+
- allow_single_line
|
4438
4474
|
- only_numbered_parameters
|
4439
4475
|
- always
|
4440
4476
|
- disallow
|
4441
4477
|
VersionAdded: '1.75'
|
4478
|
+
VersionChanged: '1.76'
|
4442
4479
|
|
4443
4480
|
Style/KeywordArgumentsMerging:
|
4444
4481
|
Description: >-
|
@@ -5151,6 +5188,12 @@ Style/RedundantArrayConstructor:
|
|
5151
5188
|
Enabled: pending
|
5152
5189
|
VersionAdded: '1.52'
|
5153
5190
|
|
5191
|
+
Style/RedundantArrayFlatten:
|
5192
|
+
Description: 'Checks for redundant calls of `Array#flatten`.'
|
5193
|
+
Enabled: pending
|
5194
|
+
Safe: false
|
5195
|
+
VersionAdded: '1.76'
|
5196
|
+
|
5154
5197
|
Style/RedundantAssignment:
|
5155
5198
|
Description: 'Checks for redundant assignment before returning.'
|
5156
5199
|
Enabled: true
|
data/config/obsoletion.yml
CHANGED
@@ -31,6 +31,9 @@ renamed:
|
|
31
31
|
Lint/UnneededRequireStatement: Lint/RedundantRequireStatement
|
32
32
|
Lint/UnneededSplatExpansion: Lint/RedundantSplatExpansion
|
33
33
|
Metrics/LineLength: Layout/LineLength
|
34
|
+
Naming/PredicateName:
|
35
|
+
new_name: Naming/PredicatePrefix
|
36
|
+
severity: warning
|
34
37
|
Naming/UncommunicativeBlockParamName: Naming/BlockParameterName
|
35
38
|
Naming/UncommunicativeMethodParamName: Naming/MethodParameterName
|
36
39
|
Style/AccessorMethodName: Naming/AccessorMethodName
|
@@ -44,7 +47,7 @@ renamed:
|
|
44
47
|
Style/MethodName: Naming/MethodName
|
45
48
|
Style/OpMethod: Naming/BinaryOperatorParameterName
|
46
49
|
Style/PredicateName:
|
47
|
-
new_name: Naming/
|
50
|
+
new_name: Naming/PredicatePrefix
|
48
51
|
severity: warning
|
49
52
|
Style/SingleSpaceBeforeFirstArg: Layout/SpaceBeforeFirstArg
|
50
53
|
Style/UnneededCapitalW: Style/RedundantCapitalW
|
@@ -179,10 +182,10 @@ changed_parameters:
|
|
179
182
|
- cops: Naming/HeredocDelimiterNaming
|
180
183
|
parameters: Blacklist
|
181
184
|
alternative: ForbiddenDelimiters
|
182
|
-
- cops: Naming/
|
185
|
+
- cops: Naming/PredicatePrefix
|
183
186
|
parameters: NamePrefixBlacklist
|
184
187
|
alternative: ForbiddenPrefixes
|
185
|
-
- cops: Naming/
|
188
|
+
- cops: Naming/PredicatePrefix
|
186
189
|
parameters: NameWhitelist
|
187
190
|
alternative: AllowedMethods
|
188
191
|
- cops:
|
@@ -45,7 +45,7 @@ module RuboCop
|
|
45
45
|
|
46
46
|
gem_declarations(processed_source.ast)
|
47
47
|
.each_cons(2) do |previous, current|
|
48
|
-
next unless consecutive_lines(previous, current)
|
48
|
+
next unless consecutive_lines?(previous, current)
|
49
49
|
next unless case_insensitive_out_of_order?(gem_name(current), gem_name(previous))
|
50
50
|
|
51
51
|
register_offense(previous, current)
|
@@ -57,13 +57,13 @@ module RuboCop
|
|
57
57
|
# @!method assignment_method_declarations(node)
|
58
58
|
def_node_search :assignment_method_declarations, <<~PATTERN
|
59
59
|
(send
|
60
|
-
(lvar #match_block_variable_name?) _ ...)
|
60
|
+
(lvar {#match_block_variable_name? :_1 :it}) _ ...)
|
61
61
|
PATTERN
|
62
62
|
|
63
63
|
# @!method indexed_assignment_method_declarations(node)
|
64
64
|
def_node_search :indexed_assignment_method_declarations, <<~PATTERN
|
65
65
|
(send
|
66
|
-
(send (lvar #match_block_variable_name?) _)
|
66
|
+
(send (lvar {#match_block_variable_name? :_1 :it}) _)
|
67
67
|
:[]=
|
68
68
|
literal?
|
69
69
|
_
|
@@ -71,7 +71,7 @@ module RuboCop
|
|
71
71
|
|
72
72
|
dependency_declarations(processed_source.ast)
|
73
73
|
.each_cons(2) do |previous, current|
|
74
|
-
next unless consecutive_lines(previous, current)
|
74
|
+
next unless consecutive_lines?(previous, current)
|
75
75
|
next unless case_insensitive_out_of_order?(gem_name(current), gem_name(previous))
|
76
76
|
next unless get_dependency_name(previous) == get_dependency_name(current)
|
77
77
|
|
@@ -29,6 +29,7 @@ module RuboCop
|
|
29
29
|
NODE_GROUPS = {
|
30
30
|
any_block: %i[block numblock itblock],
|
31
31
|
any_def: %i[def defs],
|
32
|
+
any_match_pattern: %i[match_pattern match_pattern_p],
|
32
33
|
argument: %i[arg optarg restarg kwarg kwoptarg kwrestarg blockarg forward_arg shadowarg],
|
33
34
|
boolean: %i[true false],
|
34
35
|
call: %i[send csend],
|
@@ -19,7 +19,9 @@ module RuboCop
|
|
19
19
|
MSG = 'Empty interpolation detected.'
|
20
20
|
|
21
21
|
def on_interpolation(begin_node)
|
22
|
-
|
22
|
+
node_children = begin_node.children.dup
|
23
|
+
node_children.delete_if { |e| e&.nil_type? || (e&.basic_literal? && e&.value&.empty?) }
|
24
|
+
return unless node_children.empty?
|
23
25
|
|
24
26
|
add_offense(begin_node) { |corrector| corrector.remove(begin_node) }
|
25
27
|
end
|
@@ -11,39 +11,43 @@ module RuboCop
|
|
11
11
|
# @example
|
12
12
|
# # bad
|
13
13
|
# foo.object_id == bar.object_id
|
14
|
+
# foo.object_id != baz.object_id
|
14
15
|
#
|
15
16
|
# # good
|
16
17
|
# foo.equal?(bar)
|
18
|
+
# !foo.equal?(baz)
|
17
19
|
#
|
18
20
|
class IdentityComparison < Base
|
19
21
|
extend AutoCorrector
|
20
22
|
|
21
|
-
MSG = 'Use
|
22
|
-
RESTRICT_ON_SEND = %i[==].freeze
|
23
|
+
MSG = 'Use `%<bang>sequal?` instead of `%<comparison_method>s` when comparing `object_id`.'
|
24
|
+
RESTRICT_ON_SEND = %i[== !=].freeze
|
25
|
+
|
26
|
+
# @!method object_id_comparison(node)
|
27
|
+
def_node_matcher :object_id_comparison, <<~PATTERN
|
28
|
+
(send
|
29
|
+
(send
|
30
|
+
_lhs_receiver :object_id) ${:== :!=}
|
31
|
+
(send
|
32
|
+
_rhs_receiver :object_id))
|
33
|
+
PATTERN
|
23
34
|
|
24
35
|
def on_send(node)
|
25
|
-
return unless
|
36
|
+
return unless (comparison_method = object_id_comparison(node))
|
26
37
|
|
27
|
-
|
38
|
+
bang = comparison_method == :== ? '' : '!'
|
39
|
+
add_offense(node,
|
40
|
+
message: format(MSG, comparison_method: comparison_method,
|
41
|
+
bang: bang)) do |corrector|
|
28
42
|
receiver = node.receiver.receiver
|
29
43
|
argument = node.first_argument.receiver
|
30
44
|
return unless receiver && argument
|
31
45
|
|
32
|
-
replacement = "#{receiver.source}.equal?(#{argument.source})"
|
46
|
+
replacement = "#{bang}#{receiver.source}.equal?(#{argument.source})"
|
33
47
|
|
34
48
|
corrector.replace(node, replacement)
|
35
49
|
end
|
36
50
|
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def compare_between_object_id_by_double_equal?(node)
|
41
|
-
object_id_method?(node.receiver) && object_id_method?(node.first_argument)
|
42
|
-
end
|
43
|
-
|
44
|
-
def object_id_method?(node)
|
45
|
-
node.send_type? && node.method?(:object_id)
|
46
|
-
end
|
47
51
|
end
|
48
52
|
end
|
49
53
|
end
|
@@ -240,30 +240,22 @@ module RuboCop
|
|
240
240
|
def correct_if_node(node, cond)
|
241
241
|
result = condition_evaluation(node, cond)
|
242
242
|
|
243
|
-
if node.elsif? && result
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
elsif node.else? || node.ternary?
|
260
|
-
add_offense(cond) do |corrector|
|
261
|
-
corrector.replace(node, node.else_branch.source)
|
262
|
-
end
|
263
|
-
else
|
264
|
-
add_offense(cond) do |corrector|
|
265
|
-
corrector.remove(node)
|
266
|
-
end
|
243
|
+
new_node = if node.elsif? && result
|
244
|
+
"else\n #{range_with_comments(node.if_branch).source}"
|
245
|
+
elsif node.elsif? && !result
|
246
|
+
"else\n #{node.else_branch.source}"
|
247
|
+
elsif node.if_branch && result
|
248
|
+
node.if_branch.source
|
249
|
+
elsif node.elsif_conditional?
|
250
|
+
"#{node.else_branch.source.sub('elsif', 'if')}\nend"
|
251
|
+
elsif node.else? || node.ternary?
|
252
|
+
node.else_branch.source
|
253
|
+
else
|
254
|
+
'' # Equivalent to removing the node
|
255
|
+
end
|
256
|
+
|
257
|
+
add_offense(cond) do |corrector|
|
258
|
+
corrector.replace(node, new_node)
|
267
259
|
end
|
268
260
|
end
|
269
261
|
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
@@ -8,6 +8,11 @@ module RuboCop
|
|
8
8
|
# given by `ruby -cw` prior to Ruby 2.6:
|
9
9
|
# "shadowing outer local variable - foo".
|
10
10
|
#
|
11
|
+
# The cop is now disabled by default to match the upstream Ruby behavior.
|
12
|
+
# It's useful, however, if you'd like to avoid shadowing variables from outer
|
13
|
+
# scopes, which some people consider an anti-pattern that makes it harder
|
14
|
+
# to keep track of what's going on in a program.
|
15
|
+
#
|
11
16
|
# NOTE: Shadowing of variables in block passed to `Ractor.new` is allowed
|
12
17
|
# because `Ractor` should not access outer variables.
|
13
18
|
# eg. following style is encouraged:
|
@@ -0,0 +1,87 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for usage of method `fetch` or `Array.new` with default value argument
|
7
|
+
# and block. In such cases, block will always be used as default value.
|
8
|
+
#
|
9
|
+
# This cop emulates Ruby warning "block supersedes default value argument" which
|
10
|
+
# applies to `Array.new`, `Array#fetch`, `Hash#fetch`, `ENV.fetch` and
|
11
|
+
# `Thread#fetch`.
|
12
|
+
#
|
13
|
+
# @safety
|
14
|
+
# This cop is unsafe because the receiver could have nonstandard implementation
|
15
|
+
# of `fetch`, or be a class other than the one listed above.
|
16
|
+
#
|
17
|
+
# It is also unsafe because default value argument could have side effects:
|
18
|
+
#
|
19
|
+
# [source,ruby]
|
20
|
+
# ----
|
21
|
+
# def x(a) = puts "side effect"
|
22
|
+
# Array.new(5, x(1)) { 2 }
|
23
|
+
# ----
|
24
|
+
#
|
25
|
+
# so removing it would change behavior.
|
26
|
+
#
|
27
|
+
# @example
|
28
|
+
# # bad
|
29
|
+
# x.fetch(key, default_value) { block_value }
|
30
|
+
# Array.new(size, default_value) { block_value }
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# x.fetch(key) { block_value }
|
34
|
+
# Array.new(size) { block_value }
|
35
|
+
#
|
36
|
+
# # also good - in case default value argument is desired instead
|
37
|
+
# x.fetch(key, default_value)
|
38
|
+
# Array.new(size, default_value)
|
39
|
+
#
|
40
|
+
# # good - keyword arguments aren't registered as offenses
|
41
|
+
# x.fetch(key, keyword: :arg) { block_value }
|
42
|
+
#
|
43
|
+
# @example AllowedReceivers: ['Rails.cache']
|
44
|
+
# # good
|
45
|
+
# Rails.cache.fetch(name, options) { block }
|
46
|
+
#
|
47
|
+
class UselessDefaultValueArgument < Base
|
48
|
+
include AllowedReceivers
|
49
|
+
extend AutoCorrector
|
50
|
+
|
51
|
+
MSG = 'Block supersedes default value argument.'
|
52
|
+
|
53
|
+
RESTRICT_ON_SEND = %i[fetch new].freeze
|
54
|
+
|
55
|
+
# @!method default_value_argument_and_block(node)
|
56
|
+
def_node_matcher :default_value_argument_and_block, <<~PATTERN
|
57
|
+
(any_block
|
58
|
+
{
|
59
|
+
(call _receiver :fetch $_key $_default_value)
|
60
|
+
(send (const _ :Array) :new $_size $_default_value)
|
61
|
+
}
|
62
|
+
_args
|
63
|
+
_block_body)
|
64
|
+
PATTERN
|
65
|
+
|
66
|
+
def on_send(node)
|
67
|
+
unless (prev_arg_node, default_value_node = default_value_argument_and_block(node.parent))
|
68
|
+
return
|
69
|
+
end
|
70
|
+
return if allowed_receiver?(node.receiver)
|
71
|
+
return if hash_without_braces?(default_value_node)
|
72
|
+
|
73
|
+
add_offense(default_value_node) do |corrector|
|
74
|
+
corrector.remove(prev_arg_node.source_range.end.join(default_value_node.source_range))
|
75
|
+
end
|
76
|
+
end
|
77
|
+
alias on_csend on_send
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def hash_without_braces?(node)
|
82
|
+
node.hash_type? && !node.braces?
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# Checks for useless OR (`||` and `or`) expressions.
|
7
|
+
#
|
8
|
+
# Some methods always return a truthy value, even when called
|
9
|
+
# on `nil` (e.g. `nil.to_i` evaluates to `0`). Therefore, OR expressions
|
10
|
+
# appended after these methods will never evaluate.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# x.to_a || fallback
|
16
|
+
# x.to_c || fallback
|
17
|
+
# x.to_d || fallback
|
18
|
+
# x.to_i || fallback
|
19
|
+
# x.to_f || fallback
|
20
|
+
# x.to_h || fallback
|
21
|
+
# x.to_r || fallback
|
22
|
+
# x.to_s || fallback
|
23
|
+
# x.to_sym || fallback
|
24
|
+
# x.intern || fallback
|
25
|
+
# x.inspect || fallback
|
26
|
+
# x.hash || fallback
|
27
|
+
# x.object_id || fallback
|
28
|
+
# x.__id__ || fallback
|
29
|
+
#
|
30
|
+
# x.to_s or fallback
|
31
|
+
#
|
32
|
+
# # good - if fallback is same as return value of method called on nil
|
33
|
+
# x.to_a # nil.to_a returns []
|
34
|
+
# x.to_c # nil.to_c returns (0+0i)
|
35
|
+
# x.to_d # nil.to_d returns 0.0
|
36
|
+
# x.to_i # nil.to_i returns 0
|
37
|
+
# x.to_f # nil.to_f returns 0.0
|
38
|
+
# x.to_h # nil.to_h returns {}
|
39
|
+
# x.to_r # nil.to_r returns (0/1)
|
40
|
+
# x.to_s # nil.to_s returns ''
|
41
|
+
# x.to_sym # nil.to_sym raises an error
|
42
|
+
# x.intern # nil.intern raises an error
|
43
|
+
# x.inspect # nil.inspect returns "nil"
|
44
|
+
# x.hash # nil.hash returns an Integer
|
45
|
+
# x.object_id # nil.object_id returns an Integer
|
46
|
+
# x.__id__ # nil.object_id returns an Integer
|
47
|
+
#
|
48
|
+
# # good - if the intention is not to call the method on nil
|
49
|
+
# x&.to_a || fallback
|
50
|
+
# x&.to_c || fallback
|
51
|
+
# x&.to_d || fallback
|
52
|
+
# x&.to_i || fallback
|
53
|
+
# x&.to_f || fallback
|
54
|
+
# x&.to_h || fallback
|
55
|
+
# x&.to_r || fallback
|
56
|
+
# x&.to_s || fallback
|
57
|
+
# x&.to_sym || fallback
|
58
|
+
# x&.intern || fallback
|
59
|
+
# x&.inspect || fallback
|
60
|
+
# x&.hash || fallback
|
61
|
+
# x&.object_id || fallback
|
62
|
+
# x&.__id__ || fallback
|
63
|
+
#
|
64
|
+
# x&.to_s or fallback
|
65
|
+
#
|
66
|
+
class UselessOr < Base
|
67
|
+
MSG = '`%<rhs>s` will never evaluate because `%<lhs>s` always returns a truthy value.'
|
68
|
+
|
69
|
+
TRUTHY_RETURN_VALUE_METHODS = Set[:to_a, :to_c, :to_d, :to_i, :to_f, :to_h, :to_r,
|
70
|
+
:to_s, :to_sym, :intern, :inspect, :hash, :object_id,
|
71
|
+
:__id__].freeze
|
72
|
+
|
73
|
+
# @!method truthy_return_value_method?(node)
|
74
|
+
def_node_matcher :truthy_return_value_method?, <<~PATTERN
|
75
|
+
(send _ %TRUTHY_RETURN_VALUE_METHODS)
|
76
|
+
PATTERN
|
77
|
+
|
78
|
+
def on_or(node)
|
79
|
+
if truthy_return_value_method?(node.lhs)
|
80
|
+
report_offense(node, node.lhs)
|
81
|
+
elsif truthy_return_value_method?(node.rhs)
|
82
|
+
parent = node.parent
|
83
|
+
parent = parent.parent if parent&.begin_type?
|
84
|
+
|
85
|
+
report_offense(parent, node.rhs) if parent&.or_type?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def report_offense(or_node, truthy_node)
|
92
|
+
add_offense(or_node.loc.operator.join(or_node.rhs.source_range),
|
93
|
+
message: format(MSG, lhs: truthy_node.source, rhs: or_node.rhs.source))
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -24,7 +24,7 @@ module RuboCop
|
|
24
24
|
gem_canonical_name(string_a) < gem_canonical_name(string_b)
|
25
25
|
end
|
26
26
|
|
27
|
-
def consecutive_lines(previous, current)
|
27
|
+
def consecutive_lines?(previous, current)
|
28
28
|
first_line = get_source_range(current, treat_comments_as_separators).first_line
|
29
29
|
previous.source_range.last_line == first_line - 1
|
30
30
|
end
|