rubocop 0.86.0 → 0.87.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 +1 -1
- data/config/default.yml +46 -4
- data/lib/rubocop.rb +8 -1
- data/lib/rubocop/cli.rb +0 -2
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +40 -5
- data/lib/rubocop/cli/command/show_cops.rb +1 -1
- data/lib/rubocop/config_loader.rb +21 -62
- data/lib/rubocop/config_obsoletion.rb +0 -1
- data/lib/rubocop/cop/autocorrect_logic.rb +13 -23
- data/lib/rubocop/cop/base.rb +399 -0
- data/lib/rubocop/cop/bundler/insecure_protocol_source.rb +10 -20
- data/lib/rubocop/cop/commissioner.rb +48 -50
- data/lib/rubocop/cop/cop.rb +85 -236
- data/lib/rubocop/cop/corrector.rb +38 -115
- data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +1 -1
- data/lib/rubocop/cop/generator.rb +1 -1
- data/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +11 -14
- data/lib/rubocop/cop/layout/case_indentation.rb +18 -19
- data/lib/rubocop/cop/layout/class_structure.rb +2 -37
- data/lib/rubocop/cop/layout/empty_lines_around_attribute_accessor.rb +1 -8
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +4 -0
- data/lib/rubocop/cop/layout/hash_alignment.rb +1 -2
- data/lib/rubocop/cop/layout/multiline_block_layout.rb +0 -1
- data/lib/rubocop/cop/layout/space_around_block_parameters.rb +19 -25
- data/lib/rubocop/cop/legacy/corrections_proxy.rb +49 -0
- data/lib/rubocop/cop/legacy/corrector.rb +29 -0
- data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +4 -4
- data/lib/rubocop/cop/lint/interpolation_check.rb +13 -0
- data/lib/rubocop/cop/lint/nested_method_definition.rb +1 -1
- data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +2 -2
- data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +8 -3
- data/lib/rubocop/cop/lint/rand_one.rb +1 -1
- data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +27 -23
- data/lib/rubocop/cop/lint/redundant_splat_expansion.rb +2 -2
- data/lib/rubocop/cop/lint/safe_navigation_with_empty.rb +8 -0
- data/lib/rubocop/cop/lint/syntax.rb +11 -26
- data/lib/rubocop/cop/lint/unused_method_argument.rb +1 -1
- data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
- data/lib/rubocop/cop/metrics/block_length.rb +22 -0
- data/lib/rubocop/cop/metrics/class_length.rb +25 -2
- data/lib/rubocop/cop/metrics/method_length.rb +23 -0
- data/lib/rubocop/cop/metrics/module_length.rb +25 -2
- data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +129 -0
- data/lib/rubocop/cop/mixin/allowed_methods.rb +19 -0
- data/lib/rubocop/cop/mixin/auto_corrector.rb +12 -0
- data/lib/rubocop/cop/mixin/code_length.rb +4 -0
- data/lib/rubocop/cop/mixin/configurable_formatting.rb +1 -1
- data/lib/rubocop/cop/mixin/enforce_superclass.rb +3 -1
- data/lib/rubocop/cop/mixin/nil_methods.rb +3 -5
- data/lib/rubocop/cop/mixin/ordered_gem_node.rb +6 -1
- data/lib/rubocop/cop/mixin/surrounding_space.rb +7 -2
- data/lib/rubocop/cop/mixin/too_many_lines.rb +3 -13
- data/lib/rubocop/cop/mixin/uncommunicative_name.rb +4 -2
- data/lib/rubocop/cop/mixin/visibility_help.rb +50 -0
- data/lib/rubocop/cop/naming/ascii_identifiers.rb +27 -4
- data/lib/rubocop/cop/naming/binary_operator_parameter_name.rb +2 -2
- data/lib/rubocop/cop/naming/method_name.rb +1 -1
- data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
- data/lib/rubocop/cop/naming/predicate_name.rb +3 -5
- data/lib/rubocop/cop/naming/variable_name.rb +1 -1
- data/lib/rubocop/cop/naming/variable_number.rb +1 -1
- data/lib/rubocop/cop/offense.rb +16 -2
- data/lib/rubocop/cop/style/accessor_grouping.rb +140 -0
- data/lib/rubocop/cop/style/bisected_attr_accessor.rb +145 -0
- data/lib/rubocop/cop/style/class_vars.rb +21 -0
- data/lib/rubocop/cop/style/date_time.rb +1 -1
- data/lib/rubocop/cop/style/dir.rb +2 -2
- data/lib/rubocop/cop/style/empty_literal.rb +5 -5
- data/lib/rubocop/cop/style/expand_path_arguments.rb +2 -2
- data/lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb +12 -0
- data/lib/rubocop/cop/style/multiline_block_chain.rb +10 -1
- data/lib/rubocop/cop/style/mutable_constant.rb +4 -4
- data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -5
- data/lib/rubocop/cop/style/proc.rb +1 -1
- data/lib/rubocop/cop/style/random_with_offset.rb +4 -10
- data/lib/rubocop/cop/style/redundant_assignment.rb +117 -0
- data/lib/rubocop/cop/style/redundant_exception.rb +14 -10
- data/lib/rubocop/cop/style/redundant_fetch_block.rb +26 -7
- data/lib/rubocop/cop/style/redundant_freeze.rb +1 -1
- data/lib/rubocop/cop/style/redundant_parentheses.rb +7 -1
- data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +2 -1
- data/lib/rubocop/cop/style/redundant_regexp_escape.rb +2 -2
- data/lib/rubocop/cop/style/rescue_standard_error.rb +1 -1
- data/lib/rubocop/cop/style/signal_exception.rb +1 -1
- data/lib/rubocop/cop/style/stderr_puts.rb +1 -1
- data/lib/rubocop/cop/style/struct_inheritance.rb +2 -2
- data/lib/rubocop/cop/style/symbol_proc.rb +1 -1
- data/lib/rubocop/cop/style/trivial_accessors.rb +8 -7
- data/lib/rubocop/cop/style/zero_length_predicate.rb +2 -2
- data/lib/rubocop/cop/team.rb +97 -81
- data/lib/rubocop/cop/utils/format_string.rb +1 -2
- data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
- data/lib/rubocop/name_similarity.rb +1 -3
- data/lib/rubocop/options.rb +15 -8
- data/lib/rubocop/rake_task.rb +6 -9
- data/lib/rubocop/rspec/cop_helper.rb +4 -4
- data/lib/rubocop/rspec/expect_offense.rb +22 -17
- data/lib/rubocop/rspec/shared_contexts.rb +7 -7
- data/lib/rubocop/runner.rb +31 -29
- data/lib/rubocop/target_ruby.rb +1 -1
- data/lib/rubocop/version.rb +1 -1
- metadata +16 -7
- data/lib/rubocop/cop/mixin/classish_length.rb +0 -37
@@ -18,7 +18,7 @@ module RuboCop
|
|
18
18
|
'name its argument `other`.'
|
19
19
|
|
20
20
|
OP_LIKE_METHODS = %i[eql? equal?].freeze
|
21
|
-
|
21
|
+
EXCLUDED = %i[+@ -@ [] []= << === `].freeze
|
22
22
|
|
23
23
|
def_node_matcher :op_method_candidate?, <<~PATTERN
|
24
24
|
(def [#op_method? $_] (args $(arg [!:other !:_other])) _)
|
@@ -33,7 +33,7 @@ module RuboCop
|
|
33
33
|
private
|
34
34
|
|
35
35
|
def op_method?(name)
|
36
|
-
return false if
|
36
|
+
return false if EXCLUDED.include?(name)
|
37
37
|
|
38
38
|
!/\A\w/.match?(name) || OP_LIKE_METHODS.include?(name)
|
39
39
|
end
|
@@ -28,6 +28,8 @@ module RuboCop
|
|
28
28
|
# def value?
|
29
29
|
# end
|
30
30
|
class PredicateName < Cop
|
31
|
+
include AllowedMethods
|
32
|
+
|
31
33
|
def_node_matcher :dynamic_method_define, <<~PATTERN
|
32
34
|
(send nil? #method_definition_macros
|
33
35
|
(sym $_)
|
@@ -70,7 +72,7 @@ module RuboCop
|
|
70
72
|
!method_name.match?(/^#{prefix}[^0-9]/) ||
|
71
73
|
method_name == expected_name(method_name, prefix) ||
|
72
74
|
method_name.end_with?('=') ||
|
73
|
-
|
75
|
+
allowed_method?(method_name)
|
74
76
|
end
|
75
77
|
|
76
78
|
def expected_name(method_name, prefix)
|
@@ -95,10 +97,6 @@ module RuboCop
|
|
95
97
|
cop_config['NamePrefix']
|
96
98
|
end
|
97
99
|
|
98
|
-
def allowed_methods
|
99
|
-
cop_config['AllowedMethods']
|
100
|
-
end
|
101
|
-
|
102
100
|
def method_definition_macros(macro_name)
|
103
101
|
cop_config['MethodDefinitionMacros'].include?(macro_name.to_s)
|
104
102
|
end
|
data/lib/rubocop/cop/offense.rb
CHANGED
@@ -54,14 +54,28 @@ module RuboCop
|
|
54
54
|
# @api private
|
55
55
|
attr_reader :status
|
56
56
|
|
57
|
+
# @api public
|
58
|
+
#
|
59
|
+
# @!attribute [r] corrector
|
60
|
+
#
|
61
|
+
# @return [Corrector | nil]
|
62
|
+
# the autocorrection for this offense, or `nil` when not available
|
63
|
+
attr_reader :corrector
|
64
|
+
|
65
|
+
PseudoSourceRange = Struct.new(:line, :column, :source_line, :begin_pos,
|
66
|
+
:end_pos)
|
67
|
+
|
68
|
+
NO_LOCATION = PseudoSourceRange.new(1, 0, '', 0, 1).freeze
|
69
|
+
|
57
70
|
# @api private
|
58
|
-
def initialize(severity, location, message, cop_name,
|
59
|
-
status = :uncorrected)
|
71
|
+
def initialize(severity, location, message, cop_name, # rubocop:disable Metrics/ParameterLists
|
72
|
+
status = :uncorrected, corrector = nil)
|
60
73
|
@severity = RuboCop::Cop::Severity.new(severity)
|
61
74
|
@location = location
|
62
75
|
@message = message.freeze
|
63
76
|
@cop_name = cop_name.freeze
|
64
77
|
@status = status
|
78
|
+
@corrector = corrector
|
65
79
|
freeze
|
66
80
|
end
|
67
81
|
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Style
|
6
|
+
# This cop checks for grouping of accessors in `class` and `module` bodies.
|
7
|
+
# By default it enforces accessors to be placed in grouped declarations,
|
8
|
+
# but it can be configured to enforce separating them in multiple declarations.
|
9
|
+
#
|
10
|
+
# @example EnforcedStyle: grouped (default)
|
11
|
+
# # bad
|
12
|
+
# class Foo
|
13
|
+
# attr_reader :bar
|
14
|
+
# attr_reader :baz
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# class Foo
|
19
|
+
# attr_reader :bar, :baz
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# @example EnforcedStyle: separated
|
23
|
+
# # bad
|
24
|
+
# class Foo
|
25
|
+
# attr_reader :bar, :baz
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# # good
|
29
|
+
# class Foo
|
30
|
+
# attr_reader :bar
|
31
|
+
# attr_reader :baz
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
class AccessorGrouping < Cop
|
35
|
+
include ConfigurableEnforcedStyle
|
36
|
+
include VisibilityHelp
|
37
|
+
|
38
|
+
GROUPED_MSG = 'Group together all `%<accessor>s` attributes.'
|
39
|
+
SEPARATED_MSG = 'Use one attribute per `%<accessor>s`.'
|
40
|
+
|
41
|
+
ACCESSOR_METHODS = %i[attr_reader attr_writer attr_accessor attr].freeze
|
42
|
+
|
43
|
+
def on_class(node)
|
44
|
+
class_send_elements(node).each do |macro|
|
45
|
+
next unless accessor?(macro)
|
46
|
+
|
47
|
+
check(macro)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
alias on_sclass on_class
|
51
|
+
alias on_module on_class
|
52
|
+
|
53
|
+
def autocorrect(node)
|
54
|
+
lambda do |corrector|
|
55
|
+
corrector.replace(node, correction(node))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def class_send_elements(class_node)
|
62
|
+
class_def = class_node.body
|
63
|
+
|
64
|
+
if !class_def || class_def.def_type?
|
65
|
+
[]
|
66
|
+
elsif class_def.send_type?
|
67
|
+
[class_def]
|
68
|
+
else
|
69
|
+
class_def.each_child_node(:send).to_a
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def accessor?(send_node)
|
74
|
+
send_node.macro? && ACCESSOR_METHODS.include?(send_node.method_name)
|
75
|
+
end
|
76
|
+
|
77
|
+
def check(send_node)
|
78
|
+
if grouped_style? && sibling_accessors(send_node).size > 1
|
79
|
+
add_offense(send_node)
|
80
|
+
elsif separated_style? && send_node.arguments.size > 1
|
81
|
+
add_offense(send_node)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def grouped_style?
|
86
|
+
style == :grouped
|
87
|
+
end
|
88
|
+
|
89
|
+
def separated_style?
|
90
|
+
style == :separated
|
91
|
+
end
|
92
|
+
|
93
|
+
def sibling_accessors(send_node)
|
94
|
+
send_node.parent.each_child_node(:send).select do |sibling|
|
95
|
+
accessor?(sibling) &&
|
96
|
+
sibling.method?(send_node.method_name) &&
|
97
|
+
node_visibility(sibling) == node_visibility(send_node)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def message(send_node)
|
102
|
+
msg = grouped_style? ? GROUPED_MSG : SEPARATED_MSG
|
103
|
+
format(msg, accessor: send_node.method_name)
|
104
|
+
end
|
105
|
+
|
106
|
+
def correction(node)
|
107
|
+
if grouped_style?
|
108
|
+
accessors = sibling_accessors(node)
|
109
|
+
if node == accessors.first
|
110
|
+
group_accessors(node, accessors)
|
111
|
+
else
|
112
|
+
''
|
113
|
+
end
|
114
|
+
else
|
115
|
+
separate_accessors(node)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def group_accessors(node, accessors)
|
120
|
+
accessor_names = accessors.flat_map do |accessor|
|
121
|
+
accessor.arguments.map(&:source)
|
122
|
+
end
|
123
|
+
|
124
|
+
"#{node.method_name} #{accessor_names.join(', ')}"
|
125
|
+
end
|
126
|
+
|
127
|
+
def separate_accessors(node)
|
128
|
+
node.arguments.map do |arg|
|
129
|
+
if arg == node.arguments.first
|
130
|
+
"#{node.method_name} #{arg.source}"
|
131
|
+
else
|
132
|
+
indent = ' ' * node.loc.column
|
133
|
+
"#{indent}#{node.method_name} #{arg.source}"
|
134
|
+
end
|
135
|
+
end.join("\n")
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,145 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'set'
|
4
|
+
|
5
|
+
module RuboCop
|
6
|
+
module Cop
|
7
|
+
module Style
|
8
|
+
# This cop checks for places where `attr_reader` and `attr_writer`
|
9
|
+
# for the same method can be combined into single `attr_accessor`.
|
10
|
+
#
|
11
|
+
# @example
|
12
|
+
# # bad
|
13
|
+
# class Foo
|
14
|
+
# attr_reader :bar
|
15
|
+
# attr_writer :bar
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# # good
|
19
|
+
# class Foo
|
20
|
+
# attr_accessor :bar
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
class BisectedAttrAccessor < Cop
|
24
|
+
include VisibilityHelp
|
25
|
+
|
26
|
+
MSG = 'Combine both accessors into `attr_accessor %<name>s`.'
|
27
|
+
|
28
|
+
def on_class(class_node)
|
29
|
+
VISIBILITY_SCOPES.each do |visibility|
|
30
|
+
reader_names, writer_names = accessor_names(class_node, visibility)
|
31
|
+
|
32
|
+
accessor_macroses(class_node, visibility).each do |macro|
|
33
|
+
check(macro, reader_names, writer_names)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
alias on_sclass on_class
|
38
|
+
alias on_module on_class
|
39
|
+
|
40
|
+
def autocorrect(node)
|
41
|
+
macro = node.parent
|
42
|
+
|
43
|
+
lambda do |corrector|
|
44
|
+
corrector.replace(macro, replacement(macro, node))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def accessor_names(class_node, visibility)
|
51
|
+
reader_names = Set.new
|
52
|
+
writer_names = Set.new
|
53
|
+
|
54
|
+
accessor_macroses(class_node, visibility).each do |macro|
|
55
|
+
names = macro.arguments.map(&:source)
|
56
|
+
|
57
|
+
names.each do |name|
|
58
|
+
if attr_reader?(macro)
|
59
|
+
reader_names.add(name)
|
60
|
+
else
|
61
|
+
writer_names.add(name)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
[reader_names, writer_names]
|
67
|
+
end
|
68
|
+
|
69
|
+
def accessor_macroses(class_node, visibility)
|
70
|
+
class_def = class_node.body
|
71
|
+
return [] if !class_def || class_def.def_type?
|
72
|
+
|
73
|
+
send_nodes =
|
74
|
+
if class_def.send_type?
|
75
|
+
[class_def]
|
76
|
+
else
|
77
|
+
class_def.each_child_node(:send)
|
78
|
+
end
|
79
|
+
|
80
|
+
send_nodes.select { |node| attr_within_visibility_scope?(node, visibility) }
|
81
|
+
end
|
82
|
+
|
83
|
+
def attr_within_visibility_scope?(node, visibility)
|
84
|
+
node.macro? &&
|
85
|
+
(attr_reader?(node) || attr_writer?(node)) &&
|
86
|
+
node_visibility(node) == visibility
|
87
|
+
end
|
88
|
+
|
89
|
+
def attr_reader?(send_node)
|
90
|
+
send_node.method?(:attr_reader) || send_node.method?(:attr)
|
91
|
+
end
|
92
|
+
|
93
|
+
def attr_writer?(send_node)
|
94
|
+
send_node.method?(:attr_writer)
|
95
|
+
end
|
96
|
+
|
97
|
+
def check(macro, reader_names, writer_names)
|
98
|
+
macro.arguments.each do |arg_node|
|
99
|
+
name = arg_node.source
|
100
|
+
|
101
|
+
if (attr_reader?(macro) && writer_names.include?(name)) ||
|
102
|
+
(attr_writer?(macro) && reader_names.include?(name))
|
103
|
+
add_offense(arg_node, message: format(MSG, name: name))
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def replacement(macro, node)
|
109
|
+
class_node = macro.each_ancestor(:class, :sclass, :module).first
|
110
|
+
reader_names, writer_names = accessor_names(class_node, node_visibility(macro))
|
111
|
+
|
112
|
+
rest_args = rest_args(macro.arguments, reader_names, writer_names)
|
113
|
+
|
114
|
+
if attr_reader?(macro)
|
115
|
+
attr_reader_replacement(macro, node, rest_args)
|
116
|
+
elsif rest_args.empty?
|
117
|
+
''
|
118
|
+
else
|
119
|
+
"#{macro.method_name} #{rest_args.map(&:source).join(', ')}"
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def rest_args(args, reader_names, writer_names)
|
124
|
+
args.reject do |arg|
|
125
|
+
name = arg.source
|
126
|
+
reader_names.include?(name) && writer_names.include?(name)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def attr_reader_replacement(macro, node, rest_args)
|
131
|
+
if rest_args.empty?
|
132
|
+
"attr_accessor #{node.source}"
|
133
|
+
else
|
134
|
+
"attr_accessor #{node.source}\n"\
|
135
|
+
"#{indent(macro)}#{macro.method_name} #{rest_args.map(&:source).join(', ')}"
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
def indent(node)
|
140
|
+
' ' * node.loc.column
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -19,6 +19,15 @@ module RuboCop
|
|
19
19
|
# @@test = 10
|
20
20
|
# end
|
21
21
|
#
|
22
|
+
# class A
|
23
|
+
# def self.test(name, value)
|
24
|
+
# class_variable_set("@@#{name}", value)
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# class A; end
|
29
|
+
# A.class_variable_set(:@@test, 10)
|
30
|
+
#
|
22
31
|
# # good
|
23
32
|
# class A
|
24
33
|
# @test = 10
|
@@ -30,6 +39,12 @@ module RuboCop
|
|
30
39
|
# end
|
31
40
|
# end
|
32
41
|
#
|
42
|
+
# class A
|
43
|
+
# def self.test(name)
|
44
|
+
# class_variable_get("@@#{name}") # you can access without offense
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
#
|
33
48
|
class ClassVars < Cop
|
34
49
|
MSG = 'Replace class var %<class_var>s with a class ' \
|
35
50
|
'instance var.'
|
@@ -38,6 +53,12 @@ module RuboCop
|
|
38
53
|
add_offense(node, location: :name)
|
39
54
|
end
|
40
55
|
|
56
|
+
def on_send(node)
|
57
|
+
return unless node.method?(:class_variable_set)
|
58
|
+
|
59
|
+
add_offense(node.first_argument)
|
60
|
+
end
|
61
|
+
|
41
62
|
def message(node)
|
42
63
|
class_var, = *node
|
43
64
|
format(MSG, class_var: class_var)
|