rubocop 0.54.0 → 0.55.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 +5 -1
- data/config/default.yml +17 -2
- data/config/enabled.yml +13 -0
- data/lib/rubocop.rb +4 -0
- data/lib/rubocop/ast/node/mixin/binary_operator_node.rb +20 -0
- data/lib/rubocop/cli.rb +6 -2
- data/lib/rubocop/cop/commissioner.rb +21 -25
- data/lib/rubocop/cop/layout/end_of_line.rb +33 -0
- data/lib/rubocop/cop/layout/space_inside_parens.rb +64 -5
- data/lib/rubocop/cop/layout/trailing_whitespace.rb +20 -0
- data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +80 -0
- data/lib/rubocop/cop/lint/shadowed_argument.rb +3 -0
- data/lib/rubocop/cop/lint/void.rb +20 -9
- data/lib/rubocop/cop/metrics/block_length.rb +17 -1
- data/lib/rubocop/cop/metrics/line_length.rb +2 -3
- data/lib/rubocop/cop/mixin/percent_literal.rb +9 -8
- data/lib/rubocop/cop/performance/end_with.rb +2 -1
- data/lib/rubocop/cop/performance/regexp_match.rb +43 -7
- data/lib/rubocop/cop/performance/start_with.rb +2 -1
- data/lib/rubocop/cop/performance/unneeded_sort.rb +130 -0
- data/lib/rubocop/cop/rails/http_status.rb +19 -16
- data/lib/rubocop/cop/rails/inverse_of.rb +29 -22
- data/lib/rubocop/cop/rails/read_write_attribute.rb +9 -2
- data/lib/rubocop/cop/style/array_join.rb +1 -1
- data/lib/rubocop/cop/style/class_vars.rb +5 -4
- data/lib/rubocop/cop/style/commented_keyword.rb +2 -3
- data/lib/rubocop/cop/style/empty_line_after_guard_clause.rb +39 -8
- data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +22 -11
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +5 -0
- data/lib/rubocop/cop/style/mutable_constant.rb +5 -0
- data/lib/rubocop/cop/style/negated_while.rb +18 -0
- data/lib/rubocop/cop/style/nested_ternary_operator.rb +11 -0
- data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
- data/lib/rubocop/cop/style/one_line_conditional.rb +17 -0
- data/lib/rubocop/cop/style/option_hash.rb +6 -0
- data/lib/rubocop/cop/style/single_line_block_params.rb +20 -0
- data/lib/rubocop/cop/style/special_global_vars.rb +52 -0
- data/lib/rubocop/cop/style/string_literals.rb +1 -1
- data/lib/rubocop/cop/style/unpack_first.rb +0 -2
- data/lib/rubocop/formatter/auto_gen_config_formatter.rb +16 -0
- data/lib/rubocop/formatter/formatter_set.rb +14 -13
- data/lib/rubocop/node_pattern.rb +2 -2
- data/lib/rubocop/options.rb +1 -0
- data/lib/rubocop/version.rb +1 -1
- metadata +13 -4
@@ -4,11 +4,16 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
6
|
# This cop looks for has_(one|many) and belongs_to associations where
|
7
|
-
#
|
8
|
-
# because of a scope or the options used.
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
7
|
+
# Active Record can't automatically determine the inverse association
|
8
|
+
# because of a scope or the options used. Using the blog with order scope
|
9
|
+
# example below, traversing the a Blog's association in both directions
|
10
|
+
# with `blog.posts.first.blog` would cause the `blog` to be loaded from
|
11
|
+
# the database twice.
|
12
|
+
#
|
13
|
+
# `:inverse_of` must be manually specified for Active Record to use the
|
14
|
+
# associated object in memory, or set to `false` to opt-out. Note that
|
15
|
+
# setting `nil` does not stop Active Record from trying to determine the
|
16
|
+
# inverse automatically, and is not considered a valid value for this.
|
12
17
|
#
|
13
18
|
# @example
|
14
19
|
# # good
|
@@ -62,15 +67,6 @@ module RuboCop
|
|
62
67
|
# )
|
63
68
|
# end
|
64
69
|
#
|
65
|
-
# # good
|
66
|
-
# # You can also opt-out with specifying `inverse_of: nil`.
|
67
|
-
# class Blog < ApplicationRecord
|
68
|
-
# has_many(:posts,
|
69
|
-
# -> { order(published_at: :desc) },
|
70
|
-
# inverse_of: nil
|
71
|
-
# )
|
72
|
-
# end
|
73
|
-
#
|
74
70
|
# @example
|
75
71
|
# # bad
|
76
72
|
# class Picture < ApplicationRecord
|
@@ -139,7 +135,9 @@ module RuboCop
|
|
139
135
|
|
140
136
|
minimum_target_rails_version 4.1
|
141
137
|
|
142
|
-
|
138
|
+
SPECIFY_MSG = 'Specify an `:inverse_of` option.'.freeze
|
139
|
+
NIL_MSG = 'You specified `inverse_of: nil`, you probably meant to ' \
|
140
|
+
'use `inverse_of: false`.'.freeze
|
143
141
|
|
144
142
|
def_node_matcher :association_recv_arguments, <<-PATTERN
|
145
143
|
(send $_ {:has_many :has_one :belongs_to} _ $...)
|
@@ -165,16 +163,16 @@ module RuboCop
|
|
165
163
|
(pair (sym :as) !nil)
|
166
164
|
PATTERN
|
167
165
|
|
168
|
-
def_node_matcher :class_name_option?, <<-PATTERN
|
169
|
-
(pair (sym :class_name) !nil)
|
170
|
-
PATTERN
|
171
|
-
|
172
166
|
def_node_matcher :foreign_key_option?, <<-PATTERN
|
173
167
|
(pair (sym :foreign_key) !nil)
|
174
168
|
PATTERN
|
175
169
|
|
176
170
|
def_node_matcher :inverse_of_option?, <<-PATTERN
|
177
|
-
(pair (sym :inverse_of)
|
171
|
+
(pair (sym :inverse_of) !nil)
|
172
|
+
PATTERN
|
173
|
+
|
174
|
+
def_node_matcher :inverse_of_nil_option?, <<-PATTERN
|
175
|
+
(pair (sym :inverse_of) nil)
|
178
176
|
PATTERN
|
179
177
|
|
180
178
|
def on_send(node)
|
@@ -191,7 +189,7 @@ module RuboCop
|
|
191
189
|
options_requiring_inverse_of?(options)
|
192
190
|
|
193
191
|
return if options_contain_inverse_of?(options)
|
194
|
-
add_offense(node, location: :selector)
|
192
|
+
add_offense(node, message: message(options), location: :selector)
|
195
193
|
end
|
196
194
|
|
197
195
|
def scope?(arguments)
|
@@ -201,7 +199,6 @@ module RuboCop
|
|
201
199
|
def options_requiring_inverse_of?(options)
|
202
200
|
required = options.any? do |opt|
|
203
201
|
conditions_option?(opt) ||
|
204
|
-
class_name_option?(opt) ||
|
205
202
|
foreign_key_option?(opt)
|
206
203
|
end
|
207
204
|
|
@@ -231,6 +228,16 @@ module RuboCop
|
|
231
228
|
return true if arg.nil? && recv.nil?
|
232
229
|
arg && recv && arg.children[0] == recv.children[0]
|
233
230
|
end
|
231
|
+
|
232
|
+
private
|
233
|
+
|
234
|
+
def message(options)
|
235
|
+
if options.any? { |opt| inverse_of_nil_option?(opt) }
|
236
|
+
NIL_MSG
|
237
|
+
else
|
238
|
+
SPECIFY_MSG
|
239
|
+
end
|
240
|
+
end
|
234
241
|
end
|
235
242
|
end
|
236
243
|
end
|
@@ -3,8 +3,15 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
# This cop checks for the use of the read_attribute or
|
7
|
-
#
|
6
|
+
# This cop checks for the use of the read_attribute or write_attribute
|
7
|
+
# methods, and recommends square brackets instead.
|
8
|
+
#
|
9
|
+
# If an attribute is missing from the instance (for example, when
|
10
|
+
# initialized by a partial `select`) then read_attribute will return nil,
|
11
|
+
# but square brackets will raise an ActiveModel::MissingAttributeError.
|
12
|
+
#
|
13
|
+
# Explicitly raising an error in this situation is preferable, and that
|
14
|
+
# is why rubocop recommends using square brackets.
|
8
15
|
#
|
9
16
|
# @example
|
10
17
|
#
|
@@ -7,10 +7,11 @@ module RuboCop
|
|
7
7
|
# are signaled only on assignment to class variables to
|
8
8
|
# reduce the number of offenses that would be reported.
|
9
9
|
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
10
|
+
# You have to be careful when setting a value for a class
|
11
|
+
# variable; if a class has been inherited, changing the
|
12
|
+
# value of a class variable also affects the inheriting
|
13
|
+
# classes. This means that it's almost always better to
|
14
|
+
# use a class instance variable instead.
|
14
15
|
#
|
15
16
|
# @example
|
16
17
|
# # bad
|
@@ -74,10 +74,9 @@ module RuboCop
|
|
74
74
|
|
75
75
|
def extract_heredoc_lines(ast)
|
76
76
|
return [] unless ast
|
77
|
-
ast.each_node.
|
78
|
-
next unless node.location.is_a?(Parser::Source::Map::Heredoc)
|
77
|
+
ast.each_node(:str, :dstr, :xstr).select(&:heredoc?).map do |node|
|
79
78
|
body = node.location.heredoc_body
|
80
|
-
|
79
|
+
(body.first_line...body.last_line)
|
81
80
|
end
|
82
81
|
end
|
83
82
|
end
|
@@ -39,17 +39,25 @@ module RuboCop
|
|
39
39
|
include RangeHelp
|
40
40
|
|
41
41
|
MSG = 'Add empty line after guard clause.'.freeze
|
42
|
+
END_OF_HEREDOC_LINE = 1
|
42
43
|
|
43
44
|
def on_if(node)
|
44
|
-
return
|
45
|
+
return if correct_style?(node)
|
45
46
|
|
46
|
-
|
47
|
-
|
48
|
-
return if next_sibling_empty_or_guard_clause?(node)
|
47
|
+
if last_argument_is_heredoc?(node)
|
48
|
+
heredoc_node = last_argument(node)
|
49
49
|
|
50
|
-
|
50
|
+
num_of_heredoc_lines = heredoc_node.children.size
|
51
|
+
line = node.last_line + num_of_heredoc_lines + END_OF_HEREDOC_LINE
|
51
52
|
|
52
|
-
|
53
|
+
return if next_line_empty?(line)
|
54
|
+
|
55
|
+
add_offense(heredoc_node, location: :heredoc_end)
|
56
|
+
else
|
57
|
+
return if next_line_empty?(node.last_line)
|
58
|
+
|
59
|
+
add_offense(node)
|
60
|
+
end
|
53
61
|
end
|
54
62
|
|
55
63
|
def autocorrect(node)
|
@@ -61,12 +69,19 @@ module RuboCop
|
|
61
69
|
|
62
70
|
private
|
63
71
|
|
72
|
+
def correct_style?(node)
|
73
|
+
!contains_guard_clause?(node) ||
|
74
|
+
next_line_rescue_or_ensure?(node) ||
|
75
|
+
next_sibling_parent_empty_or_else?(node) ||
|
76
|
+
next_sibling_empty_or_guard_clause?(node)
|
77
|
+
end
|
78
|
+
|
64
79
|
def contains_guard_clause?(node)
|
65
80
|
node.if_branch && node.if_branch.guard_clause?
|
66
81
|
end
|
67
82
|
|
68
|
-
def next_line_empty?(
|
69
|
-
processed_source[
|
83
|
+
def next_line_empty?(line)
|
84
|
+
processed_source[line].blank?
|
70
85
|
end
|
71
86
|
|
72
87
|
def next_line_rescue_or_ensure?(node)
|
@@ -89,6 +104,22 @@ module RuboCop
|
|
89
104
|
|
90
105
|
next_sibling.if_type? && contains_guard_clause?(next_sibling)
|
91
106
|
end
|
107
|
+
|
108
|
+
def last_argument_is_heredoc?(node)
|
109
|
+
last_children = node.children.last
|
110
|
+
|
111
|
+
return false unless last_children && last_children.send_type?
|
112
|
+
|
113
|
+
last_argument = last_argument(node)
|
114
|
+
|
115
|
+
last_argument &&
|
116
|
+
(last_argument.str_type? || last_argument.dstr_type?) &&
|
117
|
+
last_argument.heredoc?
|
118
|
+
end
|
119
|
+
|
120
|
+
def last_argument(node)
|
121
|
+
node.children.last.last_argument
|
122
|
+
end
|
92
123
|
end
|
93
124
|
end
|
94
125
|
end
|
@@ -74,20 +74,12 @@ module RuboCop
|
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
def autocorrect(node)
|
77
|
+
def autocorrect(node)
|
78
78
|
lambda do |corrector|
|
79
79
|
if style == :never
|
80
|
-
corrector
|
81
|
-
side: :right))
|
80
|
+
remove_comment(corrector, node)
|
82
81
|
else
|
83
|
-
|
84
|
-
if last_special_comment.nil?
|
85
|
-
corrector.insert_before(processed_source.tokens[0].pos,
|
86
|
-
"#{FROZEN_STRING_LITERAL_ENABLED}\n")
|
87
|
-
else
|
88
|
-
corrector.insert_after(last_special_comment.pos,
|
89
|
-
"\n#{FROZEN_STRING_LITERAL_ENABLED}")
|
90
|
-
end
|
82
|
+
insert_comment(corrector)
|
91
83
|
end
|
92
84
|
end
|
93
85
|
end
|
@@ -138,6 +130,25 @@ module RuboCop
|
|
138
130
|
location: frozen_string_literal_comment.pos,
|
139
131
|
message: MSG_UNNECESSARY)
|
140
132
|
end
|
133
|
+
|
134
|
+
def remove_comment(corrector, node)
|
135
|
+
corrector.remove(range_with_surrounding_space(range: node.pos,
|
136
|
+
side: :right))
|
137
|
+
end
|
138
|
+
|
139
|
+
def insert_comment(corrector)
|
140
|
+
last_special_comment = last_special_comment(processed_source)
|
141
|
+
if last_special_comment.nil?
|
142
|
+
corrector.insert_before(processed_source.tokens[0].pos,
|
143
|
+
"#{FROZEN_STRING_LITERAL_ENABLED}\n\n")
|
144
|
+
elsif processed_source.following_line(last_special_comment).empty?
|
145
|
+
corrector.insert_after(last_special_comment.pos,
|
146
|
+
"\n#{FROZEN_STRING_LITERAL_ENABLED}")
|
147
|
+
else
|
148
|
+
corrector.insert_after(last_special_comment.pos,
|
149
|
+
"\n#{FROZEN_STRING_LITERAL_ENABLED}\n")
|
150
|
+
end
|
151
|
+
end
|
141
152
|
end
|
142
153
|
end
|
143
154
|
end
|
@@ -20,6 +20,7 @@ module RuboCop
|
|
20
20
|
def on_send(node)
|
21
21
|
return if ineligible_node?(node)
|
22
22
|
return unless !node.arguments? && node.parenthesized?
|
23
|
+
return if ignored_method?(node.method_name)
|
23
24
|
return if same_name_assignment?(node)
|
24
25
|
|
25
26
|
add_offense(node, location: :begin)
|
@@ -38,6 +39,10 @@ module RuboCop
|
|
38
39
|
node.camel_case_method? || node.implicit_call? || node.keyword_not?
|
39
40
|
end
|
40
41
|
|
42
|
+
def ignored_method?(method)
|
43
|
+
cop_config['IgnoredMethods'].to_a.map(&:to_sym).include?(method)
|
44
|
+
end
|
45
|
+
|
41
46
|
def same_name_assignment?(node)
|
42
47
|
any_assignment?(node) do |asgn_node|
|
43
48
|
if asgn_node.masgn_type?
|
@@ -4,6 +4,24 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
6
|
# Checks for uses of while with a negated condition.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# while !foo
|
11
|
+
# bar
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# until foo
|
16
|
+
# bar
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # bad
|
20
|
+
# bar until !foo
|
21
|
+
#
|
22
|
+
# # good
|
23
|
+
# bar while foo
|
24
|
+
# bar while !foo && baz
|
7
25
|
class NegatedWhile < Cop
|
8
26
|
include NegativeConditional
|
9
27
|
|
@@ -4,6 +4,17 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
6
|
# This cop checks for nested ternary op expressions.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# a ? (b ? b1 : b2) : a2
|
11
|
+
#
|
12
|
+
# # good
|
13
|
+
# if a
|
14
|
+
# b ? b1 : b2
|
15
|
+
# else
|
16
|
+
# a2
|
17
|
+
# end
|
7
18
|
class NestedTernaryOperator < Cop
|
8
19
|
MSG = 'Ternary operators must not be nested. Prefer `if` or `else` ' \
|
9
20
|
'constructs instead.'.freeze
|
@@ -14,7 +14,7 @@ module RuboCop
|
|
14
14
|
#
|
15
15
|
# The cop ignores comparisons to global variables, since they are often
|
16
16
|
# populated with objects which can be compared with integers, but are
|
17
|
-
# not themselves `
|
17
|
+
# not themselves `Integer` polymorphic.
|
18
18
|
#
|
19
19
|
# @example EnforcedStyle: predicate (default)
|
20
20
|
# # bad
|
@@ -5,6 +5,23 @@ module RuboCop
|
|
5
5
|
module Style
|
6
6
|
# TODO: Make configurable.
|
7
7
|
# Checks for uses of if/then/else/end on a single line.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# # bad
|
11
|
+
# if foo then boo else doo end
|
12
|
+
# unless foo then boo else goo end
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# foo ? boo : doo
|
16
|
+
# boo if foo
|
17
|
+
# if foo then boo end
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# if foo
|
21
|
+
# boo
|
22
|
+
# else
|
23
|
+
# doo
|
24
|
+
# end
|
8
25
|
class OneLineConditional < Cop
|
9
26
|
include OnNormalIfUnless
|
10
27
|
|
@@ -27,6 +27,8 @@ module RuboCop
|
|
27
27
|
PATTERN
|
28
28
|
|
29
29
|
def on_args(node)
|
30
|
+
return if super_used?(node)
|
31
|
+
|
30
32
|
option_hash(node) do |options|
|
31
33
|
add_offense(options)
|
32
34
|
end
|
@@ -38,6 +40,10 @@ module RuboCop
|
|
38
40
|
cop_config.key?('SuspiciousParamNames') &&
|
39
41
|
cop_config['SuspiciousParamNames'].include?(arg_name.to_s)
|
40
42
|
end
|
43
|
+
|
44
|
+
def super_used?(node)
|
45
|
+
node.parent.each_node(:zsuper).any?
|
46
|
+
end
|
41
47
|
end
|
42
48
|
end
|
43
49
|
end
|
@@ -8,6 +8,26 @@ module RuboCop
|
|
8
8
|
#
|
9
9
|
# For instance one can configure `reduce`(`inject`) to use |a, e| as
|
10
10
|
# parameters.
|
11
|
+
#
|
12
|
+
# Configuration option: Methods
|
13
|
+
# Should be set to use this cop. Array of hashes, where each key is the
|
14
|
+
# method name and value - array of argument names.
|
15
|
+
#
|
16
|
+
# @example Methods: [{reduce: %w[a b]}]
|
17
|
+
# # bad
|
18
|
+
# foo.reduce { |c, d| c + d }
|
19
|
+
# foo.reduce { |_, _d| 1 }
|
20
|
+
#
|
21
|
+
# # good
|
22
|
+
# foo.reduce { |a, b| a + b }
|
23
|
+
# foo.reduce { |a, _b| a }
|
24
|
+
# foo.reduce { |a, (id, _)| a + id }
|
25
|
+
# foo.reduce { true }
|
26
|
+
#
|
27
|
+
# # good
|
28
|
+
# foo.reduce do |c, d|
|
29
|
+
# c + d
|
30
|
+
# end
|
11
31
|
class SingleLineBlockParams < Cop
|
12
32
|
MSG = 'Name `%<method>s` block params `|%<params>s|`.'.freeze
|
13
33
|
|
@@ -3,7 +3,59 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Style
|
6
|
+
#
|
6
7
|
# This cop looks for uses of Perl-style global variables.
|
8
|
+
#
|
9
|
+
# @example EnforcedStyle: use_english_names (default)
|
10
|
+
# # good
|
11
|
+
# puts $LOAD_PATH
|
12
|
+
# puts $LOADED_FEATURES
|
13
|
+
# puts $PROGRAM_NAME
|
14
|
+
# puts $ERROR_INFO
|
15
|
+
# puts $ERROR_POSITION
|
16
|
+
# puts $FIELD_SEPARATOR # or $FS
|
17
|
+
# puts $OUTPUT_FIELD_SEPARATOR # or $OFS
|
18
|
+
# puts $INPUT_RECORD_SEPARATOR # or $RS
|
19
|
+
# puts $OUTPUT_RECORD_SEPARATOR # or $ORS
|
20
|
+
# puts $INPUT_LINE_NUMBER # or $NR
|
21
|
+
# puts $LAST_READ_LINE
|
22
|
+
# puts $DEFAULT_OUTPUT
|
23
|
+
# puts $DEFAULT_INPUT
|
24
|
+
# puts $PROCESS_ID # or $PID
|
25
|
+
# puts $CHILD_STATUS
|
26
|
+
# puts $LAST_MATCH_INFO
|
27
|
+
# puts $IGNORECASE
|
28
|
+
# puts $ARGV # or ARGV
|
29
|
+
# puts $MATCH
|
30
|
+
# puts $PREMATCH
|
31
|
+
# puts $POSTMATCH
|
32
|
+
# puts $LAST_PAREN_MATCH
|
33
|
+
#
|
34
|
+
# @example EnforcedStyle: use_perl_names
|
35
|
+
# # good
|
36
|
+
# puts $:
|
37
|
+
# puts $"
|
38
|
+
# puts $0
|
39
|
+
# puts $!
|
40
|
+
# puts $@
|
41
|
+
# puts $;
|
42
|
+
# puts $,
|
43
|
+
# puts $/
|
44
|
+
# puts $\
|
45
|
+
# puts $.
|
46
|
+
# puts $_
|
47
|
+
# puts $>
|
48
|
+
# puts $<
|
49
|
+
# puts $$
|
50
|
+
# puts $?
|
51
|
+
# puts $~
|
52
|
+
# puts $=
|
53
|
+
# puts $*
|
54
|
+
# puts $&
|
55
|
+
# puts $`
|
56
|
+
# puts $'
|
57
|
+
# puts $+
|
58
|
+
#
|
7
59
|
class SpecialGlobalVars < Cop
|
8
60
|
include ConfigurableEnforcedStyle
|
9
61
|
|