rubocop 1.11.0 → 1.12.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 -2
- data/config/default.yml +16 -1
- data/lib/rubocop.rb +1 -0
- data/lib/rubocop/cli/command/suggest_extensions.rb +3 -2
- data/lib/rubocop/comment_config.rb +43 -94
- data/lib/rubocop/cop/correctors/alignment_corrector.rb +3 -6
- data/lib/rubocop/cop/layout/access_modifier_indentation.rb +11 -8
- data/lib/rubocop/cop/layout/argument_alignment.rb +6 -5
- data/lib/rubocop/cop/layout/array_alignment.rb +7 -6
- data/lib/rubocop/cop/layout/assignment_indentation.rb +6 -3
- data/lib/rubocop/cop/layout/block_end_newline.rb +4 -8
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +14 -15
- data/lib/rubocop/cop/layout/comment_indentation.rb +16 -16
- data/lib/rubocop/cop/layout/else_alignment.rb +9 -6
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +6 -5
- data/lib/rubocop/cop/layout/first_array_element_indentation.rb +9 -6
- data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +22 -15
- data/lib/rubocop/cop/layout/first_parameter_indentation.rb +6 -5
- data/lib/rubocop/cop/layout/indentation_consistency.rb +9 -6
- data/lib/rubocop/cop/layout/indentation_style.rb +27 -30
- data/lib/rubocop/cop/layout/indentation_width.rb +19 -9
- data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +6 -5
- data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +6 -5
- data/lib/rubocop/cop/layout/parameter_alignment.rb +6 -5
- data/lib/rubocop/cop/lint/number_conversion.rb +7 -0
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +1 -2
- data/lib/rubocop/cop/lint/suppressed_exception.rb +44 -1
- data/lib/rubocop/cop/lint/symbol_conversion.rb +89 -2
- data/lib/rubocop/cop/mixin/alignment.rb +10 -3
- data/lib/rubocop/cop/mixin/comments_help.rb +5 -1
- data/lib/rubocop/cop/mixin/documentation_comment.rb +1 -1
- data/lib/rubocop/cop/mixin/line_length_help.rb +11 -6
- data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +3 -1
- data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +4 -3
- data/lib/rubocop/cop/mixin/preferred_delimiters.rb +1 -1
- data/lib/rubocop/cop/mixin/uncommunicative_name.rb +4 -6
- data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +4 -0
- data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +10 -0
- data/lib/rubocop/cop/registry.rb +9 -0
- data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -1
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +59 -71
- data/lib/rubocop/cop/style/bisected_attr_accessor/macro.rb +62 -0
- data/lib/rubocop/cop/style/case_like_if.rb +15 -4
- data/lib/rubocop/cop/style/class_equality_comparison.rb +2 -0
- data/lib/rubocop/cop/style/command_literal.rb +1 -1
- data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +2 -2
- data/lib/rubocop/cop/style/documentation.rb +25 -3
- data/lib/rubocop/cop/style/eval_with_location.rb +1 -1
- data/lib/rubocop/cop/style/hash_syntax.rb +16 -15
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +40 -0
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +20 -2
- data/lib/rubocop/cop/style/negated_if_else_condition.rb +15 -2
- data/lib/rubocop/cop/style/redundant_begin.rb +26 -3
- data/lib/rubocop/cop/style/redundant_return.rb +4 -0
- data/lib/rubocop/cop/style/redundant_self.rb +7 -3
- data/lib/rubocop/cop/style/regexp_literal.rb +1 -1
- data/lib/rubocop/cop/style/rescue_modifier.rb +17 -14
- data/lib/rubocop/cop/style/sole_nested_conditional.rb +16 -0
- data/lib/rubocop/cop/style/string_chars.rb +38 -0
- data/lib/rubocop/cop/style/struct_inheritance.rb +2 -0
- data/lib/rubocop/cop/style/trailing_body_on_method_definition.rb +5 -1
- data/lib/rubocop/cop/style/unless_logical_operators.rb +8 -2
- data/lib/rubocop/directive_comment.rb +64 -9
- data/lib/rubocop/ext/regexp_parser.rb +3 -6
- data/lib/rubocop/magic_comment.rb +1 -1
- data/lib/rubocop/target_finder.rb +1 -0
- data/lib/rubocop/version.rb +1 -1
- metadata +5 -3
@@ -16,7 +16,7 @@ module RuboCop
|
|
16
16
|
|
17
17
|
return false unless comment
|
18
18
|
|
19
|
-
|
19
|
+
!!DirectiveComment.new(comment).match_captures
|
20
20
|
end
|
21
21
|
|
22
22
|
def allow_uri?
|
@@ -24,9 +24,7 @@ module RuboCop
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def allowed_uri_position?(line, uri_range)
|
27
|
-
uri_range.begin < max_line_length &&
|
28
|
-
(uri_range.end == line_length(line) ||
|
29
|
-
uri_range.end == line_length(line) - 1)
|
27
|
+
uri_range.begin < max_line_length && uri_range.end == line_length(line)
|
30
28
|
end
|
31
29
|
|
32
30
|
def line_length(line)
|
@@ -40,6 +38,14 @@ module RuboCop
|
|
40
38
|
begin_position, end_position = last_uri_match.offset(0).map do |pos|
|
41
39
|
pos + indentation_difference(line)
|
42
40
|
end
|
41
|
+
|
42
|
+
# Extend the end position until the start of the next word, if any.
|
43
|
+
# This allows for URIs that are wrapped in quotes or parens to be handled properly
|
44
|
+
# while not allowing additional words to be added after the URL.
|
45
|
+
if (match = line[end_position..line_length(line)]&.match(/^\S+(?=\s|$)/))
|
46
|
+
end_position += match.offset(0).last
|
47
|
+
end
|
48
|
+
|
43
49
|
return nil if begin_position < max_line_length &&
|
44
50
|
end_position < max_line_length
|
45
51
|
|
@@ -79,8 +85,7 @@ module RuboCop
|
|
79
85
|
end
|
80
86
|
|
81
87
|
def line_length_without_directive(line)
|
82
|
-
before_comment
|
83
|
-
before_comment.rstrip.length
|
88
|
+
DirectiveComment.before_comment(line).rstrip.length
|
84
89
|
end
|
85
90
|
end
|
86
91
|
end
|
@@ -77,7 +77,9 @@ module RuboCop
|
|
77
77
|
def incorrect_style_detected(styles, first, left_parenthesis)
|
78
78
|
msg = message(base_description(left_parenthesis))
|
79
79
|
|
80
|
-
add_offense(first, message: msg) do
|
80
|
+
add_offense(first, message: msg) do |corrector|
|
81
|
+
autocorrect(corrector, first)
|
82
|
+
|
81
83
|
ambiguous_style_detected(*styles)
|
82
84
|
end
|
83
85
|
end
|
@@ -91,9 +91,10 @@ module RuboCop
|
|
91
91
|
end
|
92
92
|
|
93
93
|
def incorrect_style_detected(range, node, lhs, rhs)
|
94
|
-
add_offense(range,
|
95
|
-
|
96
|
-
|
94
|
+
add_offense(range, message: message(node, lhs, rhs)) do |corrector|
|
95
|
+
autocorrect(corrector, range)
|
96
|
+
|
97
|
+
if supported_styles.size > 2 || offending_range(node, lhs, rhs, alternative_style)
|
97
98
|
unrecognized_style_detected
|
98
99
|
else
|
99
100
|
opposite_style_detected
|
@@ -53,12 +53,10 @@ module RuboCop
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def name_type(node)
|
56
|
-
@name_type ||=
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
61
|
-
end
|
56
|
+
@name_type ||= case node.type
|
57
|
+
when :block then 'block parameter'
|
58
|
+
when :def, :defs then 'method parameter'
|
59
|
+
end
|
62
60
|
end
|
63
61
|
|
64
62
|
def num_offense(node, range)
|
@@ -139,6 +139,10 @@ module RuboCop
|
|
139
139
|
# define_method(:foo) do
|
140
140
|
# @_foo ||= calculate_expensive_thing
|
141
141
|
# end
|
142
|
+
#
|
143
|
+
# This cop relies on the pattern `@instance_var ||= ...`,
|
144
|
+
# but this is sometimes used for other purposes than memoization
|
145
|
+
# so this cop is considered unsafe.
|
142
146
|
class MemoizedInstanceVariableName < Base
|
143
147
|
include ConfigurableEnforcedStyle
|
144
148
|
|
@@ -9,6 +9,11 @@ module RuboCop
|
|
9
9
|
# The `PreferredName` config option takes a `String`. It represents
|
10
10
|
# the required name of the variable. Its default is `e`.
|
11
11
|
#
|
12
|
+
# NOTE: This cop does not consider nested rescues because it cannot
|
13
|
+
# guarantee that the variable from the outer rescue is not used within
|
14
|
+
# the inner rescue (in which case, changing the inner variable would
|
15
|
+
# shadow the outer variable).
|
16
|
+
#
|
12
17
|
# @example PreferredName: e (default)
|
13
18
|
# # bad
|
14
19
|
# begin
|
@@ -62,6 +67,11 @@ module RuboCop
|
|
62
67
|
offending_name = variable_name(node)
|
63
68
|
return unless offending_name
|
64
69
|
|
70
|
+
# Handle nested rescues by only requiring the outer one to use the
|
71
|
+
# configured variable name, so that nested rescues don't use the same
|
72
|
+
# variable.
|
73
|
+
return if node.each_ancestor(:resbody).any?
|
74
|
+
|
65
75
|
preferred_name = preferred_name(offending_name)
|
66
76
|
return if preferred_name.to_sym == offending_name
|
67
77
|
|
data/lib/rubocop/cop/registry.rb
CHANGED
@@ -64,6 +64,11 @@ module RuboCop
|
|
64
64
|
with(without_department.values.flatten)
|
65
65
|
end
|
66
66
|
|
67
|
+
# @return [Boolean] Checks if given name is department
|
68
|
+
def department?(name)
|
69
|
+
departments.include? name.to_sym
|
70
|
+
end
|
71
|
+
|
67
72
|
def contains_cop_matching?(names)
|
68
73
|
cops.any? { |cop| cop.match?(names) }
|
69
74
|
end
|
@@ -179,6 +184,10 @@ module RuboCop
|
|
179
184
|
cops.map(&:cop_name)
|
180
185
|
end
|
181
186
|
|
187
|
+
def names_for_department(department)
|
188
|
+
cops.select { |cop| cop.department == department.to_sym }.map(&:cop_name)
|
189
|
+
end
|
190
|
+
|
182
191
|
def ==(other)
|
183
192
|
cops == other.cops
|
184
193
|
end
|
@@ -79,7 +79,7 @@ module RuboCop
|
|
79
79
|
|
80
80
|
# @!method access_modifier_with_symbol?(node)
|
81
81
|
def_node_matcher :access_modifier_with_symbol?, <<~PATTERN
|
82
|
-
(send nil? {:private :protected :public} (sym _))
|
82
|
+
(send nil? {:private :protected :public :module_function} (sym _))
|
83
83
|
PATTERN
|
84
84
|
|
85
85
|
def on_send(node)
|
@@ -19,47 +19,61 @@ module RuboCop
|
|
19
19
|
# end
|
20
20
|
#
|
21
21
|
class BisectedAttrAccessor < Base
|
22
|
-
|
22
|
+
require_relative 'bisected_attr_accessor/macro'
|
23
|
+
|
24
|
+
include RangeHelp
|
23
25
|
extend AutoCorrector
|
24
26
|
|
25
27
|
MSG = 'Combine both accessors into `attr_accessor %<name>s`.'
|
26
28
|
|
29
|
+
def on_new_investigation
|
30
|
+
@macros_to_rewrite = {}
|
31
|
+
end
|
32
|
+
|
27
33
|
def on_class(class_node)
|
28
|
-
|
29
|
-
|
30
|
-
|
34
|
+
@macros_to_rewrite[class_node] = Set.new
|
35
|
+
|
36
|
+
find_macros(class_node.body).each do |_visibility, macros|
|
37
|
+
bisected = find_bisection(macros)
|
38
|
+
next unless bisected.any?
|
31
39
|
|
32
|
-
|
33
|
-
|
40
|
+
macros.each do |macro|
|
41
|
+
attrs = macro.bisect(*bisected)
|
42
|
+
next if attrs.none?
|
43
|
+
|
44
|
+
@macros_to_rewrite[class_node] << macro
|
45
|
+
attrs.each { |attr| register_offense(attr) }
|
34
46
|
end
|
35
47
|
end
|
36
48
|
end
|
37
49
|
alias on_sclass on_class
|
38
50
|
alias on_module on_class
|
39
51
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
(reader_names ||= Set.new).add(name)
|
52
|
+
# Each offending macro is captured and registered in `on_class` but correction
|
53
|
+
# happens in `after_class` because a macro might have multiple attributes
|
54
|
+
# rewritten from it
|
55
|
+
def after_class(class_node)
|
56
|
+
@macros_to_rewrite[class_node].each do |macro|
|
57
|
+
node = macro.node
|
58
|
+
range = range_by_whole_lines(node.loc.expression, include_final_newline: true)
|
59
|
+
|
60
|
+
correct(range) do |corrector|
|
61
|
+
if macro.writer?
|
62
|
+
correct_writer(corrector, macro, node, range)
|
52
63
|
else
|
53
|
-
(
|
64
|
+
correct_reader(corrector, macro, node, range)
|
54
65
|
end
|
55
66
|
end
|
56
67
|
end
|
57
|
-
|
58
|
-
[reader_names, writer_names]
|
59
68
|
end
|
69
|
+
alias after_sclass after_class
|
70
|
+
alias after_module after_class
|
60
71
|
|
61
|
-
|
62
|
-
|
72
|
+
private
|
73
|
+
|
74
|
+
def find_macros(class_def)
|
75
|
+
# Find all the macros (`attr_reader`, `attr_writer`, etc.) in the class body
|
76
|
+
# and turn them into `Macro` objects so that they can be processed.
|
63
77
|
return [] if !class_def || class_def.def_type?
|
64
78
|
|
65
79
|
send_nodes =
|
@@ -69,66 +83,40 @@ module RuboCop
|
|
69
83
|
class_def.each_child_node(:send)
|
70
84
|
end
|
71
85
|
|
72
|
-
send_nodes.
|
86
|
+
send_nodes.each_with_object([]) do |node, macros|
|
87
|
+
macros << Macro.new(node) if Macro.macro?(node)
|
88
|
+
end.group_by(&:visibility)
|
73
89
|
end
|
74
90
|
|
75
|
-
def
|
76
|
-
|
77
|
-
|
78
|
-
|
91
|
+
def find_bisection(macros)
|
92
|
+
# Find which attributes are defined in both readers and writers so that they
|
93
|
+
# can be replaced with accessors.
|
94
|
+
readers, writers = macros.partition(&:reader?)
|
95
|
+
readers.flat_map(&:attr_names) & writers.flat_map(&:attr_names)
|
79
96
|
end
|
80
97
|
|
81
|
-
def
|
82
|
-
|
98
|
+
def register_offense(attr)
|
99
|
+
add_offense(attr, message: format(MSG, name: attr.source))
|
83
100
|
end
|
84
101
|
|
85
|
-
def
|
86
|
-
|
87
|
-
end
|
102
|
+
def correct_reader(corrector, macro, node, range)
|
103
|
+
attr_accessor = "attr_accessor #{macro.bisected_names.join(', ')}\n"
|
88
104
|
|
89
|
-
|
90
|
-
|
91
|
-
name = arg_node.source
|
92
|
-
|
93
|
-
next unless (attr_reader?(macro) && writer_names.include?(name)) ||
|
94
|
-
(attr_writer?(macro) && reader_names.include?(name))
|
95
|
-
|
96
|
-
add_offense(arg_node, message: format(MSG, name: name)) do |corrector|
|
97
|
-
macro = arg_node.parent
|
98
|
-
|
99
|
-
corrector.replace(macro, replacement(macro, arg_node))
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
def replacement(macro, node)
|
105
|
-
class_node = macro.each_ancestor(:class, :sclass, :module).first
|
106
|
-
reader_names, writer_names = accessor_names(class_node, node_visibility(macro))
|
107
|
-
|
108
|
-
rest_args = rest_args(macro.arguments, reader_names, writer_names)
|
109
|
-
|
110
|
-
if attr_reader?(macro)
|
111
|
-
attr_reader_replacement(macro, node, rest_args)
|
112
|
-
elsif rest_args.empty?
|
113
|
-
''
|
105
|
+
if macro.all_bisected?
|
106
|
+
corrector.replace(range, "#{indent(node)}#{attr_accessor}")
|
114
107
|
else
|
115
|
-
"#{
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
def rest_args(args, reader_names, writer_names)
|
120
|
-
args.reject do |arg|
|
121
|
-
name = arg.source
|
122
|
-
reader_names.include?(name) && writer_names.include?(name)
|
108
|
+
correction = "#{indent(node)}attr_reader #{macro.rest.join(', ')}"
|
109
|
+
corrector.insert_before(node, attr_accessor)
|
110
|
+
corrector.replace(node, correction)
|
123
111
|
end
|
124
112
|
end
|
125
113
|
|
126
|
-
def
|
127
|
-
if
|
128
|
-
|
114
|
+
def correct_writer(corrector, macro, node, range)
|
115
|
+
if macro.all_bisected?
|
116
|
+
corrector.remove(range)
|
129
117
|
else
|
130
|
-
"
|
131
|
-
|
118
|
+
correction = "attr_writer #{macro.rest.join(', ')}"
|
119
|
+
corrector.replace(node, correction)
|
132
120
|
end
|
133
121
|
end
|
134
122
|
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
class BisectedAttrAccessor
|
7
|
+
# Representation of an `attr_reader`, `attr_writer` or `attr` macro
|
8
|
+
# for use by `Style/BisectedAttrAccessor`.
|
9
|
+
# @api private
|
10
|
+
class Macro
|
11
|
+
include VisibilityHelp
|
12
|
+
|
13
|
+
attr_reader :node, :attrs, :bisection
|
14
|
+
|
15
|
+
def self.macro?(node)
|
16
|
+
node.method?(:attr_reader) || node.method?(:attr_writer) || node.method?(:attr)
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(node)
|
20
|
+
@node = node
|
21
|
+
@attrs = node.arguments.map do |attr|
|
22
|
+
[attr.source, attr]
|
23
|
+
end.to_h
|
24
|
+
@bisection = []
|
25
|
+
end
|
26
|
+
|
27
|
+
def bisect(*names)
|
28
|
+
@bisection = attrs.slice(*names).values
|
29
|
+
end
|
30
|
+
|
31
|
+
def attr_names
|
32
|
+
@attr_names ||= attrs.keys
|
33
|
+
end
|
34
|
+
|
35
|
+
def bisected_names
|
36
|
+
bisection.map(&:source)
|
37
|
+
end
|
38
|
+
|
39
|
+
def visibility
|
40
|
+
@visibility ||= node_visibility(node)
|
41
|
+
end
|
42
|
+
|
43
|
+
def reader?
|
44
|
+
node.method?(:attr_reader) || node.method?(:attr)
|
45
|
+
end
|
46
|
+
|
47
|
+
def writer?
|
48
|
+
node.method?(:attr_writer)
|
49
|
+
end
|
50
|
+
|
51
|
+
def all_bisected?
|
52
|
+
rest.none?
|
53
|
+
end
|
54
|
+
|
55
|
+
def rest
|
56
|
+
@rest ||= attr_names - bisected_names
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -105,8 +105,7 @@ module RuboCop
|
|
105
105
|
when :===
|
106
106
|
node.arguments.first
|
107
107
|
when :include?, :cover?
|
108
|
-
|
109
|
-
node.arguments.first if receiver.range_type?
|
108
|
+
find_target_in_include_or_cover_node(node)
|
110
109
|
when :match, :match?, :=~
|
111
110
|
find_target_in_match_node(node)
|
112
111
|
end
|
@@ -124,6 +123,12 @@ module RuboCop
|
|
124
123
|
end
|
125
124
|
end
|
126
125
|
|
126
|
+
def find_target_in_include_or_cover_node(node)
|
127
|
+
return unless (receiver = node.receiver)
|
128
|
+
|
129
|
+
node.first_argument if deparenthesize(receiver).range_type?
|
130
|
+
end
|
131
|
+
|
127
132
|
def find_target_in_match_node(node)
|
128
133
|
argument = node.arguments.first
|
129
134
|
receiver = node.receiver
|
@@ -167,8 +172,7 @@ module RuboCop
|
|
167
172
|
lhs, _method, rhs = *node
|
168
173
|
lhs if rhs == target
|
169
174
|
when :include?, :cover?
|
170
|
-
|
171
|
-
receiver if receiver.range_type? && node.arguments.first == target
|
175
|
+
condition_from_include_or_cover_node(node, target)
|
172
176
|
end
|
173
177
|
end
|
174
178
|
# rubocop:enable Metrics/CyclomaticComplexity
|
@@ -184,6 +188,13 @@ module RuboCop
|
|
184
188
|
condition_from_binary_op(lhs, rhs, target)
|
185
189
|
end
|
186
190
|
|
191
|
+
def condition_from_include_or_cover_node(node, target)
|
192
|
+
return unless (receiver = node.receiver)
|
193
|
+
|
194
|
+
receiver = deparenthesize(receiver)
|
195
|
+
receiver if receiver.range_type? && node.first_argument == target
|
196
|
+
end
|
197
|
+
|
187
198
|
def condition_from_binary_op(lhs, rhs, target)
|
188
199
|
lhs = deparenthesize(lhs)
|
189
200
|
rhs = deparenthesize(rhs)
|