rubocop 1.75.2 → 1.76.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +19 -13
- data/config/default.yml +79 -23
- data/config/obsoletion.yml +6 -3
- data/lib/rubocop/config_validator.rb +6 -6
- 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 +50 -6
- data/lib/rubocop/cop/gemspec/ordered_dependencies.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/example_description.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_pattern_groups.rb +1 -0
- data/lib/rubocop/cop/internal_affairs/undefined_config.rb +6 -1
- data/lib/rubocop/cop/layout/class_structure.rb +35 -0
- data/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb +1 -1
- 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/layout/hash_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/leading_comment_space.rb +13 -1
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/space_after_semicolon.rb +10 -0
- data/lib/rubocop/cop/layout/space_before_brackets.rb +6 -32
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +5 -1
- data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +3 -0
- data/lib/rubocop/cop/lint/array_literal_in_regexp.rb +2 -3
- data/lib/rubocop/cop/lint/boolean_symbol.rb +1 -1
- data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -5
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +1 -1
- data/lib/rubocop/cop/lint/duplicate_methods.rb +84 -2
- 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 +31 -25
- data/lib/rubocop/cop/lint/missing_cop_enable_directive.rb +1 -1
- data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +5 -0
- data/lib/rubocop/cop/lint/useless_assignment.rb +2 -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/lint/useless_rescue.rb +1 -1
- data/lib/rubocop/cop/lint/void.rb +2 -2
- data/lib/rubocop/cop/message_annotator.rb +7 -3
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
- data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +15 -14
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +2 -0
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +1 -1
- data/lib/rubocop/cop/mixin/trailing_comma.rb +9 -5
- 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/access_modifier_declarations.rb +32 -10
- data/lib/rubocop/cop/style/arguments_forwarding.rb +8 -5
- data/lib/rubocop/cop/style/class_and_module_children.rb +19 -3
- data/lib/rubocop/cop/style/command_literal.rb +1 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +2 -2
- data/lib/rubocop/cop/style/comparable_between.rb +5 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +15 -6
- data/lib/rubocop/cop/style/data_inheritance.rb +7 -0
- 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/eval_with_location.rb +3 -3
- data/lib/rubocop/cop/style/hash_fetch_chain.rb +0 -1
- 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/identical_conditional_branches.rb +3 -3
- data/lib/rubocop/cop/style/if_unless_modifier.rb +22 -4
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +4 -7
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
- data/lib/rubocop/cop/style/it_block_parameter.rb +33 -14
- data/lib/rubocop/cop/style/lambda_call.rb +7 -2
- data/lib/rubocop/cop/style/map_into_array.rb +3 -1
- data/lib/rubocop/cop/style/map_to_hash.rb +11 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +4 -1
- data/lib/rubocop/cop/style/multiline_if_modifier.rb +2 -0
- data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
- data/lib/rubocop/cop/style/redundant_array_flatten.rb +48 -0
- data/lib/rubocop/cop/style/redundant_current_directory_in_path.rb +1 -1
- data/lib/rubocop/cop/style/redundant_format.rb +6 -1
- data/lib/rubocop/cop/style/redundant_line_continuation.rb +0 -3
- data/lib/rubocop/cop/style/redundant_parentheses.rb +31 -3
- data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
- data/lib/rubocop/cop/style/safe_navigation.rb +28 -10
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +4 -2
- data/lib/rubocop/cop/style/string_concatenation.rb +1 -2
- data/lib/rubocop/cop/style/struct_inheritance.rb +8 -1
- data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +7 -1
- data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +1 -1
- data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +1 -1
- data/lib/rubocop/cop/team.rb +1 -1
- data/lib/rubocop/cop/variable_force/assignment.rb +7 -3
- data/lib/rubocop/cops_documentation_generator.rb +6 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -1
- data/lib/rubocop/formatter/html_formatter.rb +1 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +1 -1
- data/lib/rubocop/rspec/cop_helper.rb +2 -2
- data/lib/rubocop/rspec/shared_contexts.rb +1 -2
- data/lib/rubocop/target_finder.rb +5 -1
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +6 -1
- metadata +12 -7
|
@@ -16,16 +16,16 @@ module RuboCop
|
|
|
16
16
|
#
|
|
17
17
|
# In Ruby 3.2, anonymous args/kwargs forwarding has been added.
|
|
18
18
|
#
|
|
19
|
-
# This cop also identifies places where
|
|
20
|
-
# replaced by
|
|
21
|
-
# by setting `UseAnonymousForwarding: false`.
|
|
19
|
+
# This cop also identifies places where `+use_args(*args)+`/`+use_kwargs(**kwargs)+` can be
|
|
20
|
+
# replaced by `+use_args(*)+`/`+use_kwargs(**)+`; if desired, this functionality can be
|
|
21
|
+
# disabled by setting `UseAnonymousForwarding: false`.
|
|
22
22
|
#
|
|
23
23
|
# And this cop has `RedundantRestArgumentNames`, `RedundantKeywordRestArgumentNames`,
|
|
24
24
|
# and `RedundantBlockArgumentNames` options. This configuration is a list of redundant names
|
|
25
25
|
# that are sufficient for anonymizing meaningless naming.
|
|
26
26
|
#
|
|
27
27
|
# Meaningless names that are commonly used can be anonymized by default:
|
|
28
|
-
# e.g.,
|
|
28
|
+
# e.g., `+*args+`, `+**options+`, `&block`, and so on.
|
|
29
29
|
#
|
|
30
30
|
# Names not on this list are likely to be meaningful and are allowed by default.
|
|
31
31
|
#
|
|
@@ -146,7 +146,7 @@ module RuboCop
|
|
|
146
146
|
minimum_target_ruby_version 2.7
|
|
147
147
|
|
|
148
148
|
FORWARDING_LVAR_TYPES = %i[splat kwsplat block_pass].freeze
|
|
149
|
-
ADDITIONAL_ARG_TYPES = %i[lvar arg].freeze
|
|
149
|
+
ADDITIONAL_ARG_TYPES = %i[lvar arg optarg].freeze
|
|
150
150
|
|
|
151
151
|
FORWARDING_MSG = 'Use shorthand syntax `...` for arguments forwarding.'
|
|
152
152
|
ARGS_MSG = 'Use anonymous positional arguments forwarding (`*`).'
|
|
@@ -479,6 +479,9 @@ module RuboCop
|
|
|
479
479
|
end
|
|
480
480
|
|
|
481
481
|
def ruby_32_only_anonymous_forwarding?
|
|
482
|
+
# A block argument and an anonymous block argument are never passed together.
|
|
483
|
+
return false if @send_node.each_ancestor(:any_block).any?
|
|
484
|
+
|
|
482
485
|
def_all_anonymous_args?(@def_node) && send_all_anonymous_args?(@send_node)
|
|
483
486
|
end
|
|
484
487
|
|
|
@@ -131,21 +131,27 @@ module RuboCop
|
|
|
131
131
|
"#{node.body.children.first.const_name}"
|
|
132
132
|
end
|
|
133
133
|
|
|
134
|
+
# rubocop:disable Metrics/AbcSize
|
|
134
135
|
def remove_end(corrector, body)
|
|
135
|
-
remove_begin_pos = body.loc.
|
|
136
|
+
remove_begin_pos = if same_line?(body.loc.name, body.loc.end)
|
|
137
|
+
body.loc.name.end_pos
|
|
138
|
+
else
|
|
139
|
+
body.loc.end.begin_pos - leading_spaces(body).size
|
|
140
|
+
end
|
|
136
141
|
adjustment = processed_source.raw_source[remove_begin_pos] == ';' ? 0 : 1
|
|
137
142
|
range = range_between(remove_begin_pos, body.loc.end.end_pos + adjustment)
|
|
138
143
|
|
|
139
144
|
corrector.remove(range)
|
|
140
145
|
end
|
|
146
|
+
# rubocop:enable Metrics/AbcSize
|
|
141
147
|
|
|
142
148
|
def unindent(corrector, node)
|
|
143
149
|
return unless node.body.children.last
|
|
144
150
|
|
|
145
151
|
last_child_leading_spaces = leading_spaces(node.body.children.last)
|
|
146
|
-
return if leading_spaces(node)
|
|
152
|
+
return if spaces_size(leading_spaces(node)) == spaces_size(last_child_leading_spaces)
|
|
147
153
|
|
|
148
|
-
column_delta = configured_indentation_width - last_child_leading_spaces
|
|
154
|
+
column_delta = configured_indentation_width - spaces_size(last_child_leading_spaces)
|
|
149
155
|
return if column_delta.zero?
|
|
150
156
|
|
|
151
157
|
AlignmentCorrector.correct(corrector, processed_source, node, column_delta)
|
|
@@ -155,6 +161,16 @@ module RuboCop
|
|
|
155
161
|
node.source_range.source_line[/\A\s*/]
|
|
156
162
|
end
|
|
157
163
|
|
|
164
|
+
def spaces_size(spaces_string)
|
|
165
|
+
mapping = { "\t" => tab_indentation_width }
|
|
166
|
+
spaces_string.chars.sum { |character| mapping.fetch(character, 1) }
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def tab_indentation_width
|
|
170
|
+
config.for_cop('Layout/IndentationStyle')['IndentationWidth'] ||
|
|
171
|
+
configured_indentation_width
|
|
172
|
+
end
|
|
173
|
+
|
|
158
174
|
def check_style(node, body, style)
|
|
159
175
|
return if node.identifier.namespace&.cbase_type?
|
|
160
176
|
|
|
@@ -58,7 +58,7 @@ module RuboCop
|
|
|
58
58
|
REGEXP = /(?<keyword>\S+).*#/.freeze
|
|
59
59
|
|
|
60
60
|
SUBCLASS_DEFINITION = /\A\s*class\s+(\w|::)+\s*<\s*(\w|::)+/.freeze
|
|
61
|
-
|
|
61
|
+
METHOD_OR_END_DEFINITIONS = /\A\s*(def\s|end)/.freeze
|
|
62
62
|
|
|
63
63
|
STEEP_REGEXP = /#\ssteep:ignore(\s|\z)/.freeze
|
|
64
64
|
|
|
@@ -102,7 +102,7 @@ module RuboCop
|
|
|
102
102
|
case line
|
|
103
103
|
when SUBCLASS_DEFINITION
|
|
104
104
|
comment.text.start_with?(/#\[.+\]/)
|
|
105
|
-
when
|
|
105
|
+
when METHOD_OR_END_DEFINITIONS
|
|
106
106
|
comment.text.start_with?('#:')
|
|
107
107
|
else
|
|
108
108
|
false
|
|
@@ -9,6 +9,9 @@ module RuboCop
|
|
|
9
9
|
# although the difference generally isn't observable. If you require maximum
|
|
10
10
|
# performance, consider using logical comparison.
|
|
11
11
|
#
|
|
12
|
+
# @safety
|
|
13
|
+
# This cop is unsafe because the receiver may not respond to `between?`.
|
|
14
|
+
#
|
|
12
15
|
# @example
|
|
13
16
|
#
|
|
14
17
|
# # bad
|
|
@@ -61,8 +64,8 @@ module RuboCop
|
|
|
61
64
|
|
|
62
65
|
def register_offense(node, min_and_value, max_and_value)
|
|
63
66
|
value = (min_and_value & max_and_value).first
|
|
64
|
-
min = min_and_value.find { _1 != value }
|
|
65
|
-
max = max_and_value.find { _1 != value }
|
|
67
|
+
min = min_and_value.find { _1 != value } || value
|
|
68
|
+
max = max_and_value.find { _1 != value } || value
|
|
66
69
|
|
|
67
70
|
prefer = "#{value.source}.between?(#{min.source}, #{max.source})"
|
|
68
71
|
add_offense(node, message: format(MSG, prefer: prefer)) do |corrector|
|
|
@@ -314,6 +314,7 @@ module RuboCop
|
|
|
314
314
|
|
|
315
315
|
def assignment_node(node)
|
|
316
316
|
assignment = node.send_type? ? node.last_argument : node.expression
|
|
317
|
+
return unless assignment
|
|
317
318
|
|
|
318
319
|
# ignore pseudo-assignments without rhs in for nodes
|
|
319
320
|
return if node.parent&.for_type?
|
|
@@ -436,7 +437,7 @@ module RuboCop
|
|
|
436
437
|
# Helper module to provide common methods to ConditionalAssignment
|
|
437
438
|
# correctors
|
|
438
439
|
module ConditionalCorrectorHelper
|
|
439
|
-
# rubocop:disable Metrics/AbcSize
|
|
440
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
440
441
|
def remove_whitespace_in_branches(corrector, branch, condition, column)
|
|
441
442
|
branch.each_node do |child|
|
|
442
443
|
next if child.source_range.nil?
|
|
@@ -446,13 +447,19 @@ module RuboCop
|
|
|
446
447
|
corrector.remove(white_space) if white_space.source.strip.empty?
|
|
447
448
|
end
|
|
448
449
|
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
corrector.remove_preceding(loc, loc.column - column)
|
|
450
|
+
if condition.loc.else && !same_line?(condition.else_branch, condition)
|
|
451
|
+
corrector.remove_preceding(condition.loc.else, condition.loc.else.column - column)
|
|
453
452
|
end
|
|
453
|
+
|
|
454
|
+
return unless condition.loc.end && !same_line?(condition.loc.end, condition)
|
|
455
|
+
|
|
456
|
+
corrector.remove_preceding(condition.loc.end, condition.loc.end.column - column)
|
|
457
|
+
end
|
|
458
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
|
|
459
|
+
|
|
460
|
+
def same_line?(node1, node2)
|
|
461
|
+
RuboCop::Cop::Util.same_line?(node1, node2)
|
|
454
462
|
end
|
|
455
|
-
# rubocop:enable Metrics/AbcSize
|
|
456
463
|
|
|
457
464
|
def white_space_range(node, column)
|
|
458
465
|
expression = node.source_range
|
|
@@ -598,6 +605,8 @@ module RuboCop
|
|
|
598
605
|
|
|
599
606
|
return unless (branch_else = branch.parent.loc.else)
|
|
600
607
|
|
|
608
|
+
return if same_line?(branch_else, condition)
|
|
609
|
+
|
|
601
610
|
corrector.remove_preceding(branch_else, branch_else.column - column)
|
|
602
611
|
end
|
|
603
612
|
end
|
|
@@ -4,6 +4,7 @@ module RuboCop
|
|
|
4
4
|
module Cop
|
|
5
5
|
module Style
|
|
6
6
|
# Checks for inheritance from `Data.define` to avoid creating the anonymous parent class.
|
|
7
|
+
# Inheriting from `Data.define` adds a superfluous level in inheritance tree.
|
|
7
8
|
#
|
|
8
9
|
# @safety
|
|
9
10
|
# Autocorrection is unsafe because it will change the inheritance
|
|
@@ -17,12 +18,18 @@ module RuboCop
|
|
|
17
18
|
# end
|
|
18
19
|
# end
|
|
19
20
|
#
|
|
21
|
+
# Person.ancestors
|
|
22
|
+
# # => [Person, #<Class:0x000000010b4e14a0>, Data, (...)]
|
|
23
|
+
#
|
|
20
24
|
# # good
|
|
21
25
|
# Person = Data.define(:first_name, :last_name) do
|
|
22
26
|
# def age
|
|
23
27
|
# 42
|
|
24
28
|
# end
|
|
25
29
|
# end
|
|
30
|
+
#
|
|
31
|
+
# Person.ancestors
|
|
32
|
+
# # => [Person, Data, (...)]
|
|
26
33
|
class DataInheritance < Base
|
|
27
34
|
include RangeHelp
|
|
28
35
|
extend AutoCorrector
|
|
@@ -25,8 +25,9 @@ module RuboCop
|
|
|
25
25
|
# # good
|
|
26
26
|
# def foo = do_something
|
|
27
27
|
#
|
|
28
|
-
# # good
|
|
28
|
+
# # good - without parentheses it's a syntax error
|
|
29
29
|
# def foo() do_something end
|
|
30
|
+
# def foo()=do_something
|
|
30
31
|
#
|
|
31
32
|
# # bad
|
|
32
33
|
# def Baz.foo()
|
|
@@ -38,19 +39,31 @@ module RuboCop
|
|
|
38
39
|
# do_something
|
|
39
40
|
# end
|
|
40
41
|
class DefWithParentheses < Base
|
|
42
|
+
include RangeHelp
|
|
41
43
|
extend AutoCorrector
|
|
42
44
|
|
|
43
45
|
MSG = "Omit the parentheses in defs when the method doesn't accept any arguments."
|
|
44
46
|
|
|
45
47
|
def on_def(node)
|
|
46
|
-
return
|
|
47
|
-
return
|
|
48
|
+
return unless !node.arguments? && (arguments_range = node.arguments.source_range)
|
|
49
|
+
return if parentheses_required?(node, arguments_range)
|
|
48
50
|
|
|
49
|
-
add_offense(
|
|
50
|
-
corrector.remove(
|
|
51
|
+
add_offense(arguments_range) do |corrector|
|
|
52
|
+
corrector.remove(arguments_range)
|
|
51
53
|
end
|
|
52
54
|
end
|
|
53
55
|
alias on_defs on_def
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def parentheses_required?(node, arguments_range)
|
|
60
|
+
return true if node.single_line? && !node.endless?
|
|
61
|
+
|
|
62
|
+
end_pos = arguments_range.end.end_pos
|
|
63
|
+
token_after_argument = range_between(end_pos, end_pos + 1).source
|
|
64
|
+
|
|
65
|
+
token_after_argument == '='
|
|
66
|
+
end
|
|
54
67
|
end
|
|
55
68
|
end
|
|
56
69
|
end
|
|
@@ -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
|
|
@@ -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
|
|
@@ -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
|
#
|
|
@@ -189,7 +189,7 @@ module RuboCop
|
|
|
189
189
|
end
|
|
190
190
|
end
|
|
191
191
|
|
|
192
|
-
# rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
192
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
193
193
|
def check_expressions(node, expressions, insert_position)
|
|
194
194
|
return if expressions.any?(&:nil?)
|
|
195
195
|
|
|
@@ -197,7 +197,7 @@ module RuboCop
|
|
|
197
197
|
|
|
198
198
|
expressions.each do |expression|
|
|
199
199
|
add_offense(expression) do |corrector|
|
|
200
|
-
next if node.if_type? && node.ternary?
|
|
200
|
+
next if node.if_type? && (node.ternary? || node.then?)
|
|
201
201
|
|
|
202
202
|
range = range_by_whole_lines(expression.source_range, include_final_newline: true)
|
|
203
203
|
corrector.remove(range)
|
|
@@ -213,7 +213,7 @@ module RuboCop
|
|
|
213
213
|
end
|
|
214
214
|
end
|
|
215
215
|
end
|
|
216
|
-
# rubocop:enable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
216
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
217
217
|
|
|
218
218
|
def correct_assignment(corrector, node, expression, insert_position)
|
|
219
219
|
if insert_position == :after_condition
|
|
@@ -23,6 +23,17 @@ module RuboCop
|
|
|
23
23
|
# end
|
|
24
24
|
# ----
|
|
25
25
|
#
|
|
26
|
+
# The code `def method_name = body if condition` is considered a bad case by
|
|
27
|
+
# `Style/AmbiguousEndlessMethodDefinition` cop. So, to respect the user's intention to use
|
|
28
|
+
# an endless method definition in the `if` body, the following code is allowed:
|
|
29
|
+
#
|
|
30
|
+
# [source,ruby]
|
|
31
|
+
# ----
|
|
32
|
+
# if condition
|
|
33
|
+
# def method_name = body
|
|
34
|
+
# end
|
|
35
|
+
# ----
|
|
36
|
+
#
|
|
26
37
|
# NOTE: It is allowed when `defined?` argument has an undefined value,
|
|
27
38
|
# because using the modifier form causes the following incompatibility:
|
|
28
39
|
#
|
|
@@ -77,10 +88,14 @@ module RuboCop
|
|
|
77
88
|
[Style::SoleNestedConditional]
|
|
78
89
|
end
|
|
79
90
|
|
|
91
|
+
# rubocop:disable Metrics/AbcSize
|
|
80
92
|
def on_if(node)
|
|
93
|
+
return if endless_method?(node.body)
|
|
94
|
+
|
|
81
95
|
condition = node.condition
|
|
82
96
|
return if defined_nodes(condition).any? { |n| defined_argument_is_undefined?(node, n) } ||
|
|
83
97
|
pattern_matching_nodes(condition).any?
|
|
98
|
+
|
|
84
99
|
return unless (msg = message(node))
|
|
85
100
|
|
|
86
101
|
add_offense(node.loc.keyword, message: format(msg, keyword: node.keyword)) do |corrector|
|
|
@@ -90,9 +105,14 @@ module RuboCop
|
|
|
90
105
|
ignore_node(node)
|
|
91
106
|
end
|
|
92
107
|
end
|
|
108
|
+
# rubocop:enable Metrics/AbcSize
|
|
93
109
|
|
|
94
110
|
private
|
|
95
111
|
|
|
112
|
+
def endless_method?(body)
|
|
113
|
+
body&.any_def_type? && body.endless?
|
|
114
|
+
end
|
|
115
|
+
|
|
96
116
|
def defined_nodes(condition)
|
|
97
117
|
if condition.defined_type?
|
|
98
118
|
[condition]
|
|
@@ -112,12 +132,10 @@ module RuboCop
|
|
|
112
132
|
end
|
|
113
133
|
|
|
114
134
|
def pattern_matching_nodes(condition)
|
|
115
|
-
if condition.
|
|
135
|
+
if condition.any_match_pattern_type?
|
|
116
136
|
[condition]
|
|
117
137
|
else
|
|
118
|
-
condition.each_descendant.select
|
|
119
|
-
node.type?(:match_pattern, :match_pattern_p)
|
|
120
|
-
end
|
|
138
|
+
condition.each_descendant.select(&:any_match_pattern_type?)
|
|
121
139
|
end
|
|
122
140
|
end
|
|
123
141
|
|
|
@@ -28,19 +28,16 @@ module RuboCop
|
|
|
28
28
|
|
|
29
29
|
MSG = 'Avoid modifier `%<keyword>s` after another conditional.'
|
|
30
30
|
|
|
31
|
+
# rubocop:disable Metrics/AbcSize
|
|
31
32
|
def on_if(node)
|
|
32
33
|
return unless node.modifier_form? && node.body.if_type?
|
|
33
34
|
|
|
34
35
|
add_offense(node.loc.keyword, message: format(MSG, keyword: node.keyword)) do |corrector|
|
|
35
|
-
keyword
|
|
36
|
-
|
|
37
|
-
corrector.replace(node, <<~RUBY.chop)
|
|
38
|
-
#{keyword} #{node.condition.source}
|
|
39
|
-
#{node.if_branch.source}
|
|
40
|
-
end
|
|
41
|
-
RUBY
|
|
36
|
+
corrector.wrap(node.if_branch, "#{node.keyword} #{node.condition.source}\n", "\nend")
|
|
37
|
+
corrector.remove(node.if_branch.source_range.end.join(node.condition.source_range.end))
|
|
42
38
|
end
|
|
43
39
|
end
|
|
40
|
+
# rubocop:enable Metrics/AbcSize
|
|
44
41
|
end
|
|
45
42
|
end
|
|
46
43
|
end
|
|
@@ -10,7 +10,7 @@ module RuboCop
|
|
|
10
10
|
# `nonzero?` method is allowed by default.
|
|
11
11
|
# These are customizable with `AllowedMethods` option.
|
|
12
12
|
#
|
|
13
|
-
# This cop targets only
|
|
13
|
+
# This cop targets only ``if``s with a single `elsif` or `else` branch. The following
|
|
14
14
|
# code will be allowed, because it has two `elsif` branches:
|
|
15
15
|
#
|
|
16
16
|
# [source,ruby]
|
|
@@ -5,15 +5,28 @@ module RuboCop
|
|
|
5
5
|
module Style
|
|
6
6
|
# Checks for blocks with one argument where `it` block parameter can be used.
|
|
7
7
|
#
|
|
8
|
-
# It provides
|
|
8
|
+
# It provides four `EnforcedStyle` options:
|
|
9
9
|
#
|
|
10
|
-
# 1. `
|
|
11
|
-
# 2. `
|
|
12
|
-
# 3. `
|
|
10
|
+
# 1. `allow_single_line` (default) ... Always uses the `it` block parameter in a single line.
|
|
11
|
+
# 2. `only_numbered_parameters` ... Detects only numbered block parameters.
|
|
12
|
+
# 3. `always` ... Always uses the `it` block parameter.
|
|
13
|
+
# 4. `disallow` ... Disallows the `it` block parameter.
|
|
13
14
|
#
|
|
14
|
-
# A single numbered parameter is detected when `
|
|
15
|
+
# A single numbered parameter is detected when `allow_single_line`,
|
|
16
|
+
# `only_numbered_parameters`, or `always`.
|
|
15
17
|
#
|
|
16
|
-
# @example EnforcedStyle:
|
|
18
|
+
# @example EnforcedStyle: allow_single_line (default)
|
|
19
|
+
# # bad
|
|
20
|
+
# block do
|
|
21
|
+
# do_something(it)
|
|
22
|
+
# end
|
|
23
|
+
# block { do_something(_1) }
|
|
24
|
+
#
|
|
25
|
+
# # good
|
|
26
|
+
# block { do_something(it) }
|
|
27
|
+
# block { |named_param| do_something(named_param) }
|
|
28
|
+
#
|
|
29
|
+
# @example EnforcedStyle: only_numbered_parameters
|
|
17
30
|
# # bad
|
|
18
31
|
# block { do_something(_1) }
|
|
19
32
|
#
|
|
@@ -42,8 +55,9 @@ module RuboCop
|
|
|
42
55
|
extend TargetRubyVersion
|
|
43
56
|
extend AutoCorrector
|
|
44
57
|
|
|
45
|
-
|
|
46
|
-
|
|
58
|
+
MSG_USE_IT_PARAMETER = 'Use `it` block parameter.'
|
|
59
|
+
MSG_AVOID_IT_PARAMETER = 'Avoid using `it` block parameter.'
|
|
60
|
+
MSG_AVOID_IT_PARAMETER_MULTI_LINE = 'Avoid using numbered parameters for multi-line blocks.'
|
|
47
61
|
|
|
48
62
|
minimum_target_ruby_version 3.4
|
|
49
63
|
|
|
@@ -57,7 +71,7 @@ module RuboCop
|
|
|
57
71
|
variables = find_block_variables(node, node.first_argument.source)
|
|
58
72
|
|
|
59
73
|
variables.each do |variable|
|
|
60
|
-
add_offense(variable, message:
|
|
74
|
+
add_offense(variable, message: MSG_USE_IT_PARAMETER) do |corrector|
|
|
61
75
|
corrector.remove(node.arguments)
|
|
62
76
|
corrector.replace(variable, 'it')
|
|
63
77
|
end
|
|
@@ -71,19 +85,24 @@ module RuboCop
|
|
|
71
85
|
variables = find_block_variables(node, '_1')
|
|
72
86
|
|
|
73
87
|
variables.each do |variable|
|
|
74
|
-
add_offense(variable, message:
|
|
88
|
+
add_offense(variable, message: MSG_USE_IT_PARAMETER) do |corrector|
|
|
75
89
|
corrector.replace(variable, 'it')
|
|
76
90
|
end
|
|
77
91
|
end
|
|
78
92
|
end
|
|
79
93
|
|
|
80
94
|
def on_itblock(node)
|
|
81
|
-
|
|
95
|
+
case style
|
|
96
|
+
when :allow_single_line
|
|
97
|
+
return if node.single_line?
|
|
82
98
|
|
|
83
|
-
|
|
99
|
+
add_offense(node, message: MSG_AVOID_IT_PARAMETER_MULTI_LINE)
|
|
100
|
+
when :disallow
|
|
101
|
+
variables = find_block_variables(node, 'it')
|
|
84
102
|
|
|
85
|
-
|
|
86
|
-
|
|
103
|
+
variables.each do |variable|
|
|
104
|
+
add_offense(variable, message: MSG_AVOID_IT_PARAMETER)
|
|
105
|
+
end
|
|
87
106
|
end
|
|
88
107
|
end
|
|
89
108
|
|
|
@@ -54,9 +54,14 @@ module RuboCop
|
|
|
54
54
|
|
|
55
55
|
def prefer(node)
|
|
56
56
|
receiver = node.receiver.source
|
|
57
|
-
arguments = node.arguments.map(&:source).join(', ')
|
|
58
57
|
dot = node.loc.dot.source
|
|
59
|
-
|
|
58
|
+
call_arguments = if node.arguments.empty?
|
|
59
|
+
''
|
|
60
|
+
else
|
|
61
|
+
arguments = node.arguments.map(&:source).join(', ')
|
|
62
|
+
"(#{arguments})"
|
|
63
|
+
end
|
|
64
|
+
method = explicit_style? ? "call#{call_arguments}" : "(#{arguments})"
|
|
60
65
|
|
|
61
66
|
"#{receiver}#{dot}#{method}"
|
|
62
67
|
end
|
|
@@ -212,9 +212,11 @@ module RuboCop
|
|
|
212
212
|
end
|
|
213
213
|
|
|
214
214
|
def correct_push_node(corrector, push_node)
|
|
215
|
+
arg_node = push_node.first_argument
|
|
215
216
|
range = push_node.source_range
|
|
216
|
-
arg_range =
|
|
217
|
+
arg_range = arg_node.source_range
|
|
217
218
|
|
|
219
|
+
corrector.wrap(arg_node, '{ ', ' }') if arg_node.hash_type? && !arg_node.braces?
|
|
218
220
|
corrector.remove(range_between(range.begin_pos, arg_range.begin_pos))
|
|
219
221
|
corrector.remove(range_between(arg_range.end_pos, range.end_pos))
|
|
220
222
|
end
|