rubocop 0.65.0 → 0.66.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 +3 -3
- data/config/default.yml +53 -4
- data/lib/rubocop.rb +4 -5
- data/lib/rubocop/cli.rb +1 -1
- data/lib/rubocop/config.rb +1 -1
- data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +3 -5
- data/lib/rubocop/cop/layout/class_structure.rb +59 -28
- data/lib/rubocop/cop/layout/extra_spacing.rb +18 -0
- data/lib/rubocop/cop/layout/indentation_width.rb +25 -5
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +33 -17
- data/lib/rubocop/cop/lint/deprecated_class_methods.rb +30 -11
- data/lib/rubocop/cop/lint/else_layout.rb +1 -0
- data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
- data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +38 -0
- data/lib/rubocop/cop/lint/shadowed_exception.rb +14 -1
- data/lib/rubocop/cop/lint/to_json.rb +38 -0
- data/lib/rubocop/cop/lint/void.rb +1 -1
- data/lib/rubocop/cop/message_annotator.rb +4 -4
- data/lib/rubocop/cop/metrics/abc_size.rb +1 -0
- data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +31 -9
- data/lib/rubocop/cop/mixin/frozen_string_literal.rb +1 -1
- data/lib/rubocop/cop/mixin/integer_node.rb +1 -1
- data/lib/rubocop/cop/mixin/method_preference.rb +2 -1
- data/lib/rubocop/cop/naming/constant_name.rb +6 -1
- data/lib/rubocop/cop/naming/predicate_name.rb +6 -0
- data/lib/rubocop/cop/rails/link_to_blank.rb +1 -1
- data/lib/rubocop/cop/rails/output.rb +18 -1
- data/lib/rubocop/cop/rails/reflection_class_name.rb +1 -1
- data/lib/rubocop/cop/rails/time_zone.rb +10 -0
- data/lib/rubocop/cop/rails/validation.rb +3 -2
- data/lib/rubocop/cop/style/block_delimiters.rb +30 -1
- data/lib/rubocop/cop/style/conditional_assignment.rb +3 -1
- data/lib/rubocop/cop/style/constant_visibility.rb +66 -0
- data/lib/rubocop/cop/style/identical_conditional_branches.rb +8 -12
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +16 -4
- data/lib/rubocop/cop/style/numeric_literals.rb +16 -7
- data/lib/rubocop/cop/style/option_hash.rb +5 -0
- data/lib/rubocop/cop/style/redundant_freeze.rb +13 -1
- data/lib/rubocop/cop/style/redundant_self.rb +3 -1
- data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
- data/lib/rubocop/cop/style/symbol_array.rb +9 -1
- data/lib/rubocop/cop/style/trivial_accessors.rb +5 -0
- data/lib/rubocop/cop/style/word_array.rb +0 -4
- data/lib/rubocop/cop/util.rb +4 -0
- data/lib/rubocop/core_ext/string.rb +47 -0
- data/lib/rubocop/node_pattern.rb +76 -55
- data/lib/rubocop/processed_source.rb +2 -2
- data/lib/rubocop/result_cache.rb +4 -4
- data/lib/rubocop/rspec/cop_helper.rb +5 -0
- data/lib/rubocop/rspec/expect_offense.rb +5 -5
- data/lib/rubocop/runner.rb +6 -13
- data/lib/rubocop/version.rb +1 -1
- metadata +15 -19
@@ -18,7 +18,7 @@ module RuboCop
|
|
18
18
|
MSG = 'Specify a `:rel` option containing noopener.'.freeze
|
19
19
|
|
20
20
|
def_node_matcher :blank_target?, <<-PATTERN
|
21
|
-
(pair {(sym :target) (str "target")} (str "_blank"))
|
21
|
+
(pair {(sym :target) (str "target")} {(str "_blank") (sym :_blank)})
|
22
22
|
PATTERN
|
23
23
|
|
24
24
|
def_node_matcher :includes_noopener?, <<-PATTERN
|
@@ -21,11 +21,28 @@ module RuboCop
|
|
21
21
|
(send nil? {:ap :p :pp :pretty_print :print :puts} ...)
|
22
22
|
PATTERN
|
23
23
|
|
24
|
+
def_node_matcher :io_output?, <<-PATTERN
|
25
|
+
(send
|
26
|
+
{
|
27
|
+
(gvar #match_gvar?)
|
28
|
+
{(const nil? :STDOUT) (const nil? :STDERR)}
|
29
|
+
}
|
30
|
+
{:binwrite :syswrite :write :write_nonblock}
|
31
|
+
...)
|
32
|
+
PATTERN
|
33
|
+
|
24
34
|
def on_send(node)
|
25
|
-
return unless output?(node)
|
35
|
+
return unless (output?(node) || io_output?(node)) &&
|
36
|
+
node.arguments?
|
26
37
|
|
27
38
|
add_offense(node, location: :selector)
|
28
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def match_gvar?(sym)
|
44
|
+
%i[$stdout $stderr].include?(sym)
|
45
|
+
end
|
29
46
|
end
|
30
47
|
end
|
31
48
|
end
|
@@ -78,6 +78,16 @@ module RuboCop
|
|
78
78
|
check_time_node(klass, node.parent) if TIMECLASS.include?(klass)
|
79
79
|
end
|
80
80
|
|
81
|
+
def autocorrect(node)
|
82
|
+
lambda do |corrector|
|
83
|
+
if acceptable?
|
84
|
+
corrector.insert_after(node.source_range, '.in_time_zone')
|
85
|
+
else
|
86
|
+
corrector.insert_after(node.children[0].source_range, '.zone')
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
81
91
|
private
|
82
92
|
|
83
93
|
def check_time_node(klass, node)
|
@@ -87,8 +87,9 @@ module RuboCop
|
|
87
87
|
"#{validate_type}: #{braced_options(last_argument)}"
|
88
88
|
)
|
89
89
|
else
|
90
|
-
|
91
|
-
|
90
|
+
range = last_argument.source_range
|
91
|
+
|
92
|
+
corrector.insert_after(range, ", #{validate_type}: true")
|
92
93
|
end
|
93
94
|
end
|
94
95
|
|
@@ -60,6 +60,30 @@ module RuboCop
|
|
60
60
|
# x
|
61
61
|
# }.inspect
|
62
62
|
#
|
63
|
+
# # The AllowBracesOnProceduralOneLiners option is ignored unless the
|
64
|
+
# # EnforcedStyle is set to `semantic`. If so:
|
65
|
+
#
|
66
|
+
# # If the AllowBracesOnProceduralOneLiners option is unspecified, or
|
67
|
+
# # set to `false` or any other falsey value, then semantic purity is
|
68
|
+
# # maintained, so one-line procedural blocks must use do-end, not
|
69
|
+
# # braces.
|
70
|
+
#
|
71
|
+
# # bad
|
72
|
+
# collection.each { |element| puts element }
|
73
|
+
#
|
74
|
+
# # good
|
75
|
+
# collection.each do |element| puts element end
|
76
|
+
#
|
77
|
+
# # If the AllowBracesOnProceduralOneLiners option is set to `true`, or
|
78
|
+
# # any other truthy value, then one-line procedural blocks may use
|
79
|
+
# # either style. (There is no setting for requiring braces on them.)
|
80
|
+
#
|
81
|
+
# # good
|
82
|
+
# collection.each { |element| puts element }
|
83
|
+
#
|
84
|
+
# # also good
|
85
|
+
# collection.each do |element| puts element end
|
86
|
+
#
|
63
87
|
# @example EnforcedStyle: braces_for_chaining
|
64
88
|
# # bad
|
65
89
|
# words.each do |word|
|
@@ -216,7 +240,8 @@ module RuboCop
|
|
216
240
|
method_name = node.method_name
|
217
241
|
|
218
242
|
if node.braces?
|
219
|
-
functional_method?(method_name) || functional_block?(node)
|
243
|
+
functional_method?(method_name) || functional_block?(node) ||
|
244
|
+
(procedural_oneliners_may_have_braces? && !node.multiline?)
|
220
245
|
else
|
221
246
|
procedural_method?(method_name) || !return_value_used?(node)
|
222
247
|
end
|
@@ -250,6 +275,10 @@ module RuboCop
|
|
250
275
|
return_value_used?(node) || return_value_of_scope?(node)
|
251
276
|
end
|
252
277
|
|
278
|
+
def procedural_oneliners_may_have_braces?
|
279
|
+
cop_config['AllowBracesOnProceduralOneLiners']
|
280
|
+
end
|
281
|
+
|
253
282
|
def procedural_method?(method_name)
|
254
283
|
cop_config['ProceduralMethods'].map(&:to_sym).include?(method_name)
|
255
284
|
end
|
@@ -350,6 +350,8 @@ module RuboCop
|
|
350
350
|
end
|
351
351
|
|
352
352
|
def lhs_all_match?(branches)
|
353
|
+
return true if branches.empty?
|
354
|
+
|
353
355
|
first_lhs = lhs(branches.first)
|
354
356
|
branches.all? { |branch| lhs(branch) == first_lhs }
|
355
357
|
end
|
@@ -372,7 +374,7 @@ module RuboCop
|
|
372
374
|
def allowed_statements?(branches)
|
373
375
|
return false unless branches.all?
|
374
376
|
|
375
|
-
statements = branches.map { |branch| tail(branch) }
|
377
|
+
statements = branches.map { |branch| tail(branch) }.compact
|
376
378
|
|
377
379
|
lhs_all_match?(statements) && statements.none?(&:masgn_type?) &&
|
378
380
|
assignment_types_match?(*statements)
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks that constants defined in classes and modules have
|
7
|
+
# an explicit visibility declaration. By default, Ruby makes all class-
|
8
|
+
# and module constants public, which litters the public API of the
|
9
|
+
# class or module. Explicitly declaring a visibility makes intent more
|
10
|
+
# clear, and prevents outside actors from touching private state.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# class Foo
|
16
|
+
# BAR = 42
|
17
|
+
# BAZ = 43
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# class Foo
|
22
|
+
# BAR = 42
|
23
|
+
# private_constant :BAR
|
24
|
+
#
|
25
|
+
# BAZ = 43
|
26
|
+
# public_constant :BAZ
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
class ConstantVisibility < Cop
|
30
|
+
MSG = 'Explicitly make `%<constant_name>s` public or private using ' \
|
31
|
+
'either `#public_constant` or `#private_constant`.'.freeze
|
32
|
+
|
33
|
+
def on_casgn(node)
|
34
|
+
return unless class_or_module_scope?(node)
|
35
|
+
return if visibility_declaration?(node)
|
36
|
+
|
37
|
+
add_offense(node)
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def message(node)
|
43
|
+
_namespace, constant_name, _value = *node
|
44
|
+
|
45
|
+
format(MSG, constant_name: constant_name)
|
46
|
+
end
|
47
|
+
|
48
|
+
def class_or_module_scope?(node)
|
49
|
+
node.parent && %i[class module].include?(node.parent.type)
|
50
|
+
end
|
51
|
+
|
52
|
+
def visibility_declaration?(node)
|
53
|
+
_namespace, constant_name, _value = *node
|
54
|
+
|
55
|
+
node.parent.each_child_node(:send).any? do |child|
|
56
|
+
visibility_declaration_for?(child, constant_name)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def_node_matcher :visibility_declaration_for?, <<-PATTERN
|
61
|
+
(send nil? {:public_constant :private_constant} ({sym str} %1))
|
62
|
+
PATTERN
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -69,11 +69,6 @@ module RuboCop
|
|
69
69
|
return if node.elsif?
|
70
70
|
|
71
71
|
branches = expand_elses(node.else_branch).unshift(node.if_branch)
|
72
|
-
|
73
|
-
# return if any branch is empty. An empty branch can be an `if`
|
74
|
-
# without an `else` or a branch that contains only comments.
|
75
|
-
return if branches.any?(&:nil?)
|
76
|
-
|
77
72
|
check_branches(branches)
|
78
73
|
end
|
79
74
|
|
@@ -81,19 +76,20 @@ module RuboCop
|
|
81
76
|
return unless node.else? && node.else_branch
|
82
77
|
|
83
78
|
branches = node.when_branches.map(&:body).push(node.else_branch)
|
84
|
-
|
85
|
-
return if branches.any?(&:nil?)
|
86
|
-
|
87
79
|
check_branches(branches)
|
88
80
|
end
|
89
81
|
|
90
82
|
private
|
91
83
|
|
92
84
|
def check_branches(branches)
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
85
|
+
# return if any branch is empty. An empty branch can be an `if`
|
86
|
+
# without an `else` or a branch that contains only comments.
|
87
|
+
return if branches.any?(&:nil?)
|
88
|
+
|
89
|
+
tails = branches.map { |branch| tail(branch) }
|
90
|
+
check_expressions(tails) if tails.none?(&:nil?)
|
91
|
+
heads = branches.map { |branch| head(branch) }
|
92
|
+
check_expressions(heads) if tails.none?(&:nil?)
|
97
93
|
end
|
98
94
|
|
99
95
|
def check_expressions(expressions)
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# rubocop:disable Metrics/ClassLength
|
3
4
|
module RuboCop
|
4
5
|
module Cop
|
5
6
|
module Style
|
@@ -8,7 +9,11 @@ module RuboCop
|
|
8
9
|
#
|
9
10
|
# In the default style (require_parentheses), macro methods are ignored.
|
10
11
|
# Additional methods can be added to the `IgnoredMethods` list. This
|
11
|
-
# option is valid only in the default style.
|
12
|
+
# option is valid only in the default style. Macros can be included by
|
13
|
+
# either setting `IgnoreMacros` to false or adding specific macros to
|
14
|
+
# the `IncludedMacros` list. If a method is listed in both
|
15
|
+
# `IncludedMacros` and `IgnoredMethods`, then the latter takes
|
16
|
+
# precedence (that is, the method is ignored).
|
12
17
|
#
|
13
18
|
# In the alternative style (omit_parentheses), there are three additional
|
14
19
|
# options.
|
@@ -206,11 +211,17 @@ module RuboCop
|
|
206
211
|
end
|
207
212
|
|
208
213
|
def eligible_for_parentheses_omission?(node)
|
209
|
-
node.operator_method? || node.setter_method? ||
|
214
|
+
node.operator_method? || node.setter_method? || ignored_macro?(node)
|
210
215
|
end
|
211
216
|
|
212
|
-
def
|
213
|
-
cop_config
|
217
|
+
def included_macros_list
|
218
|
+
cop_config.fetch('IncludedMacros', []).map(&:to_sym)
|
219
|
+
end
|
220
|
+
|
221
|
+
def ignored_macro?(node)
|
222
|
+
cop_config['IgnoreMacros'] &&
|
223
|
+
node.macro? &&
|
224
|
+
!included_macros_list.include?(node.method_name)
|
214
225
|
end
|
215
226
|
|
216
227
|
def args_begin(node)
|
@@ -354,3 +365,4 @@ module RuboCop
|
|
354
365
|
end
|
355
366
|
end
|
356
367
|
end
|
368
|
+
# rubocop:enable Metrics/ClassLength
|
@@ -32,6 +32,7 @@ module RuboCop
|
|
32
32
|
|
33
33
|
MSG = 'Use underscores(_) as thousands separator and ' \
|
34
34
|
'separate every 3 digits with them.'.freeze
|
35
|
+
DELIMITER_REGEXP = /[eE.]/.freeze
|
35
36
|
|
36
37
|
def on_int(node)
|
37
38
|
check(node)
|
@@ -75,7 +76,20 @@ module RuboCop
|
|
75
76
|
end
|
76
77
|
|
77
78
|
def format_number(node)
|
78
|
-
|
79
|
+
source = node.source.gsub(/\s+/, '')
|
80
|
+
int_part, additional_part = source.split(DELIMITER_REGEXP, 2)
|
81
|
+
formatted_int = format_int_part(int_part)
|
82
|
+
delimiter = source[DELIMITER_REGEXP]
|
83
|
+
|
84
|
+
if additional_part
|
85
|
+
formatted_int + delimiter + additional_part
|
86
|
+
else
|
87
|
+
formatted_int
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# @param int_part [String]
|
92
|
+
def format_int_part(int_part)
|
79
93
|
int_part = Integer(int_part)
|
80
94
|
formatted_int = int_part
|
81
95
|
.abs
|
@@ -84,12 +98,7 @@ module RuboCop
|
|
84
98
|
.gsub(/...(?=.)/, '\&_')
|
85
99
|
.reverse
|
86
100
|
formatted_int.insert(0, '-') if int_part < 0
|
87
|
-
|
88
|
-
if float_part
|
89
|
-
format('%<int>s.%<float>s', int: formatted_int, float: float_part)
|
90
|
-
else
|
91
|
-
formatted_int
|
92
|
-
end
|
101
|
+
formatted_int
|
93
102
|
end
|
94
103
|
|
95
104
|
def min_digits
|
@@ -28,6 +28,7 @@ module RuboCop
|
|
28
28
|
|
29
29
|
def on_args(node)
|
30
30
|
return if super_used?(node)
|
31
|
+
return if whitelist.include?(node.parent.method_name.to_s)
|
31
32
|
|
32
33
|
option_hash(node) do |options|
|
33
34
|
add_offense(options)
|
@@ -36,6 +37,10 @@ module RuboCop
|
|
36
37
|
|
37
38
|
private
|
38
39
|
|
40
|
+
def whitelist
|
41
|
+
cop_config['Whitelist'] || []
|
42
|
+
end
|
43
|
+
|
39
44
|
def suspicious_name?(arg_name)
|
40
45
|
cop_config.key?('SuspiciousParamNames') &&
|
41
46
|
cop_config['SuspiciousParamNames'].include?(arg_name.to_s)
|
@@ -19,7 +19,8 @@ module RuboCop
|
|
19
19
|
|
20
20
|
def on_send(node)
|
21
21
|
return unless node.receiver && node.method?(:freeze) &&
|
22
|
-
immutable_literal?(node.receiver)
|
22
|
+
(immutable_literal?(node.receiver) ||
|
23
|
+
operation_produces_immutable_object?(node.receiver))
|
23
24
|
|
24
25
|
add_offense(node)
|
25
26
|
end
|
@@ -49,6 +50,17 @@ module RuboCop
|
|
49
50
|
node
|
50
51
|
end
|
51
52
|
end
|
53
|
+
|
54
|
+
def_node_matcher :operation_produces_immutable_object?, <<-PATTERN
|
55
|
+
{
|
56
|
+
(begin (send {float int} {:+ :- :* :** :/ :% :<<} _))
|
57
|
+
(begin (send _ {:+ :- :* :** :/ :%} {float int}))
|
58
|
+
(begin (send _ {:== :=== :!= :<= :>= :< :>} _))
|
59
|
+
(send (const nil? :ENV) :[] _)
|
60
|
+
(send _ {:count :length :size} ...)
|
61
|
+
(block (send _ {:count :length :size} ...) ...)
|
62
|
+
}
|
63
|
+
PATTERN
|
52
64
|
end
|
53
65
|
end
|
54
66
|
end
|
@@ -43,6 +43,7 @@ module RuboCop
|
|
43
43
|
# end
|
44
44
|
class RedundantSelf < Cop
|
45
45
|
MSG = 'Redundant `self` detected.'.freeze
|
46
|
+
KERNEL_METHODS = Kernel.methods(false)
|
46
47
|
|
47
48
|
def self.autocorrect_incompatible_with
|
48
49
|
[ColonMethodCall]
|
@@ -117,7 +118,8 @@ module RuboCop
|
|
117
118
|
|
118
119
|
def allowed_send_node?(node)
|
119
120
|
@allowed_send_nodes.include?(node) ||
|
120
|
-
@local_variables_scopes[node].include?(node.method_name)
|
121
|
+
@local_variables_scopes[node].include?(node.method_name) ||
|
122
|
+
KERNEL_METHODS.include?(node.method_name)
|
121
123
|
end
|
122
124
|
|
123
125
|
def regular_method_call?(node)
|
@@ -70,7 +70,15 @@ module RuboCop
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def correct_bracketed(node)
|
73
|
-
syms = node.children.map
|
73
|
+
syms = node.children.map do |c|
|
74
|
+
if c.dsym_type?
|
75
|
+
string_literal = to_string_literal(c.source)
|
76
|
+
|
77
|
+
':' + trim_string_interporation_escape_character(string_literal)
|
78
|
+
else
|
79
|
+
to_symbol_literal(c.value.to_s)
|
80
|
+
end
|
81
|
+
end
|
74
82
|
|
75
83
|
lambda do |corrector|
|
76
84
|
corrector.replace(node.source_range, "[#{syms.join(', ')}]")
|
@@ -31,6 +31,7 @@ module RuboCop
|
|
31
31
|
MSG = 'Use `attr_%<kind>s` to define trivial %<kind>s methods.'.freeze
|
32
32
|
|
33
33
|
def on_def(node)
|
34
|
+
return if top_level_node?(node)
|
34
35
|
return if in_module_or_instance_eval?(node)
|
35
36
|
return if ignore_class_methods? && node.defs_type?
|
36
37
|
|
@@ -180,6 +181,10 @@ module RuboCop
|
|
180
181
|
)
|
181
182
|
end
|
182
183
|
end
|
184
|
+
|
185
|
+
def top_level_node?(node)
|
186
|
+
node.parent.nil?
|
187
|
+
end
|
183
188
|
end
|
184
189
|
end
|
185
190
|
end
|