rubocop 1.75.8 → 1.79.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 +20 -16
- data/config/default.yml +107 -26
- data/config/obsoletion.yml +6 -3
- data/lib/rubocop/cli.rb +12 -1
- data/lib/rubocop/config_loader.rb +1 -38
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -1
- data/lib/rubocop/cop/correctors/parentheses_corrector.rb +5 -2
- data/lib/rubocop/cop/gemspec/attribute_assignment.rb +91 -0
- data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +0 -22
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/gemspec/require_mfa.rb +15 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +4 -4
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/node_type_group.rb +3 -2
- data/lib/rubocop/cop/internal_affairs/useless_restrict_on_send.rb +1 -1
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +99 -0
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +26 -5
- data/lib/rubocop/cop/layout/space_around_keyword.rb +6 -1
- data/lib/rubocop/cop/layout/space_around_operators.rb +8 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +2 -9
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +7 -2
- data/lib/rubocop/cop/lint/ambiguous_range.rb +5 -0
- data/lib/rubocop/cop/lint/duplicate_methods.rb +25 -4
- data/lib/rubocop/cop/lint/empty_interpolation.rb +3 -1
- data/lib/rubocop/cop/lint/float_comparison.rb +4 -4
- data/lib/rubocop/cop/lint/identity_comparison.rb +19 -15
- data/lib/rubocop/cop/lint/literal_as_condition.rb +34 -28
- data/lib/rubocop/cop/lint/numeric_operation_with_constant_result.rb +1 -0
- data/lib/rubocop/cop/lint/redundant_regexp_quantifiers.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +101 -2
- data/lib/rubocop/cop/lint/redundant_type_conversion.rb +4 -4
- data/lib/rubocop/cop/lint/require_range_parentheses.rb +1 -1
- data/lib/rubocop/cop/lint/rescue_type.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_chain.rb +4 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +25 -0
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +29 -4
- data/lib/rubocop/cop/lint/useless_default_value_argument.rb +90 -0
- data/lib/rubocop/cop/lint/useless_numeric_operation.rb +1 -0
- data/lib/rubocop/cop/lint/useless_or.rb +98 -0
- data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +3 -3
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +121 -0
- data/lib/rubocop/cop/mixin/alignment.rb +1 -1
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/gemspec_help.rb +22 -0
- data/lib/rubocop/cop/mixin/line_length_help.rb +24 -8
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/naming/file_name.rb +2 -2
- data/lib/rubocop/cop/naming/method_name.rb +127 -13
- data/lib/rubocop/cop/naming/predicate_method.rb +306 -0
- data/lib/rubocop/cop/naming/{predicate_name.rb → predicate_prefix.rb} +4 -4
- data/lib/rubocop/cop/security/eval.rb +2 -1
- data/lib/rubocop/cop/security/open.rb +1 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +13 -1
- data/lib/rubocop/cop/style/arguments_forwarding.rb +11 -17
- data/lib/rubocop/cop/style/array_intersect.rb +53 -23
- data/lib/rubocop/cop/style/block_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/case_like_if.rb +1 -1
- data/lib/rubocop/cop/style/collection_querying.rb +167 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -2
- data/lib/rubocop/cop/style/dig_chain.rb +1 -1
- data/lib/rubocop/cop/style/empty_string_inside_interpolation.rb +100 -0
- data/lib/rubocop/cop/style/exponential_notation.rb +3 -2
- data/lib/rubocop/cop/style/fetch_env_var.rb +32 -6
- data/lib/rubocop/cop/style/hash_conversion.rb +16 -8
- data/lib/rubocop/cop/style/if_unless_modifier.rb +13 -6
- data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
- data/lib/rubocop/cop/style/it_assignment.rb +69 -12
- data/lib/rubocop/cop/style/it_block_parameter.rb +36 -15
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -6
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -0
- data/lib/rubocop/cop/style/min_max_comparison.rb +13 -5
- data/lib/rubocop/cop/style/parallel_assignment.rb +32 -20
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +50 -0
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +1 -9
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_interpolation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +35 -5
- data/lib/rubocop/cop/style/redundant_self.rb +8 -5
- data/lib/rubocop/cop/style/safe_navigation.rb +24 -11
- data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +32 -2
- data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +18 -7
- data/lib/rubocop/cops_documentation_generator.rb +1 -0
- data/lib/rubocop/formatter/fuubar_style_formatter.rb +1 -1
- data/lib/rubocop/formatter/markdown_formatter.rb +1 -0
- data/lib/rubocop/formatter/offense_count_formatter.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -0
- data/lib/rubocop/lsp/diagnostic.rb +4 -4
- data/lib/rubocop/lsp/routes.rb +4 -4
- data/lib/rubocop/pending_cops_reporter.rb +56 -0
- data/lib/rubocop/rspec/expect_offense.rb +9 -3
- data/lib/rubocop/server/cache.rb +4 -2
- data/lib/rubocop/server/client_command/base.rb +10 -0
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/server/client_command/start.rb +11 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +11 -1
- data/lib/ruby_lsp/rubocop/addon.rb +2 -2
- metadata +21 -8
@@ -0,0 +1,167 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Prefer `Enumerable` predicate methods over expressions with `count`.
|
7
|
+
#
|
8
|
+
# The cop checks calls to `count` without arguments, or with a
|
9
|
+
# block. It doesn't register offenses for `count` with a positional
|
10
|
+
# argument because its behavior differs from predicate methods (`count`
|
11
|
+
# matches the argument using `==`, while `any?`, `none?` and `one?` use
|
12
|
+
# `===`).
|
13
|
+
#
|
14
|
+
# NOTE: This cop doesn't check `length` and `size` methods because they
|
15
|
+
# would yield false positives. For example, `String` implements `length`
|
16
|
+
# and `size`, but it doesn't include `Enumerable`.
|
17
|
+
#
|
18
|
+
# @safety
|
19
|
+
# The cop is unsafe because receiver might not include `Enumerable`, or
|
20
|
+
# it has nonstandard implementation of `count` or any replacement
|
21
|
+
# methods.
|
22
|
+
#
|
23
|
+
# It's also unsafe because for collections with falsey values, expressions
|
24
|
+
# with `count` without a block return a different result than methods `any?`,
|
25
|
+
# `none?` and `one?`:
|
26
|
+
#
|
27
|
+
# [source,ruby]
|
28
|
+
# ----
|
29
|
+
# [nil, false].count.positive?
|
30
|
+
# [nil].count == 1
|
31
|
+
# # => true
|
32
|
+
#
|
33
|
+
# [nil, false].any?
|
34
|
+
# [nil].one?
|
35
|
+
# # => false
|
36
|
+
#
|
37
|
+
# [nil].count == 0
|
38
|
+
# # => false
|
39
|
+
#
|
40
|
+
# [nil].none?
|
41
|
+
# # => true
|
42
|
+
# ----
|
43
|
+
#
|
44
|
+
# Autocorrection is unsafe when replacement methods don't iterate over
|
45
|
+
# every element in collection and the given block runs side effects:
|
46
|
+
#
|
47
|
+
# [source,ruby]
|
48
|
+
# ----
|
49
|
+
# x.count(&:method_with_side_effects).positive?
|
50
|
+
# # calls `method_with_side_effects` on every element
|
51
|
+
#
|
52
|
+
# x.any?(&:method_with_side_effects)
|
53
|
+
# # calls `method_with_side_effects` until first element returns a truthy value
|
54
|
+
# ----
|
55
|
+
#
|
56
|
+
# @example
|
57
|
+
#
|
58
|
+
# # bad
|
59
|
+
# x.count.positive?
|
60
|
+
# x.count > 0
|
61
|
+
# x.count != 0
|
62
|
+
#
|
63
|
+
# x.count(&:foo?).positive?
|
64
|
+
# x.count { |item| item.foo? }.positive?
|
65
|
+
#
|
66
|
+
# # good
|
67
|
+
# x.any?
|
68
|
+
#
|
69
|
+
# x.any?(&:foo?)
|
70
|
+
# x.any? { |item| item.foo? }
|
71
|
+
#
|
72
|
+
# # bad
|
73
|
+
# x.count.zero?
|
74
|
+
# x.count == 0
|
75
|
+
#
|
76
|
+
# # good
|
77
|
+
# x.none?
|
78
|
+
#
|
79
|
+
# # bad
|
80
|
+
# x.count == 1
|
81
|
+
# x.one?
|
82
|
+
#
|
83
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: false (default)
|
84
|
+
#
|
85
|
+
# # good
|
86
|
+
# x.count > 1
|
87
|
+
#
|
88
|
+
# @example AllCops:ActiveSupportExtensionsEnabled: true
|
89
|
+
#
|
90
|
+
# # bad
|
91
|
+
# x.count > 1
|
92
|
+
#
|
93
|
+
# # good
|
94
|
+
# x.many?
|
95
|
+
#
|
96
|
+
class CollectionQuerying < Base
|
97
|
+
include RangeHelp
|
98
|
+
extend AutoCorrector
|
99
|
+
|
100
|
+
MSG = 'Use `%<prefer>s` instead.'
|
101
|
+
|
102
|
+
RESTRICT_ON_SEND = %i[positive? > != zero? ==].freeze
|
103
|
+
|
104
|
+
REPLACEMENTS = {
|
105
|
+
[:positive?, nil] => :any?,
|
106
|
+
[:>, 0] => :any?,
|
107
|
+
[:!=, 0] => :any?,
|
108
|
+
[:zero?, nil] => :none?,
|
109
|
+
[:==, 0] => :none?,
|
110
|
+
[:==, 1] => :one?,
|
111
|
+
[:>, 1] => :many?
|
112
|
+
}.freeze
|
113
|
+
|
114
|
+
# @!method count_predicate(node)
|
115
|
+
def_node_matcher :count_predicate, <<~PATTERN
|
116
|
+
(send
|
117
|
+
{
|
118
|
+
(any_block $(call !nil? :count) _ _)
|
119
|
+
$(call !nil? :count (block-pass _)?)
|
120
|
+
}
|
121
|
+
{
|
122
|
+
:positive? |
|
123
|
+
:> (int 0) |
|
124
|
+
:!= (int 0) |
|
125
|
+
:zero? |
|
126
|
+
:== (int 0) |
|
127
|
+
:== (int 1) |
|
128
|
+
:> (int 1)
|
129
|
+
})
|
130
|
+
PATTERN
|
131
|
+
|
132
|
+
def on_send(node)
|
133
|
+
return unless (count_node = count_predicate(node))
|
134
|
+
|
135
|
+
replacement_method = replacement_method(node)
|
136
|
+
|
137
|
+
return unless replacement_supported?(replacement_method)
|
138
|
+
|
139
|
+
offense_range = count_node.loc.selector.join(node.source_range.end)
|
140
|
+
add_offense(offense_range,
|
141
|
+
message: format(MSG, prefer: replacement_method)) do |corrector|
|
142
|
+
corrector.replace(count_node.loc.selector, replacement_method)
|
143
|
+
corrector.remove(removal_range(node))
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def replacement_method(node)
|
150
|
+
REPLACEMENTS.fetch([node.method_name, node.first_argument&.value])
|
151
|
+
end
|
152
|
+
|
153
|
+
def replacement_supported?(method_name)
|
154
|
+
return true if active_support_extensions_enabled?
|
155
|
+
|
156
|
+
method_name != :many?
|
157
|
+
end
|
158
|
+
|
159
|
+
def removal_range(node)
|
160
|
+
range = (node.loc.dot || node.loc.selector).join(node.source_range.end)
|
161
|
+
|
162
|
+
range_with_surrounding_space(range, side: :left)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -111,7 +111,7 @@ module RuboCop
|
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
|
-
#
|
114
|
+
# Checks for `if` and `case` statements where each branch is used for
|
115
115
|
# both the assignment and comparison of the same variable
|
116
116
|
# when using the return of the condition can be used instead.
|
117
117
|
#
|
@@ -451,7 +451,9 @@ module RuboCop
|
|
451
451
|
corrector.remove_preceding(condition.loc.else, condition.loc.else.column - column)
|
452
452
|
end
|
453
453
|
|
454
|
-
return unless condition.loc.end && !same_line?(
|
454
|
+
return unless condition.loc.end && !same_line?(
|
455
|
+
condition.branches.last.parent.else_branch, condition.loc.end
|
456
|
+
)
|
455
457
|
|
456
458
|
corrector.remove_preceding(condition.loc.end, condition.loc.end.column - column)
|
457
459
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
#
|
6
|
+
# Checks for chained `dig` calls that can be collapsed into a single `dig`.
|
7
7
|
#
|
8
8
|
# @safety
|
9
9
|
# This cop is unsafe because it cannot be guaranteed that the receiver
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for empty strings being assigned inside string interpolation.
|
7
|
+
#
|
8
|
+
# Empty strings are a meaningless outcome inside of string interpolation, so we remove them.
|
9
|
+
# Alternatively, when configured to do so, we prioritise using empty strings.
|
10
|
+
#
|
11
|
+
# While this cop would also apply to variables that are only going to be used as strings,
|
12
|
+
# RuboCop can't detect that, so we only check inside of string interpolation.
|
13
|
+
#
|
14
|
+
# @example EnforcedStyle: trailing_conditional (default)
|
15
|
+
# # bad
|
16
|
+
# "#{condition ? 'foo' : ''}"
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# "#{'foo' if condition}"
|
20
|
+
#
|
21
|
+
# # bad
|
22
|
+
# "#{condition ? '' : 'foo'}"
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# "#{'foo' unless condition}"
|
26
|
+
#
|
27
|
+
# @example EnforcedStyle: ternary
|
28
|
+
# # bad
|
29
|
+
# "#{'foo' if condition}"
|
30
|
+
#
|
31
|
+
# # good
|
32
|
+
# "#{condition ? 'foo' : ''}"
|
33
|
+
#
|
34
|
+
# # bad
|
35
|
+
# "#{'foo' unless condition}"
|
36
|
+
#
|
37
|
+
# # good
|
38
|
+
# "#{condition ? '' : 'foo'}"
|
39
|
+
#
|
40
|
+
class EmptyStringInsideInterpolation < Base
|
41
|
+
include ConfigurableEnforcedStyle
|
42
|
+
include Interpolation
|
43
|
+
extend AutoCorrector
|
44
|
+
|
45
|
+
MSG_TRAILING_CONDITIONAL = 'Do not use trailing conditionals in string interpolation.'
|
46
|
+
MSG_TERNARY = 'Do not return empty strings in string interpolation.'
|
47
|
+
|
48
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
49
|
+
def on_interpolation(node)
|
50
|
+
node.each_child_node(:if) do |child_node|
|
51
|
+
if style == :trailing_conditional
|
52
|
+
if empty_if_outcome?(child_node)
|
53
|
+
ternary_style_autocorrect(child_node, child_node.else_branch.source, 'unless')
|
54
|
+
end
|
55
|
+
|
56
|
+
if empty_else_outcome?(child_node)
|
57
|
+
ternary_style_autocorrect(child_node, child_node.if_branch.source, 'if')
|
58
|
+
end
|
59
|
+
elsif style == :ternary
|
60
|
+
next unless child_node.modifier_form?
|
61
|
+
|
62
|
+
ternary_component = if child_node.unless?
|
63
|
+
"'' : #{child_node.if_branch.source}"
|
64
|
+
else
|
65
|
+
"#{child_node.if_branch.source} : ''"
|
66
|
+
end
|
67
|
+
|
68
|
+
add_offense(node, message: MSG_TRAILING_CONDITIONAL) do |corrector|
|
69
|
+
corrector.replace(node, "\#{#{child_node.condition.source} ? #{ternary_component}}")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def empty_if_outcome?(node)
|
79
|
+
empty_branch_outcome?(node.if_branch)
|
80
|
+
end
|
81
|
+
|
82
|
+
def empty_else_outcome?(node)
|
83
|
+
empty_branch_outcome?(node.else_branch)
|
84
|
+
end
|
85
|
+
|
86
|
+
def empty_branch_outcome?(branch)
|
87
|
+
return false unless branch
|
88
|
+
|
89
|
+
branch.nil_type? || (branch.str_type? && branch.value.empty?)
|
90
|
+
end
|
91
|
+
|
92
|
+
def ternary_style_autocorrect(node, outcome, condition)
|
93
|
+
add_offense(node, message: MSG_TERNARY) do |corrector|
|
94
|
+
corrector.replace(node, "#{outcome} #{condition} #{node.condition.source}")
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -59,6 +59,7 @@ module RuboCop
|
|
59
59
|
#
|
60
60
|
class ExponentialNotation < Base
|
61
61
|
include ConfigurableEnforcedStyle
|
62
|
+
|
62
63
|
MESSAGES = {
|
63
64
|
scientific: 'Use a mantissa >= 1 and < 10.',
|
64
65
|
engineering: 'Use an exponent divisible by 3 and a mantissa >= 0.1 and < 1000.',
|
@@ -87,7 +88,7 @@ module RuboCop
|
|
87
88
|
true
|
88
89
|
end
|
89
90
|
|
90
|
-
def integral(node)
|
91
|
+
def integral?(node)
|
91
92
|
mantissa, = node.source.split('e')
|
92
93
|
/^-?[1-9](\d*[1-9])?$/.match?(mantissa)
|
93
94
|
end
|
@@ -101,7 +102,7 @@ module RuboCop
|
|
101
102
|
when :engineering
|
102
103
|
!engineering?(node)
|
103
104
|
when :integral
|
104
|
-
!integral(node)
|
105
|
+
!integral?(node)
|
105
106
|
else
|
106
107
|
false
|
107
108
|
end
|
@@ -9,7 +9,20 @@ module RuboCop
|
|
9
9
|
# On the other hand, `ENV.fetch` raises `KeyError` or returns the explicitly
|
10
10
|
# specified default value.
|
11
11
|
#
|
12
|
-
# @example
|
12
|
+
# @example DefaultToNil: true (default)
|
13
|
+
# # bad
|
14
|
+
# ENV['X']
|
15
|
+
# x = ENV['X']
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# ENV.fetch('X', nil)
|
19
|
+
# x = ENV.fetch('X', nil)
|
20
|
+
#
|
21
|
+
# # also good
|
22
|
+
# !ENV['X']
|
23
|
+
# ENV['X'].some_method # (e.g. `.nil?`)
|
24
|
+
#
|
25
|
+
# @example DefaultToNil: false
|
13
26
|
# # bad
|
14
27
|
# ENV['X']
|
15
28
|
# x = ENV['X']
|
@@ -25,7 +38,8 @@ module RuboCop
|
|
25
38
|
class FetchEnvVar < Base
|
26
39
|
extend AutoCorrector
|
27
40
|
|
28
|
-
|
41
|
+
MSG_WITH_NIL = 'Use `ENV.fetch(%<key>s, nil)` instead of `ENV[%<key>s]`.'
|
42
|
+
MSG_WITHOUT_NIL = 'Use `ENV.fetch(%<key>s)` instead of `ENV[%<key>s]`.'
|
29
43
|
RESTRICT_ON_SEND = [:[]].freeze
|
30
44
|
|
31
45
|
# @!method env_with_bracket?(node)
|
@@ -37,7 +51,7 @@ module RuboCop
|
|
37
51
|
env_with_bracket?(node) do |name_node|
|
38
52
|
break unless offensive?(node)
|
39
53
|
|
40
|
-
message = format(
|
54
|
+
message = format(offense_message, key: name_node.source)
|
41
55
|
add_offense(node, message: message) do |corrector|
|
42
56
|
corrector.replace(node, new_code(name_node))
|
43
57
|
end
|
@@ -46,6 +60,14 @@ module RuboCop
|
|
46
60
|
|
47
61
|
private
|
48
62
|
|
63
|
+
def default_to_nil?
|
64
|
+
cop_config.fetch('DefaultToNil', true)
|
65
|
+
end
|
66
|
+
|
67
|
+
def offense_message
|
68
|
+
default_to_nil? ? MSG_WITH_NIL : MSG_WITHOUT_NIL
|
69
|
+
end
|
70
|
+
|
49
71
|
def allowed_var?(node)
|
50
72
|
env_key_node = node.children.last
|
51
73
|
env_key_node.str_type? && cop_config['AllowedVars'].include?(env_key_node.value)
|
@@ -53,12 +75,12 @@ module RuboCop
|
|
53
75
|
|
54
76
|
def used_as_flag?(node)
|
55
77
|
return false if node.root?
|
56
|
-
return true if used_if_condition_in_body(node)
|
78
|
+
return true if used_if_condition_in_body?(node)
|
57
79
|
|
58
80
|
node.parent.send_type? && (node.parent.prefix_bang? || node.parent.comparison_method?)
|
59
81
|
end
|
60
82
|
|
61
|
-
def used_if_condition_in_body(node)
|
83
|
+
def used_if_condition_in_body?(node)
|
62
84
|
if_node = node.ancestors.find(&:if_type?)
|
63
85
|
|
64
86
|
return false unless (condition = if_node&.condition)
|
@@ -125,7 +147,11 @@ module RuboCop
|
|
125
147
|
end
|
126
148
|
|
127
149
|
def new_code(name_node)
|
128
|
-
|
150
|
+
if default_to_nil?
|
151
|
+
"ENV.fetch(#{name_node.source}, nil)"
|
152
|
+
else
|
153
|
+
"ENV.fetch(#{name_node.source})"
|
154
|
+
end
|
129
155
|
end
|
130
156
|
end
|
131
157
|
end
|
@@ -44,17 +44,17 @@ module RuboCop
|
|
44
44
|
class HashConversion < Base
|
45
45
|
extend AutoCorrector
|
46
46
|
|
47
|
-
MSG_TO_H = 'Prefer ary.to_h to Hash[ary]
|
48
|
-
MSG_LITERAL_MULTI_ARG = 'Prefer literal hash to Hash[arg1, arg2, ...]
|
49
|
-
MSG_LITERAL_HASH_ARG = 'Prefer literal hash to Hash[key: value, ...]
|
50
|
-
MSG_SPLAT = 'Prefer array_of_pairs.to_h to Hash[*array]
|
47
|
+
MSG_TO_H = 'Prefer `ary.to_h` to `Hash[ary]`.'
|
48
|
+
MSG_LITERAL_MULTI_ARG = 'Prefer literal hash to `Hash[arg1, arg2, ...]`.'
|
49
|
+
MSG_LITERAL_HASH_ARG = 'Prefer literal hash to `Hash[key: value, ...]`.'
|
50
|
+
MSG_SPLAT = 'Prefer `array_of_pairs.to_h` to `Hash[*array]`.'
|
51
51
|
RESTRICT_ON_SEND = %i[[]].freeze
|
52
52
|
|
53
53
|
# @!method hash_from_array?(node)
|
54
54
|
def_node_matcher :hash_from_array?, '(send (const {nil? cbase} :Hash) :[] ...)'
|
55
55
|
|
56
56
|
def on_send(node)
|
57
|
-
return
|
57
|
+
return if part_of_ignored_node?(node) || !hash_from_array?(node)
|
58
58
|
|
59
59
|
# There are several cases:
|
60
60
|
# If there is one argument:
|
@@ -63,7 +63,8 @@ module RuboCop
|
|
63
63
|
# If there is 0 or 2+ arguments:
|
64
64
|
# Hash[a1, a2, a3, a4] => {a1 => a2, a3 => a4}
|
65
65
|
# ...but don't suggest correction if there is odd number of them (it is a bug)
|
66
|
-
node.arguments.
|
66
|
+
node.arguments.one? ? single_argument(node) : multi_argument(node)
|
67
|
+
ignore_node(node)
|
67
68
|
end
|
68
69
|
|
69
70
|
private
|
@@ -111,7 +112,12 @@ module RuboCop
|
|
111
112
|
end
|
112
113
|
|
113
114
|
def requires_parens?(node)
|
114
|
-
|
115
|
+
if node.call_type?
|
116
|
+
return false if node.method?(:[])
|
117
|
+
return true if node.arguments.any? && !node.parenthesized?
|
118
|
+
end
|
119
|
+
|
120
|
+
node.operator_keyword?
|
115
121
|
end
|
116
122
|
|
117
123
|
def multi_argument(node)
|
@@ -122,7 +128,9 @@ module RuboCop
|
|
122
128
|
corrector.replace(node, args_to_hash(node.arguments))
|
123
129
|
|
124
130
|
parent = node.parent
|
125
|
-
|
131
|
+
if parent&.send_type? && !parent.method?(:to_h) && !parent.parenthesized?
|
132
|
+
add_parentheses(parent, corrector)
|
133
|
+
end
|
126
134
|
end
|
127
135
|
end
|
128
136
|
end
|
@@ -132,12 +132,10 @@ module RuboCop
|
|
132
132
|
end
|
133
133
|
|
134
134
|
def pattern_matching_nodes(condition)
|
135
|
-
if condition.
|
135
|
+
if condition.any_match_pattern_type?
|
136
136
|
[condition]
|
137
137
|
else
|
138
|
-
condition.each_descendant.select
|
139
|
-
node.type?(:match_pattern, :match_pattern_p)
|
140
|
-
end
|
138
|
+
condition.each_descendant.select(&:any_match_pattern_type?)
|
141
139
|
end
|
142
140
|
end
|
143
141
|
|
@@ -225,8 +223,17 @@ module RuboCop
|
|
225
223
|
|
226
224
|
def too_long_line_based_on_allow_uri?(line)
|
227
225
|
if allow_uri?
|
228
|
-
uri_range =
|
229
|
-
return false if uri_range &&
|
226
|
+
uri_range = find_excessive_range(line, :uri)
|
227
|
+
return false if uri_range && allowed_position?(line, uri_range)
|
228
|
+
end
|
229
|
+
|
230
|
+
true
|
231
|
+
end
|
232
|
+
|
233
|
+
def too_long_line_based_on_allow_qualified_name?(line)
|
234
|
+
if allow_qualified_name?
|
235
|
+
namespace_range = find_excessive_range(line, :namespace)
|
236
|
+
return false if namespace_range && allowed_position?(line, namespace_range)
|
230
237
|
end
|
231
238
|
|
232
239
|
true
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
#
|
6
|
+
# Checks for usages of not (`not` or `!`) called on a method
|
7
7
|
# when an inverse of that method can be used instead.
|
8
8
|
#
|
9
9
|
# Methods that can be inverted by a not (`not` or `!`) should be defined
|
@@ -3,33 +3,90 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Checks for
|
6
|
+
# Checks for local variables and method parameters named `it`,
|
7
7
|
# where `it` can refer to the first anonymous parameter as of Ruby 3.4.
|
8
|
+
# Use a meaningful variable name instead.
|
8
9
|
#
|
9
|
-
# Although Ruby allows reassigning `it` in these cases, it could
|
10
|
+
# NOTE: Although Ruby allows reassigning `it` in these cases, it could
|
10
11
|
# cause confusion if `it` is used as a block parameter elsewhere.
|
11
|
-
# For consistency, this also applies to numblocks and blocks with
|
12
|
-
# parameters, even though `it` cannot be used in those cases.
|
13
12
|
#
|
14
13
|
# @example
|
15
14
|
# # bad
|
16
|
-
#
|
17
|
-
# foo { |bar| it = bar }
|
18
|
-
# foo { it = _2 }
|
15
|
+
# it = 5
|
19
16
|
#
|
20
|
-
# # good
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
17
|
+
# # good
|
18
|
+
# var = 5
|
19
|
+
#
|
20
|
+
# # bad
|
21
|
+
# def foo(it)
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# # good
|
25
|
+
# def foo(arg)
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# # bad
|
29
|
+
# def foo(it = 5)
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# def foo(arg = 5)
|
34
|
+
# end
|
35
|
+
#
|
36
|
+
# # bad
|
37
|
+
# def foo(*it)
|
38
|
+
# end
|
39
|
+
#
|
40
|
+
# # good
|
41
|
+
# def foo(*args)
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# # bad
|
45
|
+
# def foo(it:)
|
46
|
+
# end
|
47
|
+
#
|
48
|
+
# # good
|
49
|
+
# def foo(arg:)
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# # bad
|
53
|
+
# def foo(it: 5)
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# def foo(arg: 5)
|
58
|
+
# end
|
59
|
+
#
|
60
|
+
# # bad
|
61
|
+
# def foo(**it)
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# # good
|
65
|
+
# def foo(**kwargs)
|
66
|
+
# end
|
67
|
+
#
|
68
|
+
# # bad
|
69
|
+
# def foo(&it)
|
70
|
+
# end
|
71
|
+
#
|
72
|
+
# # good
|
73
|
+
# def foo(&block)
|
74
|
+
# end
|
24
75
|
class ItAssignment < Base
|
25
76
|
MSG = '`it` is the default block parameter; consider another name.'
|
26
77
|
|
27
78
|
def on_lvasgn(node)
|
28
79
|
return unless node.name == :it
|
29
|
-
return unless node.each_ancestor(:any_block).any?
|
30
80
|
|
31
81
|
add_offense(node.loc.name)
|
32
82
|
end
|
83
|
+
alias on_arg on_lvasgn
|
84
|
+
alias on_optarg on_lvasgn
|
85
|
+
alias on_restarg on_lvasgn
|
86
|
+
alias on_blockarg on_lvasgn
|
87
|
+
alias on_kwarg on_lvasgn
|
88
|
+
alias on_kwoptarg on_lvasgn
|
89
|
+
alias on_kwrestarg on_lvasgn
|
33
90
|
end
|
34
91
|
end
|
35
92
|
end
|