rubocop 1.75.7 → 1.76.1
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 +50 -7
- data/config/obsoletion.yml +6 -3
- data/lib/rubocop/cop/autocorrect_logic.rb +18 -10
- 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/layout/class_structure.rb +35 -0
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +6 -2
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
- data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +27 -0
- 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/def_with_parentheses.rb +18 -5
- 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/map_to_hash.rb +11 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
- data/lib/rubocop/cop/style/redundant_format.rb +6 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +17 -5
- data/lib/rubocop/cop/style/safe_navigation.rb +24 -11
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/rspec/expect_offense.rb +9 -3
- 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: b3a37fd910269f3c84074e6a29c94c43e0deb0ed967d6ce879fbfd6b45380db7
|
4
|
+
data.tar.gz: 65e707c85e20a9242af4bdc21b4bf0bf3d46e9646dc74a981dfe2a3691102d3b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1255eac20671a11a1efd42d85696125d0394673b9343b99fc8205275b66445adb99b79da7e9ecc2c457c1e2bf86d57a207c4d7def8d17b6d13abbb6bd08aa574
|
7
|
+
data.tar.gz: bf23d4d52d27505fc7bcfdaf992fb3d942261bc9eaea475c8374ea991352b47b10938e5e7ac1d19d84a44e0fac0683eb6d01218a136be5b2eb39aa3504a376c6
|
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
|
@@ -2676,7 +2689,7 @@ Metrics/AbcSize:
|
|
2676
2689
|
A calculated magnitude based on number of assignments,
|
2677
2690
|
branches, and conditions.
|
2678
2691
|
References:
|
2679
|
-
-
|
2692
|
+
- https://wiki.c2.com/?AbcMetric
|
2680
2693
|
- https://en.wikipedia.org/wiki/ABC_Software_Metric
|
2681
2694
|
Enabled: true
|
2682
2695
|
VersionAdded: '0.27'
|
@@ -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: >-
|
@@ -4969,7 +5006,7 @@ Style/OpenStructUse:
|
|
4969
5006
|
Avoid using OpenStruct. As of Ruby 3.0, use is officially discouraged due to performance,
|
4970
5007
|
version compatibility, and potential security issues.
|
4971
5008
|
References:
|
4972
|
-
- https://docs.ruby-lang.org/en/3.0
|
5009
|
+
- https://docs.ruby-lang.org/en/3.0/OpenStruct.html#class-OpenStruct-label-Caveats
|
4973
5010
|
|
4974
5011
|
Enabled: pending
|
4975
5012
|
Safe: false
|
@@ -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:
|
@@ -50,7 +50,7 @@ module RuboCop
|
|
50
50
|
|
51
51
|
def disable_offense(offense_range)
|
52
52
|
unbreakable_range = multiline_ranges(offense_range)&.find do |range|
|
53
|
-
|
53
|
+
eol_comment_would_be_inside_literal?(offense_range, range)
|
54
54
|
end
|
55
55
|
|
56
56
|
if unbreakable_range
|
@@ -75,18 +75,22 @@ module RuboCop
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def disable_offense_with_eol_or_surround_comment(range)
|
78
|
-
|
79
|
-
needed_line_length = (range.source_line + eol_comment).length
|
80
|
-
|
81
|
-
if needed_line_length <= max_line_length
|
82
|
-
disable_offense_at_end_of_line(range_of_first_line(range), eol_comment)
|
83
|
-
else
|
78
|
+
if line_with_eol_comment_too_long?(range)
|
84
79
|
disable_offense_before_and_after(range_by_lines(range))
|
80
|
+
else
|
81
|
+
disable_offense_at_end_of_line(range_of_first_line(range))
|
85
82
|
end
|
86
83
|
end
|
87
84
|
|
88
|
-
def
|
89
|
-
|
85
|
+
def eol_comment_would_be_inside_literal?(offense_range, literal_range)
|
86
|
+
return true if line_with_eol_comment_too_long?(offense_range)
|
87
|
+
|
88
|
+
offense_line = offense_range.line
|
89
|
+
offense_line >= literal_range.first_line && offense_line < literal_range.last_line
|
90
|
+
end
|
91
|
+
|
92
|
+
def line_with_eol_comment_too_long?(range)
|
93
|
+
(range.source_line + eol_comment).length > max_line_length
|
90
94
|
end
|
91
95
|
|
92
96
|
def surrounding_heredoc?(node)
|
@@ -132,10 +136,14 @@ module RuboCop
|
|
132
136
|
config.for_cop('Layout/LineLength')['Max'] || 120
|
133
137
|
end
|
134
138
|
|
135
|
-
def disable_offense_at_end_of_line(range
|
139
|
+
def disable_offense_at_end_of_line(range)
|
136
140
|
Corrector.new(range).insert_after(range, eol_comment)
|
137
141
|
end
|
138
142
|
|
143
|
+
def eol_comment
|
144
|
+
" # rubocop:todo #{cop_name}"
|
145
|
+
end
|
146
|
+
|
139
147
|
def disable_offense_before_and_after(range_by_lines)
|
140
148
|
range_with_newline = range_by_lines.resize(range_by_lines.size + 1)
|
141
149
|
leading_whitespace = range_by_lines.source_line[/^\s*/]
|
@@ -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],
|
@@ -22,6 +22,11 @@ module RuboCop
|
|
22
22
|
# * Private attribute macros (`attr_accessor`, `attr_writer`, `attr_reader`)
|
23
23
|
# * Private instance methods
|
24
24
|
#
|
25
|
+
# NOTE: Simply enabling the cop with `Enabled: true` will not use
|
26
|
+
# the example order shown below.
|
27
|
+
# To enforce the order of macros like `attr_reader`,
|
28
|
+
# you must define both `ExpectedOrder` *and* `Categories`.
|
29
|
+
#
|
25
30
|
# You can configure the following order:
|
26
31
|
#
|
27
32
|
# [source,yaml]
|
@@ -68,6 +73,36 @@ module RuboCop
|
|
68
73
|
# - extend
|
69
74
|
# ----
|
70
75
|
#
|
76
|
+
# If you only set `ExpectedOrder`
|
77
|
+
# without defining `Categories`,
|
78
|
+
# macros such as `attr_reader` or `has_many`
|
79
|
+
# will not be recognized as part of a category, and their order will not be validated.
|
80
|
+
# For example, the following will NOT raise any offenses, even if the order is incorrect:
|
81
|
+
#
|
82
|
+
# [source,yaml]
|
83
|
+
# ----
|
84
|
+
# Layout/ClassStructure:
|
85
|
+
# Enabled: true
|
86
|
+
# ExpectedOrder:
|
87
|
+
# - public_attribute_macros
|
88
|
+
# - initializer
|
89
|
+
# ----
|
90
|
+
#
|
91
|
+
# To make it work as expected, you must also specify `Categories` like this:
|
92
|
+
#
|
93
|
+
# [source,yaml]
|
94
|
+
# ----
|
95
|
+
# Layout/ClassStructure:
|
96
|
+
# ExpectedOrder:
|
97
|
+
# - public_attribute_macros
|
98
|
+
# - initializer
|
99
|
+
# Categories:
|
100
|
+
# attribute_macros:
|
101
|
+
# - attr_reader
|
102
|
+
# - attr_writer
|
103
|
+
# - attr_accessor
|
104
|
+
# ----
|
105
|
+
#
|
71
106
|
# @safety
|
72
107
|
# Autocorrection is unsafe because class methods and module inclusion
|
73
108
|
# can behave differently, based on which methods or constants have
|
@@ -116,7 +116,7 @@ module RuboCop
|
|
116
116
|
def allowed_only_before_style?(node)
|
117
117
|
if node.special_modifier?
|
118
118
|
return true if processed_source[node.last_line] == 'end'
|
119
|
-
return false if
|
119
|
+
return false if next_line_empty_and_exists?(node.last_line)
|
120
120
|
end
|
121
121
|
|
122
122
|
previous_line_empty?(node.first_line)
|
@@ -129,7 +129,7 @@ module RuboCop
|
|
129
129
|
when :around
|
130
130
|
corrector.insert_after(line, "\n") unless next_line_empty?(node.last_line)
|
131
131
|
when :only_before
|
132
|
-
if
|
132
|
+
if next_line_empty_and_exists?(node.last_line)
|
133
133
|
range = next_empty_line_range(node)
|
134
134
|
|
135
135
|
corrector.remove(range)
|
@@ -154,6 +154,10 @@ module RuboCop
|
|
154
154
|
body_end?(last_send_line) || next_line.blank?
|
155
155
|
end
|
156
156
|
|
157
|
+
def next_line_empty_and_exists?(last_send_line)
|
158
|
+
next_line_empty?(last_send_line) && last_send_line.next != processed_source.lines.size
|
159
|
+
end
|
160
|
+
|
157
161
|
def empty_lines_around?(node)
|
158
162
|
previous_line_empty?(node.first_line) && next_line_empty?(node.last_line)
|
159
163
|
end
|
@@ -155,7 +155,7 @@ module RuboCop
|
|
155
155
|
def on_send(node)
|
156
156
|
return unless should_check?(node)
|
157
157
|
return if same_line?(node, node.first_argument)
|
158
|
-
return if
|
158
|
+
return if enforce_first_argument_with_fixed_indentation? &&
|
159
159
|
!enable_layout_first_method_argument_line_break?
|
160
160
|
|
161
161
|
indent = base_indentation(node) + configured_indentation_width
|
@@ -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.to_s.empty?) }
|
24
|
+
return unless node_children.empty?
|
23
25
|
|
24
26
|
add_offense(begin_node) { |corrector| corrector.remove(begin_node) }
|
25
27
|
end
|
@@ -15,6 +15,14 @@ module RuboCop
|
|
15
15
|
# x == 0.1
|
16
16
|
# x != 0.1
|
17
17
|
#
|
18
|
+
# # bad
|
19
|
+
# case value
|
20
|
+
# when 1.0
|
21
|
+
# foo
|
22
|
+
# when 2.0
|
23
|
+
# bar
|
24
|
+
# end
|
25
|
+
#
|
18
26
|
# # good - using BigDecimal
|
19
27
|
# x.to_d == 0.1.to_d
|
20
28
|
#
|
@@ -32,12 +40,21 @@ module RuboCop
|
|
32
40
|
# # good - comparing against nil
|
33
41
|
# Float(x, exception: false) == nil
|
34
42
|
#
|
43
|
+
# # good - using epsilon comparison in case expression
|
44
|
+
# case
|
45
|
+
# when (value - 1.0).abs < Float::EPSILON
|
46
|
+
# foo
|
47
|
+
# when (value - 2.0).abs < Float::EPSILON
|
48
|
+
# bar
|
49
|
+
# end
|
50
|
+
#
|
35
51
|
# # Or some other epsilon based type of comparison:
|
36
52
|
# # https://www.embeddeduse.com/2019/08/26/qt-compare-two-floats/
|
37
53
|
#
|
38
54
|
class FloatComparison < Base
|
39
55
|
MSG_EQUALITY = 'Avoid equality comparisons of floats as they are unreliable.'
|
40
56
|
MSG_INEQUALITY = 'Avoid inequality comparisons of floats as they are unreliable.'
|
57
|
+
MSG_CASE = 'Avoid float literal comparisons in case statements as they are unreliable.'
|
41
58
|
|
42
59
|
EQUALITY_METHODS = %i[== != eql? equal?].freeze
|
43
60
|
FLOAT_RETURNING_METHODS = %i[to_f Float fdiv].freeze
|
@@ -58,6 +75,16 @@ module RuboCop
|
|
58
75
|
end
|
59
76
|
alias on_csend on_send
|
60
77
|
|
78
|
+
def on_case(node)
|
79
|
+
node.when_branches.each do |when_branch|
|
80
|
+
when_branch.each_condition do |condition|
|
81
|
+
next if !float?(condition) || literal_safe?(condition)
|
82
|
+
|
83
|
+
add_offense(condition, message: MSG_CASE)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
61
88
|
private
|
62
89
|
|
63
90
|
def float?(node)
|
@@ -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:
|