rubocop 1.79.2 → 1.82.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 +1 -1
- data/config/default.yml +35 -7
- data/config/obsoletion.yml +4 -0
- data/exe/rubocop +1 -8
- data/lib/rubocop/cli/command/auto_generate_config.rb +2 -2
- data/lib/rubocop/cli.rb +8 -3
- data/lib/rubocop/comment_config.rb +62 -17
- data/lib/rubocop/config_loader.rb +5 -2
- data/lib/rubocop/config_loader_resolver.rb +7 -6
- data/lib/rubocop/config_store.rb +5 -0
- data/lib/rubocop/cop/autocorrect_logic.rb +8 -4
- data/lib/rubocop/cop/bundler/ordered_gems.rb +1 -2
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +8 -7
- data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +7 -2
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -2
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +10 -5
- data/lib/rubocop/cop/internal_affairs/location_exists.rb +28 -2
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups/ast_processor.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +3 -1
- data/lib/rubocop/cop/internal_affairs/on_send_without_on_csend.rb +1 -1
- data/lib/rubocop/cop/layout/class_structure.rb +1 -1
- data/lib/rubocop/cop/layout/dot_position.rb +1 -1
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +3 -0
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +30 -12
- data/lib/rubocop/cop/layout/empty_lines_after_module_inclusion.rb +1 -1
- data/lib/rubocop/cop/layout/end_alignment.rb +4 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +2 -5
- data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
- data/lib/rubocop/cop/layout/heredoc_indentation.rb +1 -4
- data/lib/rubocop/cop/layout/indentation_style.rb +1 -1
- data/lib/rubocop/cop/layout/indentation_width.rb +12 -1
- data/lib/rubocop/cop/layout/line_continuation_spacing.rb +1 -1
- data/lib/rubocop/cop/layout/line_length.rb +17 -5
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -0
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +5 -1
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +8 -4
- data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +13 -3
- data/lib/rubocop/cop/layout/space_after_comma.rb +2 -10
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +1 -1
- data/lib/rubocop/cop/layout/space_around_keyword.rb +1 -1
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +47 -3
- data/lib/rubocop/cop/lint/constant_overwritten_in_rescue.rb +3 -2
- data/lib/rubocop/cop/lint/cop_directive_syntax.rb +14 -8
- data/lib/rubocop/cop/lint/debugger.rb +0 -2
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -1
- data/lib/rubocop/cop/lint/duplicate_match_pattern.rb +4 -4
- data/lib/rubocop/cop/lint/duplicate_regexp_character_class_element.rb +5 -42
- data/lib/rubocop/cop/lint/else_layout.rb +19 -0
- data/lib/rubocop/cop/lint/empty_interpolation.rb +11 -0
- data/lib/rubocop/cop/lint/literal_as_condition.rb +4 -0
- data/lib/rubocop/cop/lint/literal_in_interpolation.rb +1 -1
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +17 -8
- data/lib/rubocop/cop/lint/no_return_in_begin_end_blocks.rb +4 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +23 -9
- data/lib/rubocop/cop/lint/redundant_require_statement.rb +4 -2
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +7 -1
- data/lib/rubocop/cop/lint/rescue_exception.rb +1 -4
- data/lib/rubocop/cop/lint/self_assignment.rb +15 -6
- data/lib/rubocop/cop/lint/shadowed_argument.rb +7 -7
- data/lib/rubocop/cop/lint/unreachable_code.rb +5 -3
- data/lib/rubocop/cop/lint/uri_escape_unescape.rb +2 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +44 -16
- data/lib/rubocop/cop/lint/useless_or.rb +15 -2
- data/lib/rubocop/cop/lint/utils/nil_receiver_checker.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +7 -0
- data/lib/rubocop/cop/message_annotator.rb +1 -1
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +4 -3
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
- data/lib/rubocop/cop/mixin/check_single_line_suitability.rb +2 -4
- data/lib/rubocop/cop/mixin/code_length.rb +1 -1
- data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -7
- data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -1
- data/lib/rubocop/cop/mixin/line_length_help.rb +21 -2
- data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +1 -1
- data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
- data/lib/rubocop/cop/mixin/space_after_punctuation.rb +5 -4
- data/lib/rubocop/cop/mixin/statement_modifier.rb +0 -6
- data/lib/rubocop/cop/mixin/trailing_comma.rb +8 -5
- data/lib/rubocop/cop/naming/method_name.rb +5 -3
- data/lib/rubocop/cop/naming/predicate_method.rb +19 -6
- data/lib/rubocop/cop/security/json_load.rb +33 -11
- data/lib/rubocop/cop/style/array_intersect.rb +46 -12
- data/lib/rubocop/cop/style/array_intersect_with_single_element.rb +47 -0
- data/lib/rubocop/cop/style/bare_percent_literals.rb +1 -2
- data/lib/rubocop/cop/style/bitwise_predicate.rb +8 -1
- data/lib/rubocop/cop/style/case_equality.rb +11 -13
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -0
- data/lib/rubocop/cop/style/conditional_assignment.rb +8 -14
- data/lib/rubocop/cop/style/constant_visibility.rb +17 -12
- data/lib/rubocop/cop/style/double_negation.rb +1 -1
- data/lib/rubocop/cop/style/empty_method.rb +0 -6
- data/lib/rubocop/cop/style/endless_method.rb +15 -2
- data/lib/rubocop/cop/style/explicit_block_argument.rb +1 -1
- data/lib/rubocop/cop/style/float_division.rb +15 -1
- data/lib/rubocop/cop/style/guard_clause.rb +0 -11
- data/lib/rubocop/cop/style/hash_syntax.rb +1 -1
- data/lib/rubocop/cop/style/if_unless_modifier.rb +3 -3
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +12 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -4
- data/lib/rubocop/cop/style/module_member_existence_check.rb +74 -0
- data/lib/rubocop/cop/style/multiline_method_signature.rb +2 -4
- data/lib/rubocop/cop/style/nil_comparison.rb +9 -7
- data/lib/rubocop/cop/style/one_line_conditional.rb +17 -9
- data/lib/rubocop/cop/style/operator_method_call.rb +11 -2
- data/lib/rubocop/cop/style/parallel_assignment.rb +2 -2
- data/lib/rubocop/cop/style/redundant_argument.rb +2 -0
- data/lib/rubocop/cop/style/redundant_begin.rb +34 -0
- data/lib/rubocop/cop/style/redundant_condition.rb +1 -1
- data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +26 -5
- data/lib/rubocop/cop/style/redundant_interpolation.rb +11 -2
- data/lib/rubocop/cop/style/redundant_parentheses.rb +14 -11
- data/lib/rubocop/cop/style/redundant_percent_q.rb +1 -2
- data/lib/rubocop/cop/style/redundant_regexp_argument.rb +9 -0
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +8 -0
- data/lib/rubocop/cop/style/redundant_sort.rb +7 -7
- data/lib/rubocop/cop/style/safe_navigation.rb +18 -1
- data/lib/rubocop/cop/style/semicolon.rb +23 -7
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +8 -1
- data/lib/rubocop/cop/style/string_concatenation.rb +17 -13
- data/lib/rubocop/cop/style/super_arguments.rb +2 -2
- data/lib/rubocop/cop/style/symbol_array.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
- data/lib/rubocop/cop/style/trailing_underscore_variable.rb +11 -11
- data/lib/rubocop/cop/style/unless_else.rb +10 -9
- data/lib/rubocop/cop/util.rb +2 -3
- data/lib/rubocop/cop/utils/format_string.rb +10 -0
- data/lib/rubocop/cop/variable_force/variable.rb +1 -1
- data/lib/rubocop/cop/variable_force.rb +9 -7
- data/lib/rubocop/cops_documentation_generator.rb +4 -4
- data/lib/rubocop/directive_comment.rb +46 -3
- data/lib/rubocop/formatter/disabled_config_formatter.rb +19 -5
- data/lib/rubocop/lsp/diagnostic.rb +10 -14
- data/lib/rubocop/lsp/routes.rb +31 -2
- data/lib/rubocop/lsp/stdin_runner.rb +0 -16
- data/lib/rubocop/magic_comment.rb +20 -0
- data/lib/rubocop/rake_task.rb +1 -1
- data/lib/rubocop/remote_config.rb +7 -8
- data/lib/rubocop/result_cache.rb +39 -28
- data/lib/rubocop/rspec/shared_contexts.rb +2 -2
- data/lib/rubocop/rspec/support.rb +1 -1
- data/lib/rubocop/runner.rb +10 -4
- data/lib/rubocop/target_finder.rb +9 -9
- data/lib/rubocop/target_ruby.rb +11 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +2 -0
- data/lib/ruby_lsp/rubocop/addon.rb +23 -8
- data/lib/ruby_lsp/rubocop/runtime_adapter.rb +49 -15
- metadata +9 -7
|
@@ -3,31 +3,36 @@
|
|
|
3
3
|
module RuboCop
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
|
-
# Checks for uses of the case equality operator(
|
|
6
|
+
# Checks for uses of the case equality operator (`===`).
|
|
7
7
|
#
|
|
8
8
|
# If `AllowOnConstant` option is enabled, the cop will ignore violations when the receiver of
|
|
9
9
|
# the case equality operator is a constant.
|
|
10
|
-
|
|
10
|
+
#
|
|
11
11
|
# If `AllowOnSelfClass` option is enabled, the cop will ignore violations when the receiver of
|
|
12
12
|
# the case equality operator is `self.class`. Note intermediate variables are not accepted.
|
|
13
13
|
#
|
|
14
|
+
# NOTE: Regexp case equality (`/regexp/ === var`) is allowed because changing it to
|
|
15
|
+
# `/regexp/.match?(var)` needs to take into account `Regexp.last_match?`, `$~`, `$1`, etc.
|
|
16
|
+
# This potentially incompatible transformation is handled by `Performance/RegexpMatch` cop.
|
|
17
|
+
#
|
|
14
18
|
# @example
|
|
15
19
|
# # bad
|
|
16
20
|
# (1..100) === 7
|
|
17
|
-
# /something/ === some_string
|
|
18
21
|
#
|
|
19
22
|
# # good
|
|
20
|
-
# something.is_a?(Array)
|
|
21
23
|
# (1..100).include?(7)
|
|
22
|
-
# /something/.match?(some_string)
|
|
23
24
|
#
|
|
24
25
|
# @example AllowOnConstant: false (default)
|
|
25
26
|
# # bad
|
|
26
27
|
# Array === something
|
|
27
28
|
#
|
|
29
|
+
# # good
|
|
30
|
+
# something.is_a?(Array)
|
|
31
|
+
#
|
|
28
32
|
# @example AllowOnConstant: true
|
|
29
33
|
# # good
|
|
30
34
|
# Array === something
|
|
35
|
+
# something.is_a?(Array)
|
|
31
36
|
#
|
|
32
37
|
# @example AllowOnSelfClass: false (default)
|
|
33
38
|
# # bad
|
|
@@ -51,7 +56,7 @@ module RuboCop
|
|
|
51
56
|
|
|
52
57
|
def on_send(node)
|
|
53
58
|
case_equality?(node) do |lhs, rhs|
|
|
54
|
-
return if lhs.const_type? && !lhs.module_name?
|
|
59
|
+
return if lhs.regexp_type? || (lhs.const_type? && !lhs.module_name?)
|
|
55
60
|
|
|
56
61
|
add_offense(node.loc.selector) do |corrector|
|
|
57
62
|
replacement = replacement(lhs, rhs)
|
|
@@ -71,13 +76,6 @@ module RuboCop
|
|
|
71
76
|
|
|
72
77
|
def replacement(lhs, rhs)
|
|
73
78
|
case lhs.type
|
|
74
|
-
when :regexp
|
|
75
|
-
# The automatic correction from `a === b` to `a.match?(b)` needs to
|
|
76
|
-
# consider `Regexp.last_match?`, `$~`, `$1`, and etc.
|
|
77
|
-
# This correction is expected to be supported by `Performance/Regexp` cop.
|
|
78
|
-
# See: https://github.com/rubocop/rubocop-performance/issues/152
|
|
79
|
-
#
|
|
80
|
-
# So here is noop.
|
|
81
79
|
when :begin
|
|
82
80
|
begin_replacement(lhs, rhs)
|
|
83
81
|
when :const
|
|
@@ -213,9 +213,7 @@ module RuboCop
|
|
|
213
213
|
ASSIGN_TO_CONDITION_MSG = 'Assign variables inside of conditionals.'
|
|
214
214
|
VARIABLE_ASSIGNMENT_TYPES = %i[casgn cvasgn gvasgn ivasgn lvasgn].freeze
|
|
215
215
|
ASSIGNMENT_TYPES = VARIABLE_ASSIGNMENT_TYPES + %i[and_asgn or_asgn op_asgn masgn].freeze
|
|
216
|
-
LINE_LENGTH = 'Layout/LineLength'
|
|
217
216
|
ENABLED = 'Enabled'
|
|
218
|
-
MAX = 'Max'
|
|
219
217
|
SINGLE_LINE_CONDITIONS_ONLY = 'SingleLineConditionsOnly'
|
|
220
218
|
|
|
221
219
|
# The shovel operator `<<` does not have its own type. It is a `send`
|
|
@@ -399,7 +397,7 @@ module RuboCop
|
|
|
399
397
|
# of the longest line + the length of the corrected assignment is
|
|
400
398
|
# greater than the max configured line length
|
|
401
399
|
def correction_exceeds_line_limit?(node, branches)
|
|
402
|
-
return false unless
|
|
400
|
+
return false unless config.cop_enabled?('Layout/LineLength')
|
|
403
401
|
|
|
404
402
|
assignment = lhs(tail(branches[0]))
|
|
405
403
|
|
|
@@ -417,14 +415,6 @@ module RuboCop
|
|
|
417
415
|
assignment + longest_line
|
|
418
416
|
end
|
|
419
417
|
|
|
420
|
-
def line_length_cop_enabled?
|
|
421
|
-
config.for_cop(LINE_LENGTH)[ENABLED]
|
|
422
|
-
end
|
|
423
|
-
|
|
424
|
-
def max_line_length
|
|
425
|
-
config.for_cop(LINE_LENGTH)[MAX]
|
|
426
|
-
end
|
|
427
|
-
|
|
428
418
|
def single_line_conditions_only?
|
|
429
419
|
cop_config[SINGLE_LINE_CONDITIONS_ONLY]
|
|
430
420
|
end
|
|
@@ -444,7 +434,7 @@ module RuboCop
|
|
|
444
434
|
next if child.parent.dstr_type?
|
|
445
435
|
|
|
446
436
|
white_space = white_space_range(child, column)
|
|
447
|
-
corrector.remove(white_space) if white_space
|
|
437
|
+
corrector.remove(white_space) if white_space
|
|
448
438
|
end
|
|
449
439
|
|
|
450
440
|
if condition.loc.else && !same_line?(condition.else_branch, condition)
|
|
@@ -465,9 +455,13 @@ module RuboCop
|
|
|
465
455
|
|
|
466
456
|
def white_space_range(node, column)
|
|
467
457
|
expression = node.source_range
|
|
468
|
-
|
|
458
|
+
end_pos = expression.begin_pos
|
|
459
|
+
begin_pos = end_pos - (expression.column - column - 2)
|
|
460
|
+
|
|
461
|
+
return nil if begin_pos > end_pos
|
|
469
462
|
|
|
470
|
-
Parser::Source::Range.new(expression.source_buffer, begin_pos,
|
|
463
|
+
white_space = Parser::Source::Range.new(expression.source_buffer, begin_pos, end_pos)
|
|
464
|
+
white_space if white_space.source.strip.empty?
|
|
471
465
|
end
|
|
472
466
|
|
|
473
467
|
def assignment(node)
|
|
@@ -29,25 +29,30 @@ module RuboCop
|
|
|
29
29
|
# @example IgnoreModules: false (default)
|
|
30
30
|
# # bad
|
|
31
31
|
# class Foo
|
|
32
|
-
# MyClass = Struct.new
|
|
32
|
+
# MyClass = Struct.new
|
|
33
33
|
# end
|
|
34
34
|
#
|
|
35
35
|
# # good
|
|
36
36
|
# class Foo
|
|
37
|
-
# MyClass = Struct.new
|
|
37
|
+
# MyClass = Struct.new
|
|
38
38
|
# public_constant :MyClass
|
|
39
39
|
# end
|
|
40
40
|
#
|
|
41
41
|
# @example IgnoreModules: true
|
|
42
42
|
# # good
|
|
43
43
|
# class Foo
|
|
44
|
-
# MyClass = Struct.new
|
|
44
|
+
# MyClass = Struct.new
|
|
45
45
|
# end
|
|
46
46
|
#
|
|
47
47
|
class ConstantVisibility < Base
|
|
48
48
|
MSG = 'Explicitly make `%<constant_name>s` public or private using ' \
|
|
49
49
|
'either `#public_constant` or `#private_constant`.'
|
|
50
50
|
|
|
51
|
+
# @!method visibility_declaration_for(node)
|
|
52
|
+
def_node_matcher :visibility_declaration_for, <<~PATTERN
|
|
53
|
+
(send nil? {:public_constant :private_constant} $...)
|
|
54
|
+
PATTERN
|
|
55
|
+
|
|
51
56
|
def on_casgn(node)
|
|
52
57
|
return unless class_or_module_scope?(node)
|
|
53
58
|
return if visibility_declaration?(node)
|
|
@@ -77,20 +82,20 @@ module RuboCop
|
|
|
77
82
|
end
|
|
78
83
|
end
|
|
79
84
|
|
|
85
|
+
# rubocop:disable Metrics/AbcSize
|
|
80
86
|
def visibility_declaration?(node)
|
|
81
87
|
node.parent.each_child_node(:send).any? do |child|
|
|
82
|
-
visibility_declaration_for
|
|
83
|
-
end
|
|
84
|
-
end
|
|
88
|
+
next false unless (arguments = visibility_declaration_for(child))
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
+
arguments = arguments.first.children.first.to_a if arguments.first&.splat_type?
|
|
91
|
+
constant_values = arguments.map do |argument|
|
|
92
|
+
argument.value.to_sym if argument.respond_to?(:value)
|
|
93
|
+
end
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
constant_values.include?(node.name)
|
|
96
|
+
end
|
|
93
97
|
end
|
|
98
|
+
# rubocop:enable Metrics/AbcSize
|
|
94
99
|
end
|
|
95
100
|
end
|
|
96
101
|
end
|
|
@@ -144,7 +144,7 @@ module RuboCop
|
|
|
144
144
|
MSG_REQUIRE_ALWAYS = 'Use endless method definitions.'
|
|
145
145
|
|
|
146
146
|
def on_def(node)
|
|
147
|
-
return if node.assignment_method?
|
|
147
|
+
return if node.assignment_method? || use_heredoc?(node)
|
|
148
148
|
|
|
149
149
|
case style
|
|
150
150
|
when :allow_single_line, :allow_always
|
|
@@ -198,6 +198,13 @@ module RuboCop
|
|
|
198
198
|
add_offense(node) { |corrector| correct_to_multiline(corrector, node) }
|
|
199
199
|
end
|
|
200
200
|
|
|
201
|
+
def use_heredoc?(node)
|
|
202
|
+
return false unless (body = node.body)
|
|
203
|
+
return true if body.any_str_type? && body.heredoc?
|
|
204
|
+
|
|
205
|
+
body.each_descendant(:str).any?(&:heredoc?)
|
|
206
|
+
end
|
|
207
|
+
|
|
201
208
|
def correct_to_multiline(corrector, node)
|
|
202
209
|
replacement = <<~RUBY.strip
|
|
203
210
|
def #{node.method_name}#{arguments(node)}
|
|
@@ -225,7 +232,13 @@ module RuboCop
|
|
|
225
232
|
def too_long_when_made_endless?(node)
|
|
226
233
|
return false unless config.cop_enabled?('Layout/LineLength')
|
|
227
234
|
|
|
228
|
-
|
|
235
|
+
offset = modifier_offset(node)
|
|
236
|
+
|
|
237
|
+
endless_replacement(node).length + offset > max_line_length
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def modifier_offset(node)
|
|
241
|
+
same_line?(node.parent, node) ? node.loc.column - node.parent.loc.column : 0
|
|
229
242
|
end
|
|
230
243
|
end
|
|
231
244
|
end
|
|
@@ -7,9 +7,12 @@ module RuboCop
|
|
|
7
7
|
# It is recommended to either always use `fdiv` or coerce one side only.
|
|
8
8
|
# This cop also provides other options for code consistency.
|
|
9
9
|
#
|
|
10
|
+
# For `Regexp.last_match` and nth reference (e.g., `$1`), it assumes that the value
|
|
11
|
+
# is a string matched by a regular expression, and allows conversion with `#to_f`.
|
|
12
|
+
#
|
|
10
13
|
# @safety
|
|
11
14
|
# This cop is unsafe, because if the operand variable is a string object
|
|
12
|
-
# then
|
|
15
|
+
# then `#to_f` will be removed and an error will occur.
|
|
13
16
|
#
|
|
14
17
|
# [source,ruby]
|
|
15
18
|
# ----
|
|
@@ -84,6 +87,14 @@ module RuboCop
|
|
|
84
87
|
(send !nil? :to_f)
|
|
85
88
|
PATTERN
|
|
86
89
|
|
|
90
|
+
# @!method regexp_last_match?(node)
|
|
91
|
+
def_node_matcher :regexp_last_match?, <<~PATTERN
|
|
92
|
+
{
|
|
93
|
+
(send (const {nil? cbase} :Regexp) :last_match int)
|
|
94
|
+
(:nth_ref _)
|
|
95
|
+
}
|
|
96
|
+
PATTERN
|
|
97
|
+
|
|
87
98
|
def on_send(node)
|
|
88
99
|
return unless offense_condition?(node)
|
|
89
100
|
|
|
@@ -104,6 +115,9 @@ module RuboCop
|
|
|
104
115
|
private
|
|
105
116
|
|
|
106
117
|
def offense_condition?(node)
|
|
118
|
+
return false if regexp_last_match?(node.receiver.receiver) ||
|
|
119
|
+
regexp_last_match?(node.first_argument.receiver)
|
|
120
|
+
|
|
107
121
|
case style
|
|
108
122
|
when :left_coerce
|
|
109
123
|
right_coerce?(node)
|
|
@@ -45,17 +45,6 @@ module RuboCop
|
|
|
45
45
|
# ok
|
|
46
46
|
#
|
|
47
47
|
# # bad
|
|
48
|
-
# if something
|
|
49
|
-
# foo || raise('exception')
|
|
50
|
-
# else
|
|
51
|
-
# ok
|
|
52
|
-
# end
|
|
53
|
-
#
|
|
54
|
-
# # good
|
|
55
|
-
# foo || raise('exception') if something
|
|
56
|
-
# ok
|
|
57
|
-
#
|
|
58
|
-
# # bad
|
|
59
48
|
# define_method(:test) do
|
|
60
49
|
# if something
|
|
61
50
|
# work
|
|
@@ -207,14 +207,14 @@ module RuboCop
|
|
|
207
207
|
def too_long_line_based_on_config?(range, line)
|
|
208
208
|
return false if matches_allowed_pattern?(line)
|
|
209
209
|
|
|
210
|
-
too_long =
|
|
210
|
+
too_long = too_long_line_based_on_allow_cop_directives?(range, line)
|
|
211
211
|
return too_long unless too_long == :undetermined
|
|
212
212
|
|
|
213
213
|
too_long_line_based_on_allow_uri?(line)
|
|
214
214
|
end
|
|
215
215
|
|
|
216
|
-
def
|
|
217
|
-
if
|
|
216
|
+
def too_long_line_based_on_allow_cop_directives?(range, line)
|
|
217
|
+
if allow_cop_directives? && directive_on_source_line?(range.line - 1)
|
|
218
218
|
return line_length_without_directive(line) > max_line_length
|
|
219
219
|
end
|
|
220
220
|
|
|
@@ -68,7 +68,7 @@ module RuboCop
|
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def autocorrect(corrector, node)
|
|
71
|
-
if node.
|
|
71
|
+
if node.post_condition_loop?
|
|
72
72
|
replace_begin_end_with_modifier(corrector, node)
|
|
73
73
|
elsif node.modifier_form?
|
|
74
74
|
replace_source(corrector, node.source_range, modifier_replacement(node))
|
|
@@ -36,10 +36,21 @@ module RuboCop
|
|
|
36
36
|
cop_config.fetch('IncludedMacros', []).map(&:to_sym)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
def included_macro_patterns
|
|
40
|
+
cop_config.fetch('IncludedMacroPatterns', [])
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def matches_included_macro_pattern?(method_name)
|
|
44
|
+
included_macro_patterns.any? do |pattern|
|
|
45
|
+
Regexp.new(pattern).match?(method_name.to_s)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
39
49
|
def ignored_macro?(node)
|
|
40
50
|
cop_config['IgnoreMacros'] &&
|
|
41
51
|
node.macro? &&
|
|
42
|
-
!included_macros_list.include?(node.method_name)
|
|
52
|
+
!included_macros_list.include?(node.method_name) &&
|
|
53
|
+
!matches_included_macro_pattern?(node.method_name)
|
|
43
54
|
end
|
|
44
55
|
end
|
|
45
56
|
end
|
|
@@ -9,17 +9,20 @@ module RuboCop
|
|
|
9
9
|
# In the default style (require_parentheses), macro methods are allowed.
|
|
10
10
|
# Additional methods can be added to the `AllowedMethods` or
|
|
11
11
|
# `AllowedPatterns` list. These options are valid only in the default
|
|
12
|
-
# style. Macros can be included by either setting `IgnoreMacros` to false
|
|
13
|
-
#
|
|
12
|
+
# style. Macros can be included by either setting `IgnoreMacros` to false,
|
|
13
|
+
# adding specific macros to the `IncludedMacros` list, or using
|
|
14
|
+
# `IncludedMacroPatterns` for pattern-based matching.
|
|
14
15
|
#
|
|
15
16
|
# Precedence of options is as follows:
|
|
16
17
|
#
|
|
17
18
|
# 1. `AllowedMethods`
|
|
18
19
|
# 2. `AllowedPatterns`
|
|
19
20
|
# 3. `IncludedMacros`
|
|
21
|
+
# 4. `IncludedMacroPatterns`
|
|
20
22
|
#
|
|
21
|
-
# If a method is listed in both `IncludedMacros`
|
|
22
|
-
# then the latter takes precedence (that is, the
|
|
23
|
+
# If a method is listed in both `IncludedMacros`/`IncludedMacroPatterns`
|
|
24
|
+
# and `AllowedMethods`, then the latter takes precedence (that is, the
|
|
25
|
+
# method is allowed).
|
|
23
26
|
#
|
|
24
27
|
# In the alternative style (omit_parentheses), there are three additional
|
|
25
28
|
# options.
|
|
@@ -148,6 +151,16 @@ module RuboCop
|
|
|
148
151
|
# # still enforces parentheses on other methods
|
|
149
152
|
# array.delete(e)
|
|
150
153
|
#
|
|
154
|
+
# @example IncludedMacroPatterns: ["^assert", "^refute"]
|
|
155
|
+
#
|
|
156
|
+
# # bad
|
|
157
|
+
# assert_equal 'test', x
|
|
158
|
+
# refute_nil value
|
|
159
|
+
#
|
|
160
|
+
# # good
|
|
161
|
+
# assert_equal('test', x)
|
|
162
|
+
# refute_nil(value)
|
|
163
|
+
#
|
|
151
164
|
# @example AllowParenthesesInMultilineCall: false (default)
|
|
152
165
|
#
|
|
153
166
|
# # bad
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuboCop
|
|
4
|
+
module Cop
|
|
5
|
+
module Style
|
|
6
|
+
# Checks for usage of `Module` methods returning arrays that can be replaced
|
|
7
|
+
# with equivalent predicates.
|
|
8
|
+
#
|
|
9
|
+
# Calling a method returning an array then checking if an element is inside
|
|
10
|
+
# it is much slower than using an equivalent predicate method. For example,
|
|
11
|
+
# `instance_methods.include?` will return an array of all public and protected
|
|
12
|
+
# instance methods in the module, then check if a given method is inside that
|
|
13
|
+
# array, while `method_defined?` will do direct method lookup, which is much
|
|
14
|
+
# faster and consumes less memory.
|
|
15
|
+
#
|
|
16
|
+
# @example
|
|
17
|
+
# # bad
|
|
18
|
+
# Array.instance_methods.include?(:size)
|
|
19
|
+
# Array.instance_methods.member?(:size)
|
|
20
|
+
# Array.instance_methods(true).include?(:size)
|
|
21
|
+
#
|
|
22
|
+
# Array.instance_methods(false).include?(:find)
|
|
23
|
+
#
|
|
24
|
+
# # good
|
|
25
|
+
# Array.method_defined?(:size)
|
|
26
|
+
#
|
|
27
|
+
# Array.method_defined?(:find, false)
|
|
28
|
+
#
|
|
29
|
+
class ModuleMemberExistenceCheck < Base
|
|
30
|
+
extend AutoCorrector
|
|
31
|
+
|
|
32
|
+
MSG = 'Use `%<replacement>s` instead.'
|
|
33
|
+
|
|
34
|
+
RESTRICT_ON_SEND = %i[instance_methods].freeze
|
|
35
|
+
|
|
36
|
+
# @!method instance_methods_inclusion?(node)
|
|
37
|
+
def_node_matcher :instance_methods_inclusion?, <<~PATTERN
|
|
38
|
+
(call
|
|
39
|
+
(call _ :instance_methods _?)
|
|
40
|
+
{:include? :member?}
|
|
41
|
+
_)
|
|
42
|
+
PATTERN
|
|
43
|
+
|
|
44
|
+
def on_send(node) # rubocop:disable Metrics/AbcSize
|
|
45
|
+
return unless (parent = node.parent)
|
|
46
|
+
return unless instance_methods_inclusion?(parent)
|
|
47
|
+
return unless simple_method_argument?(node) && simple_method_argument?(parent)
|
|
48
|
+
|
|
49
|
+
offense_range = node.location.selector.join(parent.source_range.end)
|
|
50
|
+
replacement =
|
|
51
|
+
if node.first_argument.nil? || node.first_argument.true_type?
|
|
52
|
+
"method_defined?(#{parent.first_argument.source})"
|
|
53
|
+
else
|
|
54
|
+
"method_defined?(#{parent.first_argument.source}, #{node.first_argument.source})"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
add_offense(offense_range, message: format(MSG, replacement: replacement)) do |corrector|
|
|
58
|
+
corrector.replace(offense_range, replacement)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
alias on_csend on_send
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def simple_method_argument?(node)
|
|
66
|
+
return false if node.splat_argument? || node.block_argument?
|
|
67
|
+
return false if node.first_argument&.hash_type?
|
|
68
|
+
|
|
69
|
+
true
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -75,6 +75,8 @@ module RuboCop
|
|
|
75
75
|
end
|
|
76
76
|
|
|
77
77
|
def correction_exceeds_max_line_length?(node)
|
|
78
|
+
return false unless max_line_length
|
|
79
|
+
|
|
78
80
|
indentation_width(node) + definition_width(node) > max_line_length
|
|
79
81
|
end
|
|
80
82
|
|
|
@@ -85,10 +87,6 @@ module RuboCop
|
|
|
85
87
|
def definition_width(node)
|
|
86
88
|
node.source_range.begin.join(node.arguments.source_range.end).length
|
|
87
89
|
end
|
|
88
|
-
|
|
89
|
-
def max_line_length
|
|
90
|
-
config.for_cop('Layout/LineLength')['Max'] || 120
|
|
91
|
-
end
|
|
92
90
|
end
|
|
93
91
|
end
|
|
94
92
|
end
|
|
@@ -43,24 +43,26 @@ module RuboCop
|
|
|
43
43
|
# @!method nil_check?(node)
|
|
44
44
|
def_node_matcher :nil_check?, '(send _ :nil?)'
|
|
45
45
|
|
|
46
|
+
# rubocop:disable Metrics/AbcSize
|
|
46
47
|
def on_send(node)
|
|
47
48
|
return unless node.receiver
|
|
48
49
|
|
|
49
50
|
style_check?(node) do
|
|
50
51
|
add_offense(node.loc.selector) do |corrector|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
52
|
+
if prefer_comparison?
|
|
53
|
+
range = node.loc.dot.join(node.loc.selector.end)
|
|
54
|
+
corrector.replace(range, ' == nil')
|
|
55
|
+
else
|
|
56
|
+
range = node.receiver.source_range.end.join(node.source_range.end)
|
|
57
|
+
corrector.replace(range, '.nil?')
|
|
58
|
+
end
|
|
58
59
|
|
|
59
60
|
parent = node.parent
|
|
60
61
|
corrector.wrap(node, '(', ')') if parent.respond_to?(:method?) && parent.method?(:!)
|
|
61
62
|
end
|
|
62
63
|
end
|
|
63
64
|
end
|
|
65
|
+
# rubocop:enable Metrics/AbcSize
|
|
64
66
|
|
|
65
67
|
private
|
|
66
68
|
|
|
@@ -55,19 +55,21 @@ module RuboCop
|
|
|
55
55
|
include OnNormalIfUnless
|
|
56
56
|
extend AutoCorrector
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
MSG_SUFFIX = 'over single-line `%<keyword>s/then/else/end` constructs.'
|
|
59
|
+
MSG_TERNARY = "Favor the ternary operator (`?:`) #{MSG_SUFFIX}"
|
|
60
|
+
MSG_MULTILINE = "Favor multi-line `%<keyword>s` #{MSG_SUFFIX}"
|
|
60
61
|
|
|
61
62
|
def on_normal_if_unless(node)
|
|
62
63
|
return unless node.single_line?
|
|
63
64
|
return unless node.else_branch
|
|
64
65
|
return if node.elsif? || node.if_branch&.begin_type?
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
multiline = multiline?(node)
|
|
68
|
+
|
|
69
|
+
add_offense(node, message: message(node, multiline)) do |corrector|
|
|
68
70
|
next if part_of_ignored_node?(node)
|
|
69
71
|
|
|
70
|
-
autocorrect(corrector, node)
|
|
72
|
+
autocorrect(corrector, node, multiline)
|
|
71
73
|
|
|
72
74
|
ignore_node(node)
|
|
73
75
|
end
|
|
@@ -75,12 +77,18 @@ module RuboCop
|
|
|
75
77
|
|
|
76
78
|
private
|
|
77
79
|
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
+
def multiline?(node)
|
|
81
|
+
always_multiline? || cannot_replace_to_ternary?(node)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def message(node, multiline)
|
|
85
|
+
template = multiline ? MSG_MULTILINE : MSG_TERNARY
|
|
86
|
+
|
|
87
|
+
format(template, keyword: node.keyword)
|
|
80
88
|
end
|
|
81
89
|
|
|
82
|
-
def autocorrect(corrector, node)
|
|
83
|
-
if
|
|
90
|
+
def autocorrect(corrector, node, multiline)
|
|
91
|
+
if multiline
|
|
84
92
|
IfThenCorrector.new(node, indentation: configured_indentation_width).call(corrector)
|
|
85
93
|
else
|
|
86
94
|
corrector.replace(node, ternary_correction(node))
|
|
@@ -26,9 +26,10 @@ module RuboCop
|
|
|
26
26
|
splat kwsplat forwarded_args forwarded_restarg forwarded_kwrestarg block_pass
|
|
27
27
|
].freeze
|
|
28
28
|
|
|
29
|
-
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
29
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
30
30
|
def on_send(node)
|
|
31
31
|
return unless (dot = node.loc.dot)
|
|
32
|
+
return if unary_method_no_operator?(node)
|
|
32
33
|
return if node.receiver.const_type? || !node.arguments.one?
|
|
33
34
|
|
|
34
35
|
return unless (rhs = node.first_argument)
|
|
@@ -43,10 +44,18 @@ module RuboCop
|
|
|
43
44
|
corrector.insert_after(selector, ' ') if insert_space_after?(node)
|
|
44
45
|
end
|
|
45
46
|
end
|
|
46
|
-
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
47
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
47
48
|
|
|
48
49
|
private
|
|
49
50
|
|
|
51
|
+
# `foo.~@` and `foo.!@` call the method `~` and `!` respectively. While those
|
|
52
|
+
# are operator methods, we don't want to actually consider them as such.
|
|
53
|
+
def unary_method_no_operator?(node)
|
|
54
|
+
return false unless node.nonmutating_unary_operator_method?
|
|
55
|
+
|
|
56
|
+
node.method_name.to_s != node.selector.source
|
|
57
|
+
end
|
|
58
|
+
|
|
50
59
|
# Checks for an acceptable case of `foo.+(bar).baz`.
|
|
51
60
|
def method_call_with_parenthesized_arg?(argument)
|
|
52
61
|
return false unless argument.parent.parent&.send_type?
|
|
@@ -14,7 +14,7 @@ module RuboCop
|
|
|
14
14
|
#
|
|
15
15
|
# # good
|
|
16
16
|
# one, two = *foo
|
|
17
|
-
# a, b = foo
|
|
17
|
+
# a, b = foo
|
|
18
18
|
# a, b = b, a
|
|
19
19
|
#
|
|
20
20
|
# a = 1
|
|
@@ -223,7 +223,7 @@ module RuboCop
|
|
|
223
223
|
# __FILE__ is treated as a StrNode but has no begin
|
|
224
224
|
if node.str_type? && loc.respond_to?(:begin) && loc.begin.nil?
|
|
225
225
|
"'#{node.source}'"
|
|
226
|
-
elsif node.sym_type? && loc
|
|
226
|
+
elsif node.sym_type? && !node.loc?(:begin)
|
|
227
227
|
":#{node.source}"
|
|
228
228
|
else
|
|
229
229
|
node.source
|