rubocop 1.8.1 → 1.9.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 +2 -2
- data/config/default.yml +37 -4
- data/lib/rubocop.rb +6 -0
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
- data/lib/rubocop/config.rb +5 -2
- data/lib/rubocop/config_loader.rb +7 -14
- data/lib/rubocop/config_store.rb +12 -1
- data/lib/rubocop/cop/base.rb +2 -1
- data/lib/rubocop/cop/exclude_limit.rb +26 -0
- data/lib/rubocop/cop/generator.rb +1 -3
- data/lib/rubocop/cop/internal_affairs.rb +5 -1
- data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
- data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
- data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
- data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
- data/lib/rubocop/cop/layout/class_structure.rb +7 -2
- data/lib/rubocop/cop/layout/empty_line_between_defs.rb +37 -17
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +16 -2
- data/lib/rubocop/cop/layout/line_length.rb +2 -1
- data/lib/rubocop/cop/layout/space_before_brackets.rb +9 -4
- data/lib/rubocop/cop/lint/deprecated_constants.rb +5 -0
- data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
- data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
- data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
- data/lib/rubocop/cop/lint/symbol_conversion.rb +103 -0
- data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
- data/lib/rubocop/cop/message_annotator.rb +4 -1
- data/lib/rubocop/cop/metrics/block_nesting.rb +2 -2
- data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
- data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
- data/lib/rubocop/cop/mixin/code_length.rb +3 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +0 -1
- data/lib/rubocop/cop/mixin/configurable_max.rb +1 -0
- data/lib/rubocop/cop/mixin/method_complexity.rb +3 -1
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
- data/lib/rubocop/cop/naming/variable_number.rb +1 -1
- data/lib/rubocop/cop/severity.rb +3 -3
- data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
- data/lib/rubocop/cop/style/eval_with_location.rb +63 -34
- data/lib/rubocop/cop/style/float_division.rb +3 -0
- data/lib/rubocop/cop/style/format_string_token.rb +18 -2
- data/lib/rubocop/cop/style/if_inside_else.rb +14 -7
- data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +120 -0
- data/lib/rubocop/cop/style/nil_comparison.rb +3 -0
- data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
- data/lib/rubocop/cop/style/numeric_literals.rb +6 -9
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/single_line_methods.rb +3 -1
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +26 -2
- data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
- data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
- data/lib/rubocop/formatter/simple_text_formatter.rb +2 -1
- data/lib/rubocop/magic_comment.rb +30 -1
- data/lib/rubocop/options.rb +1 -1
- data/lib/rubocop/rspec/expect_offense.rb +5 -2
- data/lib/rubocop/runner.rb +1 -0
- data/lib/rubocop/version.rb +2 -2
- metadata +13 -3
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks for uses of numbered parameter assignment.
|
7
|
+
# It emulates the following warning in Ruby 2.7:
|
8
|
+
#
|
9
|
+
# % ruby -ve '_1 = :value'
|
10
|
+
# ruby 2.7.2p137 (2020-10-01 revision 5445e04352) [x86_64-darwin19]
|
11
|
+
# -e:1: warning: `_1' is reserved for numbered parameter; consider another name
|
12
|
+
#
|
13
|
+
# Assiging to numbered parameter (from `_1` to `_9`) cause an error in Ruby 3.0.
|
14
|
+
#
|
15
|
+
# % ruby -ve '_1 = :value'
|
16
|
+
# ruby 3.0.0p0 (2020-12-25 revision 95aff21468) [x86_64-darwin19]
|
17
|
+
# -e:1: _1 is reserved for numbered parameter
|
18
|
+
#
|
19
|
+
# NOTE: The parametered parameters are from `_1` to `_9`. This cop checks `_0`, and over `_10`
|
20
|
+
# as well to prevent confusion.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
#
|
24
|
+
# # bad
|
25
|
+
# _1 = :value
|
26
|
+
#
|
27
|
+
# # good
|
28
|
+
# non_numbered_parameter_name = :value
|
29
|
+
#
|
30
|
+
class NumberedParameterAssignment < Base
|
31
|
+
NUM_PARAM_MSG = '`_%<number>s` is reserved for numbered parameter; consider another name.'
|
32
|
+
LVAR_MSG = '`_%<number>s` is similar to numbered parameter; consider another name.'
|
33
|
+
NUMBERED_PARAMETER_RANGE = (1..9).freeze
|
34
|
+
|
35
|
+
def on_lvasgn(node)
|
36
|
+
lhs, _rhs = *node
|
37
|
+
return unless /\A_(\d+)\z/ =~ lhs
|
38
|
+
|
39
|
+
number = Regexp.last_match(1).to_i
|
40
|
+
template = NUMBERED_PARAMETER_RANGE.include?(number) ? NUM_PARAM_MSG : LVAR_MSG
|
41
|
+
|
42
|
+
add_offense(node, message: format(template, number: number))
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks for unintended or-assignment to a constant.
|
7
|
+
#
|
8
|
+
# Constants should always be assigned in the same location. And its value
|
9
|
+
# should always be the same. If constants are assigned in multiple
|
10
|
+
# locations, the result may vary depending on the order of `require`.
|
11
|
+
#
|
12
|
+
# Also, if you already have such an implementation, auto-correction may
|
13
|
+
# change the result.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
#
|
17
|
+
# # bad
|
18
|
+
# CONST ||= 1
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# CONST = 1
|
22
|
+
#
|
23
|
+
class OrAssignmentToConstant < Base
|
24
|
+
extend AutoCorrector
|
25
|
+
|
26
|
+
MSG = 'Avoid using or-assignment with constants.'
|
27
|
+
|
28
|
+
def on_or_asgn(node)
|
29
|
+
lhs, _rhs = *node
|
30
|
+
return unless lhs&.casgn_type?
|
31
|
+
|
32
|
+
add_offense(node.loc.operator) do |corrector|
|
33
|
+
corrector.replace(node.loc.operator, '=')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks for uses of literal strings converted to
|
7
|
+
# a symbol where a literal symbol could be used instead.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# 'string'.to_sym
|
12
|
+
# :symbol.to_sym
|
13
|
+
# 'underscored_string'.to_sym
|
14
|
+
# :'underscored_symbol'
|
15
|
+
# 'hyphenated-string'.to_sym
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# :string
|
19
|
+
# :symbol
|
20
|
+
# :underscored_string
|
21
|
+
# :underscored_symbol
|
22
|
+
# :'hyphenated-string'
|
23
|
+
#
|
24
|
+
class SymbolConversion < Base
|
25
|
+
extend AutoCorrector
|
26
|
+
|
27
|
+
MSG = 'Unnecessary symbol conversion; use `%<correction>s` instead.'
|
28
|
+
RESTRICT_ON_SEND = %i[to_sym intern].freeze
|
29
|
+
|
30
|
+
def on_send(node)
|
31
|
+
return unless node.receiver
|
32
|
+
return unless node.receiver.str_type? || node.receiver.sym_type?
|
33
|
+
|
34
|
+
register_offense(node, correction: node.receiver.value.to_sym.inspect)
|
35
|
+
end
|
36
|
+
|
37
|
+
def on_sym(node)
|
38
|
+
return if properly_quoted?(node.source, node.value.inspect)
|
39
|
+
|
40
|
+
# `alias` arguments are symbols but since a symbol that requires
|
41
|
+
# being quoted is not a valid method identifier, it can be ignored
|
42
|
+
return if in_alias?(node)
|
43
|
+
|
44
|
+
# The `%I[]` and `%i[]` macros are parsed as normal arrays of symbols
|
45
|
+
# so they need to be ignored.
|
46
|
+
return if in_percent_literal_array?(node)
|
47
|
+
|
48
|
+
# Symbol hash keys have a different format and need to be handled separately
|
49
|
+
return correct_hash_key(node) if hash_key?(node)
|
50
|
+
|
51
|
+
register_offense(node, correction: node.value.inspect)
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def register_offense(node, correction:, message: format(MSG, correction: correction))
|
57
|
+
add_offense(node, message: message) do |corrector|
|
58
|
+
corrector.replace(node, correction)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def properly_quoted?(source, value)
|
63
|
+
return true if !source.match?(/['"]/) || value.end_with?('=')
|
64
|
+
|
65
|
+
source == value ||
|
66
|
+
# `Symbol#inspect` uses double quotes, but allow single-quoted
|
67
|
+
# symbols to work as well.
|
68
|
+
source.tr("'", '"') == value
|
69
|
+
end
|
70
|
+
|
71
|
+
def in_alias?(node)
|
72
|
+
node.parent&.alias_type?
|
73
|
+
end
|
74
|
+
|
75
|
+
def in_percent_literal_array?(node)
|
76
|
+
node.parent&.array_type? && node.parent&.percent_literal?
|
77
|
+
end
|
78
|
+
|
79
|
+
def hash_key?(node)
|
80
|
+
node.parent&.pair_type? && node == node.parent.child_nodes.first
|
81
|
+
end
|
82
|
+
|
83
|
+
def correct_hash_key(node)
|
84
|
+
# Although some operators can be converted to symbols normally
|
85
|
+
# (ie. `:==`), these are not accepted as hash keys and will
|
86
|
+
# raise a syntax error (eg. `{ ==: ... }`). Therefore, if the
|
87
|
+
# symbol does not start with an alpha-numeric or underscore, it
|
88
|
+
# will be ignored.
|
89
|
+
return unless node.value.to_s.match?(/\A[a-z0-9_]/i)
|
90
|
+
|
91
|
+
correction = node.value.inspect.gsub(/\A:/, '')
|
92
|
+
return if properly_quoted?(node.source, correction)
|
93
|
+
|
94
|
+
register_offense(
|
95
|
+
node,
|
96
|
+
correction: correction,
|
97
|
+
message: format(MSG, correction: "#{correction}:")
|
98
|
+
)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Lint
|
6
|
+
# This cop checks for "triple quotes" (strings delimted by any odd number
|
7
|
+
# of quotes greater than 1).
|
8
|
+
#
|
9
|
+
# Ruby allows multiple strings to be implicitly concatenated by just
|
10
|
+
# being adjacent in a statement (ie. `"foo""bar" == "foobar"`). This sometimes
|
11
|
+
# gives the impression that there is something special about triple quotes, but
|
12
|
+
# in fact it is just extra unnecessary quotes and produces the same string. Each
|
13
|
+
# pair of quotes produces an additional concatenated empty string, so the result
|
14
|
+
# is still only the "actual" string within the delimiters.
|
15
|
+
#
|
16
|
+
# NOTE: Although this cop is called triple quotes, the same behavior is present
|
17
|
+
# for strings delimited by 5, 7, etc. quotation marks.
|
18
|
+
#
|
19
|
+
# @example
|
20
|
+
# # bad
|
21
|
+
# """
|
22
|
+
# A string
|
23
|
+
# """
|
24
|
+
#
|
25
|
+
# # bad
|
26
|
+
# '''
|
27
|
+
# A string
|
28
|
+
# '''
|
29
|
+
#
|
30
|
+
# # good
|
31
|
+
# "
|
32
|
+
# A string
|
33
|
+
# "
|
34
|
+
#
|
35
|
+
# # good
|
36
|
+
# <<STRING
|
37
|
+
# A string
|
38
|
+
# STRING
|
39
|
+
#
|
40
|
+
# # good (but not the same spacing as the bad case)
|
41
|
+
# 'A string'
|
42
|
+
class TripleQuotes < Base
|
43
|
+
extend AutoCorrector
|
44
|
+
|
45
|
+
MSG = 'Delimiting a string with multiple quotes has no effect, use a single quote instead.'
|
46
|
+
|
47
|
+
def on_dstr(node)
|
48
|
+
return if (empty_str_nodes = empty_str_nodes(node)).none?
|
49
|
+
|
50
|
+
opening_quotes = node.source.scan(/(?<=\A)['"]*/)[0]
|
51
|
+
return if opening_quotes.size < 3
|
52
|
+
|
53
|
+
# If the node is composed of only empty `str` nodes, keep one
|
54
|
+
empty_str_nodes.shift if empty_str_nodes.size == node.child_nodes.size
|
55
|
+
|
56
|
+
add_offense(node) do |corrector|
|
57
|
+
empty_str_nodes.each do |str|
|
58
|
+
corrector.remove(str)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def empty_str_nodes(node)
|
66
|
+
node.each_child_node(:str).select { |str| str.value == '' }
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -85,8 +85,11 @@ module RuboCop
|
|
85
85
|
end
|
86
86
|
end
|
87
87
|
|
88
|
+
# Returns the base style guide URL from AllCops or the specific department
|
89
|
+
#
|
90
|
+
# @return [String] style guide URL
|
88
91
|
def style_guide_base_url
|
89
|
-
department_name = cop_name.split('/').
|
92
|
+
department_name = cop_name.split('/')[0..-2].join('/')
|
90
93
|
|
91
94
|
config.for_department(department_name)['StyleGuideBaseURL'] ||
|
92
95
|
config.for_all_cops['StyleGuideBaseURL']
|
@@ -12,13 +12,13 @@ module RuboCop
|
|
12
12
|
#
|
13
13
|
# The maximum level of nesting allowed is configurable.
|
14
14
|
class BlockNesting < Base
|
15
|
-
include ConfigurableMax
|
16
|
-
|
17
15
|
NESTING_BLOCKS = %i[
|
18
16
|
case if while while_post
|
19
17
|
until until_post for resbody
|
20
18
|
].freeze
|
21
19
|
|
20
|
+
exclude_limit 'Max'
|
21
|
+
|
22
22
|
def on_new_investigation
|
23
23
|
return if processed_source.blank?
|
24
24
|
|
@@ -51,7 +51,8 @@ module RuboCop
|
|
51
51
|
# end
|
52
52
|
#
|
53
53
|
class ParameterLists < Base
|
54
|
-
|
54
|
+
exclude_limit 'Max'
|
55
|
+
exclude_limit 'MaxOptionalParameters'
|
55
56
|
|
56
57
|
MSG = 'Avoid parameter lists longer than %<max>d parameters. ' \
|
57
58
|
'[%<count>d/%<max>d]'
|
@@ -70,7 +71,9 @@ module RuboCop
|
|
70
71
|
count: optargs.count
|
71
72
|
)
|
72
73
|
|
73
|
-
add_offense(node, message: message)
|
74
|
+
add_offense(node, message: message) do
|
75
|
+
self.max_optional_parameters = optargs.count
|
76
|
+
end
|
74
77
|
end
|
75
78
|
alias on_defs on_def
|
76
79
|
|
@@ -69,6 +69,11 @@ module RuboCop
|
|
69
69
|
# @api private
|
70
70
|
def extract_first_element_over_column_limit(node, elements, max)
|
71
71
|
line = node.first_line
|
72
|
+
|
73
|
+
# If the first argument is a hash pair but the method is not parenthesized,
|
74
|
+
# the argument cannot be moved to another line because it cause a syntax error.
|
75
|
+
elements.shift if node.send_type? && !node.parenthesized? && elements.first.pair_type?
|
76
|
+
|
72
77
|
i = 0
|
73
78
|
i += 1 while within_column_limit?(elements[i], max, line)
|
74
79
|
return elements.first if i.zero?
|
@@ -4,10 +4,12 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Common functionality for checking length of code segments.
|
6
6
|
module CodeLength
|
7
|
-
|
7
|
+
extend ExcludeLimit
|
8
8
|
|
9
9
|
MSG = '%<label>s has too many lines. [%<length>d/%<max>d]'
|
10
10
|
|
11
|
+
exclude_limit 'Max'
|
12
|
+
|
11
13
|
private
|
12
14
|
|
13
15
|
def message(length, max_length)
|
@@ -6,10 +6,12 @@ module RuboCop
|
|
6
6
|
#
|
7
7
|
# This module handles measurement and reporting of complexity in methods.
|
8
8
|
module MethodComplexity
|
9
|
-
include ConfigurableMax
|
10
9
|
include IgnoredMethods
|
11
10
|
include Metrics::Utils::RepeatedCsendDiscount
|
12
11
|
extend NodePattern::Macros
|
12
|
+
extend ExcludeLimit
|
13
|
+
|
14
|
+
exclude_limit 'Max'
|
13
15
|
|
14
16
|
# Ensure cops that include `MethodComplexity` have the config
|
15
17
|
# `attr_accessor`s that `ignored_method?` needs.
|
@@ -71,11 +71,7 @@ module RuboCop
|
|
71
71
|
add_offense(range, message: message) do |corrector|
|
72
72
|
corrector.replace(range, preferred_name)
|
73
73
|
|
74
|
-
node.body
|
75
|
-
next unless var.children.first == offending_name
|
76
|
-
|
77
|
-
corrector.replace(var, preferred_name)
|
78
|
-
end
|
74
|
+
correct_node(corrector, node.body, offending_name, preferred_name)
|
79
75
|
end
|
80
76
|
end
|
81
77
|
|
@@ -86,6 +82,43 @@ module RuboCop
|
|
86
82
|
variable.loc.expression
|
87
83
|
end
|
88
84
|
|
85
|
+
def variable_name_matches?(node, name)
|
86
|
+
if node.masgn_type?
|
87
|
+
node.each_descendant(:lvasgn).any? do |lvasgn_node|
|
88
|
+
variable_name_matches?(lvasgn_node, name)
|
89
|
+
end
|
90
|
+
else
|
91
|
+
node.children.first == name
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def correct_node(corrector, node, offending_name, preferred_name)
|
96
|
+
return unless node
|
97
|
+
|
98
|
+
node.each_node(:lvar, :lvasgn, :masgn) do |child_node|
|
99
|
+
next unless variable_name_matches?(child_node, offending_name)
|
100
|
+
|
101
|
+
corrector.replace(child_node, preferred_name) if child_node.lvar_type?
|
102
|
+
|
103
|
+
if child_node.masgn_type? || child_node.lvasgn_type?
|
104
|
+
correct_reassignment(corrector, child_node, offending_name, preferred_name)
|
105
|
+
break
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# If the exception variable is reassigned, that assignment needs to be corrected.
|
111
|
+
# Further `lvar` nodes will not be corrected though since they now refer to a
|
112
|
+
# different variable.
|
113
|
+
def correct_reassignment(corrector, node, offending_name, preferred_name)
|
114
|
+
if node.lvasgn_type?
|
115
|
+
correct_node(corrector, node.child_nodes.first, offending_name, preferred_name)
|
116
|
+
elsif node.masgn_type?
|
117
|
+
# With multiple assign, the assignments are in an array as the last child
|
118
|
+
correct_node(corrector, node.children.last, offending_name, preferred_name)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
89
122
|
def preferred_name(variable_name)
|
90
123
|
preferred_name = cop_config.fetch('PreferredName', 'e')
|
91
124
|
if variable_name.to_s.start_with?('_')
|
data/lib/rubocop/cop/severity.rb
CHANGED
@@ -6,10 +6,10 @@ module RuboCop
|
|
6
6
|
class Severity
|
7
7
|
include Comparable
|
8
8
|
|
9
|
-
NAMES = %i[refactor convention warning error fatal].freeze
|
9
|
+
NAMES = %i[info refactor convention warning error fatal].freeze
|
10
10
|
|
11
11
|
# @api private
|
12
|
-
CODE_TABLE = { R: :refactor, C: :convention,
|
12
|
+
CODE_TABLE = { I: :info, R: :refactor, C: :convention,
|
13
13
|
W: :warning, E: :error, F: :fatal }.freeze
|
14
14
|
|
15
15
|
# @api public
|
@@ -18,7 +18,7 @@ module RuboCop
|
|
18
18
|
#
|
19
19
|
# @return [Symbol]
|
20
20
|
# severity.
|
21
|
-
# any of `:refactor`, `:convention`, `:warning`, `:error` or `:fatal`.
|
21
|
+
# any of `:info`, `:refactor`, `:convention`, `:warning`, `:error` or `:fatal`.
|
22
22
|
attr_reader :name
|
23
23
|
|
24
24
|
def self.name_from_code(code)
|