rubocop 0.74.0 → 0.75.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 +2 -1
- data/config/default.yml +27 -3
- data/lib/rubocop.rb +6 -1
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +1 -12
- data/lib/rubocop/comment_config.rb +3 -2
- data/lib/rubocop/config.rb +4 -0
- data/lib/rubocop/config_loader.rb +20 -2
- data/lib/rubocop/config_loader_resolver.rb +2 -2
- data/lib/rubocop/config_obsoletion.rb +12 -0
- data/lib/rubocop/cop/autocorrect_logic.rb +2 -2
- data/lib/rubocop/cop/cop.rb +4 -3
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +43 -17
- data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +2 -2
- data/lib/rubocop/cop/generator.rb +3 -3
- data/lib/rubocop/cop/generator/configuration_injector.rb +9 -4
- data/lib/rubocop/cop/generator/require_file_injector.rb +1 -1
- data/lib/rubocop/cop/layout/block_alignment.rb +2 -2
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -1
- data/lib/rubocop/cop/layout/extra_spacing.rb +0 -6
- data/lib/rubocop/cop/layout/indent_assignment.rb +9 -1
- data/lib/rubocop/cop/layout/indent_heredoc.rb +1 -1
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +24 -2
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +5 -1
- data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +1 -1
- data/lib/rubocop/cop/layout/space_inside_block_braces.rb +7 -0
- data/lib/rubocop/cop/layout/space_inside_string_interpolation.rb +2 -0
- data/lib/rubocop/cop/lint/assignment_in_condition.rb +17 -4
- data/lib/rubocop/cop/lint/debugger.rb +1 -1
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +10 -36
- data/lib/rubocop/cop/lint/number_conversion.rb +1 -1
- data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +91 -0
- data/lib/rubocop/cop/lint/unneeded_cop_disable_directive.rb +1 -1
- data/lib/rubocop/cop/message_annotator.rb +16 -7
- data/lib/rubocop/cop/migration/department_name.rb +44 -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/safe_mode.rb +2 -0
- data/lib/rubocop/cop/naming/method_name.rb +12 -1
- data/lib/rubocop/cop/naming/variable_name.rb +1 -0
- data/lib/rubocop/cop/offense.rb +18 -7
- data/lib/rubocop/cop/registry.rb +22 -1
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -0
- data/lib/rubocop/cop/style/block_delimiters.rb +2 -1
- data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +29 -10
- data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
- data/lib/rubocop/cop/style/commented_keyword.rb +8 -2
- data/lib/rubocop/cop/style/conditional_assignment.rb +4 -4
- data/lib/rubocop/cop/style/double_cop_disable_directive.rb +8 -2
- data/lib/rubocop/cop/style/format_string_token.rb +10 -40
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +18 -33
- data/lib/rubocop/cop/style/if_unless_modifier.rb +51 -15
- data/lib/rubocop/cop/style/infinite_loop.rb +1 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +5 -5
- data/lib/rubocop/cop/style/mixin_usage.rb +11 -1
- data/lib/rubocop/cop/style/multiline_memoization.rb +1 -1
- data/lib/rubocop/cop/style/nested_modifier.rb +18 -2
- data/lib/rubocop/cop/style/or_assignment.rb +6 -1
- data/lib/rubocop/cop/style/parentheses_around_condition.rb +14 -0
- data/lib/rubocop/cop/style/redundant_parentheses.rb +13 -4
- data/lib/rubocop/cop/style/redundant_self.rb +18 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +24 -0
- data/lib/rubocop/cop/style/safe_navigation.rb +9 -0
- data/lib/rubocop/cop/style/single_line_methods.rb +8 -1
- data/lib/rubocop/cop/style/ternary_parentheses.rb +19 -0
- data/lib/rubocop/cop/utils/format_string.rb +128 -0
- data/lib/rubocop/cop/variable_force/variable.rb +15 -2
- data/lib/rubocop/core_ext/string.rb +0 -24
- data/lib/rubocop/formatter/emacs_style_formatter.rb +8 -5
- data/lib/rubocop/formatter/formatter_set.rb +2 -1
- data/lib/rubocop/formatter/pacman_formatter.rb +80 -0
- data/lib/rubocop/formatter/simple_text_formatter.rb +9 -1
- data/lib/rubocop/formatter/tap_formatter.rb +9 -1
- data/lib/rubocop/magic_comment.rb +4 -0
- data/lib/rubocop/options.rb +2 -1
- data/lib/rubocop/runner.rb +14 -8
- data/lib/rubocop/version.rb +1 -1
- metadata +6 -3
- data/lib/rubocop/cop/mixin/ignored_method_patterns.rb +0 -19
@@ -12,7 +12,6 @@ module RuboCop
|
|
12
12
|
Description: 'TODO: Write a description of the cop.'
|
13
13
|
Enabled: true
|
14
14
|
VersionAdded: '%<version_added>s'
|
15
|
-
|
16
15
|
YAML
|
17
16
|
|
18
17
|
def initialize(configuration_file_path:, badge:, version_added:)
|
@@ -23,8 +22,13 @@ module RuboCop
|
|
23
22
|
end
|
24
23
|
|
25
24
|
def inject
|
26
|
-
|
27
|
-
|
25
|
+
target_line = find_target_line
|
26
|
+
if target_line
|
27
|
+
configuration_entries.insert(find_target_line,
|
28
|
+
new_configuration_entry + "\n")
|
29
|
+
else
|
30
|
+
configuration_entries.push("\n" + new_configuration_entry)
|
31
|
+
end
|
28
32
|
|
29
33
|
File.write(configuration_file_path, configuration_entries.join)
|
30
34
|
|
@@ -49,7 +53,8 @@ module RuboCop
|
|
49
53
|
|
50
54
|
return index if badge.to_s < line
|
51
55
|
end
|
52
|
-
|
56
|
+
|
57
|
+
nil
|
53
58
|
end
|
54
59
|
|
55
60
|
def cop_name_line?(yaml)
|
@@ -82,9 +82,7 @@ module RuboCop
|
|
82
82
|
token2.text.start_with?('#')
|
83
83
|
|
84
84
|
extra_space_range(token1, token2) do |range|
|
85
|
-
# Unary + doesn't appear as a token and needs special handling.
|
86
85
|
next if ignored_range?(ast, range.begin_pos)
|
87
|
-
next if unary_plus_non_offense?(range)
|
88
86
|
|
89
87
|
add_offense(range, location: range, message: MSG_UNNECESSARY)
|
90
88
|
end
|
@@ -114,10 +112,6 @@ module RuboCop
|
|
114
112
|
ignored_ranges(ast).any? { |r| r.include?(start_pos) }
|
115
113
|
end
|
116
114
|
|
117
|
-
def unary_plus_non_offense?(range)
|
118
|
-
range.resize(range.size + 1).source =~ /^ ?\+$/
|
119
|
-
end
|
120
|
-
|
121
115
|
# Returns an array of ranges that should not be reported. It's the
|
122
116
|
# extra spaces between the keys and values in a multiline hash,
|
123
117
|
# since those are handled by the Style/AlignHash cop.
|
@@ -33,13 +33,21 @@ module RuboCop
|
|
33
33
|
return unless node.loc.operator
|
34
34
|
return if node.loc.operator.line == rhs.first_line
|
35
35
|
|
36
|
-
base = display_column(node.source_range)
|
36
|
+
base = display_column(leftmost_multiple_assignment(node).source_range)
|
37
37
|
check_alignment([rhs], base + configured_indentation_width)
|
38
38
|
end
|
39
39
|
|
40
40
|
def autocorrect(node)
|
41
41
|
AlignmentCorrector.correct(processed_source, node, column_delta)
|
42
42
|
end
|
43
|
+
|
44
|
+
def leftmost_multiple_assignment(node)
|
45
|
+
return node unless node.parent&.assignment?
|
46
|
+
|
47
|
+
leftmost_multiple_assignment(node.parent)
|
48
|
+
|
49
|
+
node.parent
|
50
|
+
end
|
43
51
|
end
|
44
52
|
end
|
45
53
|
end
|
@@ -5,7 +5,9 @@ module RuboCop
|
|
5
5
|
module Layout
|
6
6
|
# This cop checks whether the multiline do end blocks have a newline
|
7
7
|
# after the start of the block. Additionally, it checks whether the block
|
8
|
-
# arguments, if any, are on the same line as the start of the
|
8
|
+
# arguments, if any, are on the same line as the start of the
|
9
|
+
# block. Putting block arguments on separate lines, because the whole
|
10
|
+
# line would otherwise be too long, is accepted.
|
9
11
|
#
|
10
12
|
# @example
|
11
13
|
# # bad
|
@@ -35,6 +37,17 @@ module RuboCop
|
|
35
37
|
# foo(i)
|
36
38
|
# bar(i)
|
37
39
|
# }
|
40
|
+
#
|
41
|
+
# # good
|
42
|
+
# blah { |
|
43
|
+
# long_list,
|
44
|
+
# of_parameters,
|
45
|
+
# that_would_not,
|
46
|
+
# fit_on_one_line
|
47
|
+
# |
|
48
|
+
# foo(i)
|
49
|
+
# bar(i)
|
50
|
+
# }
|
38
51
|
class MultilineBlockLayout < Cop
|
39
52
|
include RangeHelp
|
40
53
|
|
@@ -42,11 +55,13 @@ module RuboCop
|
|
42
55
|
'the block start.'
|
43
56
|
ARG_MSG = 'Block argument expression is not on the same line as the ' \
|
44
57
|
'block start.'
|
58
|
+
PIPE_SIZE = '|'.length
|
45
59
|
|
46
60
|
def on_block(node)
|
47
61
|
return if node.single_line?
|
48
62
|
|
49
|
-
unless args_on_beginning_line?(node)
|
63
|
+
unless args_on_beginning_line?(node) ||
|
64
|
+
line_break_necessary_in_args?(node)
|
50
65
|
add_offense_for_expression(node, node.arguments, ARG_MSG)
|
51
66
|
end
|
52
67
|
|
@@ -79,6 +94,13 @@ module RuboCop
|
|
79
94
|
node.loc.begin.line == node.arguments.loc.last_line
|
80
95
|
end
|
81
96
|
|
97
|
+
def line_break_necessary_in_args?(node)
|
98
|
+
needed_length = node.source_range.column +
|
99
|
+
node.source.lines.first.length +
|
100
|
+
block_arg_string(node.arguments).length + PIPE_SIZE
|
101
|
+
needed_length > max_line_length
|
102
|
+
end
|
103
|
+
|
82
104
|
def add_offense_for_expression(node, expr, msg)
|
83
105
|
expression = expr.source_range
|
84
106
|
range = range_between(expression.begin_pos, expression.end_pos)
|
@@ -3,7 +3,9 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Layout
|
6
|
-
# Checks the spacing inside and after block parameters pipes.
|
6
|
+
# Checks the spacing inside and after block parameters pipes. Line breaks
|
7
|
+
# inside parameter pipes are checked by `Layout/MultilineBlockLayout` and
|
8
|
+
# not by this cop.
|
7
9
|
#
|
8
10
|
# @example EnforcedStyleInsidePipes: no_space (default)
|
9
11
|
# # bad
|
@@ -156,6 +158,8 @@ module RuboCop
|
|
156
158
|
return if space_begin_pos >= space_end_pos
|
157
159
|
|
158
160
|
range = range_between(space_begin_pos, space_end_pos)
|
161
|
+
return if range.source.include?("\n")
|
162
|
+
|
159
163
|
add_offense(range, location: range,
|
160
164
|
message: "#{msg} block parameter detected.")
|
161
165
|
end
|
@@ -84,6 +84,13 @@ module RuboCop
|
|
84
84
|
def on_block(node)
|
85
85
|
return if node.keywords?
|
86
86
|
|
87
|
+
# Do not register an offense for multi-line empty braces. That means
|
88
|
+
# preventing auto-correction to single-line empty braces. It will
|
89
|
+
# conflict with auto-correction by `Layout/SpaceInsideBlockBraces` cop
|
90
|
+
# if auto-corrected to a single-line empty braces.
|
91
|
+
# See: https://github.com/rubocop-hq/rubocop/issues/7363
|
92
|
+
return if node.body.nil? && node.multiline?
|
93
|
+
|
87
94
|
left_brace = node.loc.begin
|
88
95
|
right_brace = node.loc.end
|
89
96
|
|
@@ -6,21 +6,34 @@ module RuboCop
|
|
6
6
|
# This cop checks for assignments in the conditions of
|
7
7
|
# if/while/until.
|
8
8
|
#
|
9
|
-
#
|
9
|
+
# `AllowSafeAssignment` option for safe assignment.
|
10
|
+
# By safe assignment we mean putting parentheses around
|
11
|
+
# an assignment to indicate "I know I'm using an assignment
|
12
|
+
# as a condition. It's not a mistake."
|
10
13
|
#
|
14
|
+
# @example
|
11
15
|
# # bad
|
12
|
-
#
|
13
16
|
# if some_var = true
|
14
17
|
# do_something
|
15
18
|
# end
|
16
19
|
#
|
17
|
-
#
|
20
|
+
# # good
|
21
|
+
# if some_var == true
|
22
|
+
# do_something
|
23
|
+
# end
|
18
24
|
#
|
25
|
+
# @example AllowSafeAssignment: true (default)
|
19
26
|
# # good
|
27
|
+
# if (some_var = true)
|
28
|
+
# do_something
|
29
|
+
# end
|
20
30
|
#
|
21
|
-
#
|
31
|
+
# @example AllowSafeAssignment: false
|
32
|
+
# # bad
|
33
|
+
# if (some_var = true)
|
22
34
|
# do_something
|
23
35
|
# end
|
36
|
+
#
|
24
37
|
class AssignmentInCondition < Cop
|
25
38
|
include SafeAssignment
|
26
39
|
|
@@ -43,7 +43,7 @@ module RuboCop
|
|
43
43
|
PATTERN
|
44
44
|
|
45
45
|
def_node_matcher :debugger_call?, <<~PATTERN
|
46
|
-
{(send {nil? #kernel?} {:debugger :byebug} ...)
|
46
|
+
{(send {nil? #kernel?} {:debugger :byebug :remote_byebug} ...)
|
47
47
|
(send (send {#kernel? nil?} :binding)
|
48
48
|
{:pry :remote_pry :pry_remote} ...)
|
49
49
|
(send (const {nil? (cbase)} :Pry) :rescue ...)
|
@@ -22,16 +22,10 @@ module RuboCop
|
|
22
22
|
# http://rubular.com/r/CvpbxkcTzy
|
23
23
|
MSG = "Number of arguments (%<arg_num>i) to `%<method>s` doesn't " \
|
24
24
|
'match the number of fields (%<field_num>i).'
|
25
|
-
|
26
|
-
/(%(([\s#+-0\*]*)(\d*)?(\.\d+)?[bBdiouxXeEfgGaAcps]|%))/.freeze
|
27
|
-
NAMED_FIELD_REGEX = /%\{[_a-zA-Z][_a-zA-Z]+\}/.freeze
|
25
|
+
|
28
26
|
KERNEL = 'Kernel'
|
29
27
|
SHOVEL = '<<'
|
30
|
-
PERCENT = '%'
|
31
|
-
PERCENT_PERCENT = '%%'
|
32
|
-
DIGIT_DOLLAR_FLAG = /%(\d+)\$/.freeze
|
33
28
|
STRING_TYPES = %i[str dstr].freeze
|
34
|
-
NAMED_INTERPOLATION = /%(?:<\w+>|\{\w+\})/.freeze
|
35
29
|
|
36
30
|
def on_send(node)
|
37
31
|
return unless offending_node?(node)
|
@@ -44,7 +38,7 @@ module RuboCop
|
|
44
38
|
def offending_node?(node)
|
45
39
|
return false unless called_on_string?(node)
|
46
40
|
return false unless method_with_format_args?(node)
|
47
|
-
return false if
|
41
|
+
return false if splat_args?(node)
|
48
42
|
|
49
43
|
num_of_format_args, num_of_expected_fields = count_matches(node)
|
50
44
|
|
@@ -70,16 +64,6 @@ module RuboCop
|
|
70
64
|
sprintf?(node) || format?(node) || percent?(node)
|
71
65
|
end
|
72
66
|
|
73
|
-
def named_mode?(node)
|
74
|
-
relevant_node = if sprintf?(node) || format?(node)
|
75
|
-
node.first_argument
|
76
|
-
elsif percent?(node)
|
77
|
-
node.receiver
|
78
|
-
end
|
79
|
-
|
80
|
-
!relevant_node.source.scan(NAMED_FIELD_REGEX).empty?
|
81
|
-
end
|
82
|
-
|
83
67
|
def splat_args?(node)
|
84
68
|
return false if percent?(node)
|
85
69
|
|
@@ -127,27 +111,17 @@ module RuboCop
|
|
127
111
|
|
128
112
|
def expected_fields_count(node)
|
129
113
|
return :unknown unless node.str_type?
|
130
|
-
return 1 if node.source =~ NAMED_INTERPOLATION
|
131
114
|
|
132
|
-
|
133
|
-
return
|
115
|
+
format_string = RuboCop::Cop::Utils::FormatString.new(node.source)
|
116
|
+
return 1 if format_string.named_interpolation?
|
134
117
|
|
135
|
-
|
136
|
-
|
137
|
-
.scan(FIELD_REGEX)
|
138
|
-
.reject { |x| x.first == PERCENT_PERCENT }
|
139
|
-
.reduce(0) { |acc, elem| acc + arguments_count(elem[2]) }
|
140
|
-
end
|
141
|
-
|
142
|
-
def max_digit_dollar_num(node)
|
143
|
-
node.source.scan(DIGIT_DOLLAR_FLAG).map do |digit_dollar_num|
|
144
|
-
digit_dollar_num.first.to_i
|
145
|
-
end.max
|
146
|
-
end
|
118
|
+
max_digit_dollar_num = format_string.max_digit_dollar_num
|
119
|
+
return max_digit_dollar_num if max_digit_dollar_num&.nonzero?
|
147
120
|
|
148
|
-
|
149
|
-
|
150
|
-
|
121
|
+
format_string
|
122
|
+
.format_sequences
|
123
|
+
.reject(&:percent?)
|
124
|
+
.reduce(0) { |acc, seq| acc + seq.arity }
|
151
125
|
end
|
152
126
|
|
153
127
|
def format?(node)
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
#
|
7
|
+
# This cop checks for `send`, `public_send`, and `__send__` methods
|
8
|
+
# when using mix-in.
|
9
|
+
#
|
10
|
+
# `include` and `prepend` methods were private methods until Ruby 2.0,
|
11
|
+
# they were mixed-in via `send` method. This cop uses Ruby 2.1 or
|
12
|
+
# higher style that can be called by public methods.
|
13
|
+
# And `extend` method that was originally a public method is also targeted
|
14
|
+
# for style unification.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# # bad
|
18
|
+
# Foo.send(:include, Bar)
|
19
|
+
# Foo.send(:prepend, Bar)
|
20
|
+
# Foo.send(:extend, Bar)
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
# Foo.public_send(:include, Bar)
|
24
|
+
# Foo.public_send(:prepend, Bar)
|
25
|
+
# Foo.public_send(:extend, Bar)
|
26
|
+
#
|
27
|
+
# # bad
|
28
|
+
# Foo.__send__(:include, Bar)
|
29
|
+
# Foo.__send__(:prepend, Bar)
|
30
|
+
# Foo.__send__(:extend, Bar)
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# Foo.include Bar
|
34
|
+
# Foo.prepend Bar
|
35
|
+
# Foo.extend Bar
|
36
|
+
#
|
37
|
+
class SendWithMixinArgument < Cop
|
38
|
+
include RangeHelp
|
39
|
+
|
40
|
+
MSG = 'Use `%<method>s %<module_name>s` instead of `%<bad_method>s`.'
|
41
|
+
MIXIN_METHODS = %i[include prepend extend].freeze
|
42
|
+
|
43
|
+
def_node_matcher :send_with_mixin_argument?, <<~PATTERN
|
44
|
+
(send
|
45
|
+
(const _ _) {:send :public_send :__send__}
|
46
|
+
({sym str} $#mixin_method?)
|
47
|
+
$(const _ _))
|
48
|
+
PATTERN
|
49
|
+
|
50
|
+
def on_send(node)
|
51
|
+
send_with_mixin_argument?(node) do |method, module_name|
|
52
|
+
message = message(
|
53
|
+
method, module_name.source, bad_location(node).source
|
54
|
+
)
|
55
|
+
|
56
|
+
add_offense(node, location: bad_location(node), message: message)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def autocorrect(node)
|
61
|
+
send_with_mixin_argument?(node) do |method, module_name|
|
62
|
+
lambda do |corrector|
|
63
|
+
corrector.replace(
|
64
|
+
bad_location(node), "#{method} #{module_name.source}"
|
65
|
+
)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def bad_location(node)
|
73
|
+
loc = node.loc
|
74
|
+
|
75
|
+
range_between(loc.selector.begin_pos, loc.expression.end_pos)
|
76
|
+
end
|
77
|
+
|
78
|
+
def message(method, module_name, bad_method)
|
79
|
+
format(
|
80
|
+
MSG,
|
81
|
+
method: method, module_name: module_name, bad_method: bad_method
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def mixin_method?(node)
|
86
|
+
MIXIN_METHODS.include?(node.to_sym)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|