rubocop 0.54.0 → 0.55.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
|