rubocop 1.50.2 → 1.52.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 +3 -3
- data/config/default.yml +38 -5
- data/lib/rubocop/config.rb +4 -0
- data/lib/rubocop/config_obsoletion.rb +2 -2
- data/lib/rubocop/cop/base.rb +5 -1
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +1 -1
- data/lib/rubocop/cop/gemspec/development_dependencies.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/cop_description.rb +32 -8
- data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
- data/lib/rubocop/cop/layout/closing_heredoc_indentation.rb +0 -1
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +2 -0
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +13 -1
- data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -4
- data/lib/rubocop/cop/lint/identity_comparison.rb +0 -1
- data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +5 -3
- data/lib/rubocop/cop/lint/inherit_exception.rb +9 -0
- data/lib/rubocop/cop/lint/lambda_without_literal_block.rb +1 -1
- data/lib/rubocop/cop/lint/missing_super.rb +3 -0
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +2 -2
- data/lib/rubocop/cop/lint/ordered_magic_comments.rb +0 -1
- data/lib/rubocop/cop/lint/out_of_range_regexp_ref.rb +2 -2
- data/lib/rubocop/cop/lint/redundant_string_coercion.rb +1 -1
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +1 -2
- data/lib/rubocop/cop/lint/shadowed_exception.rb +5 -11
- data/lib/rubocop/cop/lint/top_level_return_with_argument.rb +23 -9
- data/lib/rubocop/cop/lint/useless_assignment.rb +59 -1
- data/lib/rubocop/cop/lint/void.rb +62 -6
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +1 -2
- data/lib/rubocop/cop/mixin/allowed_receivers.rb +34 -0
- data/lib/rubocop/cop/mixin/comments_help.rb +6 -2
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
- data/lib/rubocop/cop/naming/constant_name.rb +1 -1
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +22 -7
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +11 -3
- data/lib/rubocop/cop/naming/variable_name.rb +6 -1
- data/lib/rubocop/cop/style/accessor_grouping.rb +5 -1
- data/lib/rubocop/cop/style/attr.rb +11 -1
- data/lib/rubocop/cop/style/begin_block.rb +1 -2
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
- data/lib/rubocop/cop/style/class_equality_comparison.rb +17 -39
- data/lib/rubocop/cop/style/collection_compact.rb +16 -6
- data/lib/rubocop/cop/style/colon_method_call.rb +2 -2
- data/lib/rubocop/cop/style/combinable_loops.rb +26 -6
- data/lib/rubocop/cop/style/conditional_assignment.rb +2 -2
- data/lib/rubocop/cop/style/copyright.rb +5 -2
- data/lib/rubocop/cop/style/dir.rb +1 -1
- data/lib/rubocop/cop/style/dir_empty.rb +8 -14
- data/lib/rubocop/cop/style/documentation.rb +1 -1
- data/lib/rubocop/cop/style/eval_with_location.rb +5 -5
- data/lib/rubocop/cop/style/exact_regexp_match.rb +68 -0
- data/lib/rubocop/cop/style/file_read.rb +2 -2
- data/lib/rubocop/cop/style/guard_clause.rb +2 -0
- data/lib/rubocop/cop/style/hash_each_methods.rb +1 -22
- data/lib/rubocop/cop/style/hash_except.rb +19 -8
- data/lib/rubocop/cop/style/hash_transform_keys.rb +2 -2
- data/lib/rubocop/cop/style/hash_transform_values.rb +2 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +6 -0
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -0
- data/lib/rubocop/cop/style/invertible_unless_condition.rb +9 -5
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +1 -2
- data/lib/rubocop/cop/style/multiple_comparison.rb +14 -0
- data/lib/rubocop/cop/style/numeric_literals.rb +1 -1
- data/lib/rubocop/cop/style/percent_literal_delimiters.rb +1 -1
- data/lib/rubocop/cop/style/redundant_array_constructor.rb +77 -0
- data/lib/rubocop/cop/style/redundant_filter_chain.rb +101 -0
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +5 -1
- data/lib/rubocop/cop/style/redundant_regexp_constructor.rb +46 -0
- data/lib/rubocop/cop/style/regexp_literal.rb +11 -2
- data/lib/rubocop/cop/style/require_order.rb +11 -5
- data/lib/rubocop/cop/style/rescue_modifier.rb +1 -3
- data/lib/rubocop/cop/style/select_by_regexp.rb +15 -5
- data/lib/rubocop/cop/style/semicolon.rb +12 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
- data/lib/rubocop/cop/style/special_global_vars.rb +3 -4
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +33 -1
- data/lib/rubocop/cop/variable_force/variable_table.rb +2 -2
- data/lib/rubocop/cop/variable_force.rb +1 -0
- data/lib/rubocop/result_cache.rb +1 -1
- data/lib/rubocop/rspec/cop_helper.rb +1 -1
- data/lib/rubocop/server/client_command/exec.rb +2 -1
- data/lib/rubocop/target_ruby.rb +3 -2
- data/lib/rubocop/version.rb +10 -6
- data/lib/rubocop.rb +5 -0
- metadata +15 -10
@@ -57,38 +57,58 @@ module RuboCop
|
|
57
57
|
# end
|
58
58
|
#
|
59
59
|
class CombinableLoops < Base
|
60
|
+
extend AutoCorrector
|
61
|
+
|
62
|
+
include RangeHelp
|
63
|
+
|
60
64
|
MSG = 'Combine this loop with the previous loop.'
|
61
65
|
|
62
66
|
def on_block(node)
|
63
67
|
return unless node.parent&.begin_type?
|
64
68
|
return unless collection_looping_method?(node)
|
69
|
+
return unless same_collection_looping_block?(node, node.left_sibling)
|
65
70
|
|
66
|
-
add_offense(node)
|
71
|
+
add_offense(node) do |corrector|
|
72
|
+
combine_with_left_sibling(corrector, node)
|
73
|
+
end
|
67
74
|
end
|
68
75
|
|
69
76
|
alias on_numblock on_block
|
70
77
|
|
71
78
|
def on_for(node)
|
72
79
|
return unless node.parent&.begin_type?
|
80
|
+
return unless same_collection_looping_for?(node, node.left_sibling)
|
73
81
|
|
74
|
-
|
75
|
-
|
82
|
+
add_offense(node) do |corrector|
|
83
|
+
combine_with_left_sibling(corrector, node)
|
84
|
+
end
|
76
85
|
end
|
77
86
|
|
78
87
|
private
|
79
88
|
|
80
89
|
def collection_looping_method?(node)
|
81
|
-
|
82
|
-
method_name = node.method_name.to_s
|
90
|
+
method_name = node.method_name
|
83
91
|
method_name.start_with?('each') || method_name.end_with?('_each')
|
84
92
|
end
|
85
93
|
|
86
|
-
def
|
94
|
+
def same_collection_looping_block?(node, sibling)
|
87
95
|
(sibling&.block_type? || sibling&.numblock_type?) &&
|
88
96
|
sibling.send_node.method?(node.method_name) &&
|
89
97
|
sibling.receiver == node.receiver &&
|
90
98
|
sibling.send_node.arguments == node.send_node.arguments
|
91
99
|
end
|
100
|
+
|
101
|
+
def same_collection_looping_for?(node, sibling)
|
102
|
+
sibling&.for_type? && node.collection == sibling.collection
|
103
|
+
end
|
104
|
+
|
105
|
+
def combine_with_left_sibling(corrector, node)
|
106
|
+
corrector.replace(
|
107
|
+
node.left_sibling.body,
|
108
|
+
"#{node.left_sibling.body.source}\n#{node.body.source}"
|
109
|
+
)
|
110
|
+
corrector.remove(range_with_surrounding_space(range: node.source_range, side: :left))
|
111
|
+
end
|
92
112
|
end
|
93
113
|
end
|
94
114
|
end
|
@@ -350,7 +350,7 @@ module RuboCop
|
|
350
350
|
end
|
351
351
|
|
352
352
|
def ternary_condition?(node)
|
353
|
-
[node, node.children.first].any? { |n| n.if_type? && n.ternary? }
|
353
|
+
[node, node.children.first].compact.any? { |n| n.if_type? && n.ternary? }
|
354
354
|
end
|
355
355
|
|
356
356
|
def lhs_all_match?(branches)
|
@@ -386,7 +386,7 @@ module RuboCop
|
|
386
386
|
def allowed_statements?(branches)
|
387
387
|
return false unless branches.all?
|
388
388
|
|
389
|
-
statements = branches.
|
389
|
+
statements = branches.filter_map { |branch| tail(branch) }
|
390
390
|
|
391
391
|
lhs_all_match?(statements) && statements.none?(&:masgn_type?) &&
|
392
392
|
assignment_types_match?(*statements)
|
@@ -8,8 +8,11 @@ module RuboCop
|
|
8
8
|
# The default regexp for an acceptable copyright notice can be found in
|
9
9
|
# config/default.yml. The default can be changed as follows:
|
10
10
|
#
|
11
|
-
#
|
12
|
-
#
|
11
|
+
# [source,yaml]
|
12
|
+
# ----
|
13
|
+
# Style/Copyright:
|
14
|
+
# Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc'
|
15
|
+
# ----
|
13
16
|
#
|
14
17
|
# This regex string is treated as an unanchored regex. For each file
|
15
18
|
# that RuboCop scans, a comment that matches this regex must be found or
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Checks for places where the
|
6
|
+
# Checks for places where the `#\_\_dir\_\_` method can replace more
|
7
7
|
# complex constructs to retrieve a canonicalized absolute path to the
|
8
8
|
# current file.
|
9
9
|
#
|
@@ -19,18 +19,16 @@ module RuboCop
|
|
19
19
|
extend AutoCorrector
|
20
20
|
extend TargetRubyVersion
|
21
21
|
|
22
|
-
MSG = 'Use
|
23
|
-
RESTRICT_ON_SEND = %i[== > empty? none?].freeze
|
22
|
+
MSG = 'Use `%<replacement>s` instead.'
|
23
|
+
RESTRICT_ON_SEND = %i[== != > empty? none?].freeze
|
24
24
|
|
25
25
|
minimum_target_ruby_version 2.4
|
26
26
|
|
27
27
|
# @!method offensive?(node)
|
28
28
|
def_node_matcher :offensive?, <<~PATTERN
|
29
29
|
{
|
30
|
-
(send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) {:== :>} (int 2))
|
31
|
-
(send (send (send $(const {nil? cbase} :Dir) :children $_) :size) {:== :>} (int 0))
|
32
|
-
(send (send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) :!) {:== :>} (int 2))
|
33
|
-
(send (send (send (send $(const {nil? cbase} :Dir) :children $_) :size) :!) {:== :>} (int 0))
|
30
|
+
(send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) {:== :!= :>} (int 2))
|
31
|
+
(send (send (send $(const {nil? cbase} :Dir) :children $_) :size) {:== :!= :>} (int 0))
|
34
32
|
(send (send $(const {nil? cbase} :Dir) :children $_) :empty?)
|
35
33
|
(send (send $(const {nil? cbase} :Dir) :each_child $_) :none?)
|
36
34
|
}
|
@@ -38,10 +36,9 @@ module RuboCop
|
|
38
36
|
|
39
37
|
def on_send(node)
|
40
38
|
offensive?(node) do |const_node, arg_node|
|
41
|
-
|
42
|
-
|
43
|
-
corrector.replace(node,
|
44
|
-
"#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})")
|
39
|
+
replacement = "#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})"
|
40
|
+
add_offense(node, message: format(MSG, replacement: replacement)) do |corrector|
|
41
|
+
corrector.replace(node, replacement)
|
45
42
|
end
|
46
43
|
end
|
47
44
|
end
|
@@ -49,10 +46,7 @@ module RuboCop
|
|
49
46
|
private
|
50
47
|
|
51
48
|
def bang(node)
|
52
|
-
if
|
53
|
-
(node.method?(:>) && !node.child_nodes.first.method?(:!))
|
54
|
-
'!'
|
55
|
-
end
|
49
|
+
'!' if %i[!= >].include? node.method_name
|
56
50
|
end
|
57
51
|
end
|
58
52
|
end
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
10
10
|
# declarations.
|
11
11
|
#
|
12
12
|
# The documentation requirement is annulled if the class or module has
|
13
|
-
# a
|
13
|
+
# a `#:nodoc:` comment next to it. Likewise, `#:nodoc: all` does the
|
14
14
|
# same for all its children.
|
15
15
|
#
|
16
16
|
# @example
|
@@ -4,12 +4,12 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
6
|
# Ensures that eval methods (`eval`, `instance_eval`, `class_eval`
|
7
|
-
# and `module_eval`) are given filename and line number values (`
|
8
|
-
# and `
|
7
|
+
# and `module_eval`) are given filename and line number values (`\_\_FILE\_\_`
|
8
|
+
# and `\_\_LINE\_\_`). This data is used to ensure that any errors raised
|
9
9
|
# within the evaluated code will be given the correct identification
|
10
10
|
# in a backtrace.
|
11
11
|
#
|
12
|
-
# The cop also checks that the line number given relative to `
|
12
|
+
# The cop also checks that the line number given relative to `\_\_LINE\_\_` is
|
13
13
|
# correct.
|
14
14
|
#
|
15
15
|
# This cop will autocorrect incorrect or missing filename and line number
|
@@ -57,7 +57,7 @@ module RuboCop
|
|
57
57
|
extend AutoCorrector
|
58
58
|
|
59
59
|
MSG = 'Pass `__FILE__` and `__LINE__` to `%<method_name>s`.'
|
60
|
-
MSG_EVAL = 'Pass a binding, `__FILE__
|
60
|
+
MSG_EVAL = 'Pass a binding, `__FILE__`, and `__LINE__` to `eval`.'
|
61
61
|
MSG_INCORRECT_FILE = 'Incorrect file for `%<method_name>s`; ' \
|
62
62
|
'use `%<expected>s` instead of `%<actual>s`.'
|
63
63
|
MSG_INCORRECT_LINE = 'Incorrect line number for `%<method_name>s`; ' \
|
@@ -210,7 +210,7 @@ module RuboCop
|
|
210
210
|
def add_offense_for_missing_line(node, code)
|
211
211
|
register_offense(node) do |corrector|
|
212
212
|
line_str = missing_line(node, code)
|
213
|
-
corrector.insert_after(node.source_range.end, ", #{line_str}")
|
213
|
+
corrector.insert_after(node.last_argument.source_range.end, ", #{line_str}")
|
214
214
|
end
|
215
215
|
end
|
216
216
|
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for exact regexp match inside Regexp literals.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# string =~ /\Astring\z/
|
12
|
+
# string === /\Astring\z/
|
13
|
+
# string.match(/\Astring\z/)
|
14
|
+
# string.match?(/\Astring\z/)
|
15
|
+
#
|
16
|
+
# # good
|
17
|
+
# string == 'string'
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# string !~ /\Astring\z/
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# string != 'string'
|
24
|
+
#
|
25
|
+
class ExactRegexpMatch < Base
|
26
|
+
extend AutoCorrector
|
27
|
+
|
28
|
+
MSG = 'Use `%<prefer>s`.'
|
29
|
+
RESTRICT_ON_SEND = %i[=~ === !~ match match?].freeze
|
30
|
+
|
31
|
+
# @!method exact_regexp_match(node)
|
32
|
+
def_node_matcher :exact_regexp_match, <<~PATTERN
|
33
|
+
(send
|
34
|
+
_ {:=~ :=== :!~ :match :match?}
|
35
|
+
(regexp
|
36
|
+
(str $_)
|
37
|
+
(regopt)))
|
38
|
+
PATTERN
|
39
|
+
|
40
|
+
def on_send(node)
|
41
|
+
return unless (regexp = exact_regexp_match(node))
|
42
|
+
|
43
|
+
parsed_regexp = Regexp::Parser.parse(regexp)
|
44
|
+
return unless exact_match_pattern?(parsed_regexp)
|
45
|
+
|
46
|
+
prefer = "#{node.receiver.source} #{new_method(node)} '#{parsed_regexp[1].text}'"
|
47
|
+
|
48
|
+
add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
|
49
|
+
corrector.replace(node, prefer)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
def exact_match_pattern?(parsed_regexp)
|
56
|
+
tokens = parsed_regexp.map(&:token)
|
57
|
+
return false unless tokens[0] == :bos && tokens[1] == :literal && tokens[2] == :eos
|
58
|
+
|
59
|
+
!parsed_regexp[1].quantifier
|
60
|
+
end
|
61
|
+
|
62
|
+
def new_method(node)
|
63
|
+
node.method?(:!~) ? '!=' : '=='
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -63,7 +63,7 @@ module RuboCop
|
|
63
63
|
|
64
64
|
# @!method block_read?(node)
|
65
65
|
def_node_matcher :block_read?, <<~PATTERN
|
66
|
-
(block _ (args (arg
|
66
|
+
(block _ (args (arg _name)) (send (lvar _name) :read))
|
67
67
|
PATTERN
|
68
68
|
|
69
69
|
def on_send(node)
|
@@ -100,7 +100,7 @@ module RuboCop
|
|
100
100
|
def file_open_read?(node)
|
101
101
|
return true if send_read?(node)
|
102
102
|
|
103
|
-
block_read?(node)
|
103
|
+
block_read?(node)
|
104
104
|
end
|
105
105
|
|
106
106
|
def read_method(mode)
|
@@ -187,6 +187,8 @@ module RuboCop
|
|
187
187
|
if_branch = node.if_branch
|
188
188
|
else_branch = node.else_branch
|
189
189
|
|
190
|
+
corrector.replace(node.loc.begin, "\n") if node.loc.begin&.is?('then')
|
191
|
+
|
190
192
|
if if_branch&.send_type? && heredoc?(if_branch.last_argument)
|
191
193
|
autocorrect_heredoc_argument(corrector, node, if_branch, else_branch, guard)
|
192
194
|
elsif else_branch&.send_type? && heredoc?(else_branch.last_argument)
|
@@ -28,6 +28,7 @@ module RuboCop
|
|
28
28
|
# execute(sql).keys.each { |v| p v }
|
29
29
|
# execute(sql).values.each { |v| p v }
|
30
30
|
class HashEachMethods < Base
|
31
|
+
include AllowedReceivers
|
31
32
|
include Lint::UnusedArgument
|
32
33
|
extend AutoCorrector
|
33
34
|
|
@@ -116,28 +117,6 @@ module RuboCop
|
|
116
117
|
def kv_range(outer_node)
|
117
118
|
outer_node.receiver.loc.selector.join(outer_node.loc.selector)
|
118
119
|
end
|
119
|
-
|
120
|
-
def allowed_receiver?(receiver)
|
121
|
-
receiver_name = receiver_name(receiver)
|
122
|
-
|
123
|
-
allowed_receivers.include?(receiver_name)
|
124
|
-
end
|
125
|
-
|
126
|
-
def receiver_name(receiver)
|
127
|
-
if receiver.send_type?
|
128
|
-
if receiver.receiver
|
129
|
-
"#{receiver_name(receiver.receiver)}.#{receiver.method_name}"
|
130
|
-
else
|
131
|
-
receiver.method_name.to_s
|
132
|
-
end
|
133
|
-
else
|
134
|
-
receiver.source
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def allowed_receivers
|
139
|
-
cop_config.fetch('AllowedReceivers', [])
|
140
|
-
end
|
141
120
|
end
|
142
121
|
end
|
143
122
|
end
|
@@ -45,13 +45,13 @@ module RuboCop
|
|
45
45
|
(block
|
46
46
|
(send _ _)
|
47
47
|
(args
|
48
|
-
(arg _)
|
48
|
+
$(arg _)
|
49
49
|
(arg _))
|
50
50
|
{
|
51
|
-
(send
|
51
|
+
$(send
|
52
52
|
_ {:== :!= :eql? :include?} _)
|
53
53
|
(send
|
54
|
-
(send
|
54
|
+
$(send
|
55
55
|
_ {:== :!= :eql? :include?} _) :!)
|
56
56
|
})
|
57
57
|
PATTERN
|
@@ -61,13 +61,13 @@ module RuboCop
|
|
61
61
|
(block
|
62
62
|
(send _ _)
|
63
63
|
(args
|
64
|
-
(arg _)
|
64
|
+
$(arg _)
|
65
65
|
(arg _))
|
66
66
|
{
|
67
|
-
(send
|
67
|
+
$(send
|
68
68
|
_ {:== :!= :eql? :in? :include? :exclude?} _)
|
69
69
|
(send
|
70
|
-
(send
|
70
|
+
$(send
|
71
71
|
_ {:== :!= :eql? :in? :include? :exclude?} _) :!)
|
72
72
|
})
|
73
73
|
PATTERN
|
@@ -89,13 +89,24 @@ module RuboCop
|
|
89
89
|
|
90
90
|
private
|
91
91
|
|
92
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
92
93
|
def bad_method?(block)
|
93
94
|
if active_support_extensions_enabled?
|
94
|
-
bad_method_with_active_support?(block)
|
95
|
+
bad_method_with_active_support?(block) do |key_arg, send_node|
|
96
|
+
if send_node.method?(:in?) && send_node.receiver&.source != key_arg.source
|
97
|
+
return false
|
98
|
+
end
|
99
|
+
return true if !send_node.method?(:include?) && !send_node.method?(:exclude?)
|
100
|
+
|
101
|
+
send_node.first_argument&.source == key_arg.source
|
102
|
+
end
|
95
103
|
else
|
96
|
-
bad_method_with_poro?(block)
|
104
|
+
bad_method_with_poro?(block) do |key_arg, send_node|
|
105
|
+
!send_node.method?(:include?) || send_node.first_argument&.source == key_arg.source
|
106
|
+
end
|
97
107
|
end
|
98
108
|
end
|
109
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
99
110
|
|
100
111
|
def semantically_except_method?(send, block)
|
101
112
|
body = block.body
|
@@ -3,8 +3,8 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Looks for uses of
|
7
|
-
#
|
6
|
+
# Looks for uses of `\_.each_with_object({}) {...}`,
|
7
|
+
# `\_.map {...}.to_h`, and `Hash[\_.map {...}]` that are actually just
|
8
8
|
# transforming the keys of a hash, and tries to use a simpler & faster
|
9
9
|
# call to `transform_keys` instead.
|
10
10
|
# It should only be enabled on Ruby version 2.5 or newer.
|
@@ -3,8 +3,8 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
-
# Looks for uses of
|
7
|
-
#
|
6
|
+
# Looks for uses of `\_.each_with_object({}) {...}`,
|
7
|
+
# `\_.map {...}.to_h`, and `Hash[\_.map {...}]` that are actually just
|
8
8
|
# transforming the values of a hash, and tries to use a simpler & faster
|
9
9
|
# call to `transform_values` instead.
|
10
10
|
#
|
@@ -59,11 +59,13 @@ module RuboCop
|
|
59
59
|
# end
|
60
60
|
#
|
61
61
|
class IfInsideElse < Base
|
62
|
+
include IgnoredNode
|
62
63
|
include RangeHelp
|
63
64
|
extend AutoCorrector
|
64
65
|
|
65
66
|
MSG = 'Convert `if` nested inside `else` to `elsif`.'
|
66
67
|
|
68
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
67
69
|
def on_if(node)
|
68
70
|
return if node.ternary? || node.unless?
|
69
71
|
|
@@ -73,9 +75,13 @@ module RuboCop
|
|
73
75
|
return if allow_if_modifier_in_else_branch?(else_branch)
|
74
76
|
|
75
77
|
add_offense(else_branch.loc.keyword) do |corrector|
|
78
|
+
next if part_of_ignored_node?(node)
|
79
|
+
|
76
80
|
autocorrect(corrector, else_branch)
|
81
|
+
ignore_node(node)
|
77
82
|
end
|
78
83
|
end
|
84
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
79
85
|
|
80
86
|
private
|
81
87
|
|
@@ -84,7 +84,10 @@ module RuboCop
|
|
84
84
|
return unless (msg = message(node))
|
85
85
|
|
86
86
|
add_offense(node.loc.keyword, message: format(msg, keyword: node.keyword)) do |corrector|
|
87
|
+
next if part_of_ignored_node?(node)
|
88
|
+
|
87
89
|
autocorrect(corrector, node)
|
90
|
+
ignore_node(node)
|
88
91
|
end
|
89
92
|
end
|
90
93
|
|
@@ -10,12 +10,16 @@ module RuboCop
|
|
10
10
|
# Methods that can be inverted should be defined in `InverseMethods`. Note that
|
11
11
|
# the relationship of inverse methods needs to be defined in both directions.
|
12
12
|
# For example,
|
13
|
-
# InverseMethods:
|
14
|
-
# :!=: :==
|
15
|
-
# :even?: :odd?
|
16
|
-
# :odd?: :even?
|
17
13
|
#
|
18
|
-
#
|
14
|
+
# [source,yaml]
|
15
|
+
# ----
|
16
|
+
# InverseMethods:
|
17
|
+
# :!=: :==
|
18
|
+
# :even?: :odd?
|
19
|
+
# :odd?: :even?
|
20
|
+
# ----
|
21
|
+
#
|
22
|
+
# will suggest both `even?` and `odd?` to be inverted, but only `!=` (and not `==`).
|
19
23
|
#
|
20
24
|
# @safety
|
21
25
|
# This cop is unsafe because it cannot be guaranteed that the method
|
@@ -135,8 +135,7 @@ module RuboCop
|
|
135
135
|
end
|
136
136
|
|
137
137
|
def call_with_braced_block?(node)
|
138
|
-
(node.send_type? || node.super_type?) &&
|
139
|
-
((node.parent&.block_type? || node.parent&.numblock_type?) && node.parent&.braces?)
|
138
|
+
(node.send_type? || node.super_type?) && node.block_node&.braces?
|
140
139
|
end
|
141
140
|
|
142
141
|
def call_as_argument_or_chain?(node)
|
@@ -40,6 +40,15 @@ module RuboCop
|
|
40
40
|
#
|
41
41
|
# # good
|
42
42
|
# foo if [b.lightweight, b.heavyweight].include?(a)
|
43
|
+
#
|
44
|
+
# @example ComparisonsThreshold: 2 (default)
|
45
|
+
# # bad
|
46
|
+
# foo if a == 'a' || a == 'b'
|
47
|
+
#
|
48
|
+
# @example ComparisonsThreshold: 3
|
49
|
+
# # good
|
50
|
+
# foo if a == 'a' || a == 'b'
|
51
|
+
#
|
43
52
|
class MultipleComparison < Base
|
44
53
|
extend AutoCorrector
|
45
54
|
|
@@ -58,6 +67,7 @@ module RuboCop
|
|
58
67
|
return unless node == root_of_or_node
|
59
68
|
return unless nested_variable_comparison?(root_of_or_node)
|
60
69
|
return if @allowed_method_comparison
|
70
|
+
return if @compared_elements.size < comparisons_threshold
|
61
71
|
|
62
72
|
add_offense(node) do |corrector|
|
63
73
|
elements = @compared_elements.join(', ')
|
@@ -151,6 +161,10 @@ module RuboCop
|
|
151
161
|
def allow_method_comparison?
|
152
162
|
cop_config.fetch('AllowMethodComparison', true)
|
153
163
|
end
|
164
|
+
|
165
|
+
def comparisons_threshold
|
166
|
+
cop_config.fetch('ComparisonsThreshold', 2)
|
167
|
+
end
|
154
168
|
end
|
155
169
|
end
|
156
170
|
end
|
@@ -93,7 +93,7 @@ module RuboCop
|
|
93
93
|
def contains_delimiter?(node, delimiters)
|
94
94
|
delimiters_regexp = Regexp.union(delimiters)
|
95
95
|
|
96
|
-
node.children.
|
96
|
+
node.children.filter_map { |n| string_source(n) }.any?(delimiters_regexp)
|
97
97
|
end
|
98
98
|
|
99
99
|
def string_source(node)
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# Checks for the instantiation of array using redundant `Array` constructor.
|
7
|
+
# Autocorrect replaces to array literal which is the simplest and fastest.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# Array.new([])
|
13
|
+
# Array[]
|
14
|
+
# Array([])
|
15
|
+
# Array.new(['foo', 'foo', 'foo'])
|
16
|
+
# Array['foo', 'foo', 'foo']
|
17
|
+
# Array(['foo', 'foo', 'foo'])
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# []
|
21
|
+
# ['foo', 'foo', 'foo']
|
22
|
+
# Array.new(3, 'foo')
|
23
|
+
# Array.new(3) { 'foo' }
|
24
|
+
#
|
25
|
+
class RedundantArrayConstructor < Base
|
26
|
+
extend AutoCorrector
|
27
|
+
|
28
|
+
MSG = 'Remove the redundant `Array` constructor.'
|
29
|
+
|
30
|
+
RESTRICT_ON_SEND = %i[new [] Array].freeze
|
31
|
+
|
32
|
+
# @!method redundant_array_constructor(node)
|
33
|
+
def_node_matcher :redundant_array_constructor, <<~PATTERN
|
34
|
+
{
|
35
|
+
(send
|
36
|
+
(const {nil? cbase} :Array) :new
|
37
|
+
$(array ...))
|
38
|
+
(send
|
39
|
+
(const {nil? cbase} :Array) :[]
|
40
|
+
$...)
|
41
|
+
(send
|
42
|
+
nil? :Array
|
43
|
+
$(array ...))
|
44
|
+
}
|
45
|
+
PATTERN
|
46
|
+
|
47
|
+
def on_send(node)
|
48
|
+
return unless (array_literal = redundant_array_constructor(node))
|
49
|
+
|
50
|
+
receiver = node.receiver
|
51
|
+
selector = node.loc.selector
|
52
|
+
|
53
|
+
if node.method?(:new)
|
54
|
+
range = receiver.source_range.join(selector)
|
55
|
+
replacement = array_literal
|
56
|
+
elsif node.method?(:Array)
|
57
|
+
range = selector
|
58
|
+
replacement = array_literal
|
59
|
+
else
|
60
|
+
range = receiver
|
61
|
+
replacement = selector.begin.join(node.source_range.end)
|
62
|
+
end
|
63
|
+
|
64
|
+
register_offense(range, node, replacement)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def register_offense(range, node, replacement)
|
70
|
+
add_offense(range) do |corrector|
|
71
|
+
corrector.replace(node, replacement.source)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|