rubocop 0.54.0 → 0.55.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -1
  3. data/config/default.yml +17 -2
  4. data/config/enabled.yml +13 -0
  5. data/lib/rubocop.rb +4 -0
  6. data/lib/rubocop/ast/node/mixin/binary_operator_node.rb +20 -0
  7. data/lib/rubocop/cli.rb +6 -2
  8. data/lib/rubocop/cop/commissioner.rb +21 -25
  9. data/lib/rubocop/cop/layout/end_of_line.rb +33 -0
  10. data/lib/rubocop/cop/layout/space_inside_parens.rb +64 -5
  11. data/lib/rubocop/cop/layout/trailing_whitespace.rb +20 -0
  12. data/lib/rubocop/cop/lint/safe_navigation_consistency.rb +80 -0
  13. data/lib/rubocop/cop/lint/shadowed_argument.rb +3 -0
  14. data/lib/rubocop/cop/lint/void.rb +20 -9
  15. data/lib/rubocop/cop/metrics/block_length.rb +17 -1
  16. data/lib/rubocop/cop/metrics/line_length.rb +2 -3
  17. data/lib/rubocop/cop/mixin/percent_literal.rb +9 -8
  18. data/lib/rubocop/cop/performance/end_with.rb +2 -1
  19. data/lib/rubocop/cop/performance/regexp_match.rb +43 -7
  20. data/lib/rubocop/cop/performance/start_with.rb +2 -1
  21. data/lib/rubocop/cop/performance/unneeded_sort.rb +130 -0
  22. data/lib/rubocop/cop/rails/http_status.rb +19 -16
  23. data/lib/rubocop/cop/rails/inverse_of.rb +29 -22
  24. data/lib/rubocop/cop/rails/read_write_attribute.rb +9 -2
  25. data/lib/rubocop/cop/style/array_join.rb +1 -1
  26. data/lib/rubocop/cop/style/class_vars.rb +5 -4
  27. data/lib/rubocop/cop/style/commented_keyword.rb +2 -3
  28. data/lib/rubocop/cop/style/empty_line_after_guard_clause.rb +39 -8
  29. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +22 -11
  30. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +5 -0
  31. data/lib/rubocop/cop/style/mutable_constant.rb +5 -0
  32. data/lib/rubocop/cop/style/negated_while.rb +18 -0
  33. data/lib/rubocop/cop/style/nested_ternary_operator.rb +11 -0
  34. data/lib/rubocop/cop/style/numeric_predicate.rb +1 -1
  35. data/lib/rubocop/cop/style/one_line_conditional.rb +17 -0
  36. data/lib/rubocop/cop/style/option_hash.rb +6 -0
  37. data/lib/rubocop/cop/style/single_line_block_params.rb +20 -0
  38. data/lib/rubocop/cop/style/special_global_vars.rb +52 -0
  39. data/lib/rubocop/cop/style/string_literals.rb +1 -1
  40. data/lib/rubocop/cop/style/unpack_first.rb +0 -2
  41. data/lib/rubocop/formatter/auto_gen_config_formatter.rb +16 -0
  42. data/lib/rubocop/formatter/formatter_set.rb +14 -13
  43. data/lib/rubocop/node_pattern.rb +2 -2
  44. data/lib/rubocop/options.rb +1 -0
  45. data/lib/rubocop/version.rb +1 -1
  46. 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
- # ActiveRecord can't automatically determine the inverse association
8
- # because of a scope or the options used. This can result in unnecessary
9
- # queries in some circumstances. `:inverse_of` must be manually specified
10
- # for associations to work in both ways, or set to `false` or `nil`
11
- # to opt-out.
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
- MSG = 'Specify an `:inverse_of` option.'.freeze
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
- # write_attribute methods.
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
  #
@@ -15,7 +15,7 @@ module RuboCop
15
15
  # %w(foo bar baz) * ","
16
16
  #
17
17
  # # good
18
- # %w(foo bar bax).join(",")
18
+ # %w(foo bar baz).join(",")
19
19
  #
20
20
  class ArrayJoin < Cop
21
21
  MSG = 'Favor `Array#join` over `Array#*`.'.freeze
@@ -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
- # Setting value for class variable need to take care.
11
- # If some class has been inherited by other classes, setting value
12
- # for class variable affected children classes.
13
- # So using class instance variable is better in almost case.
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.with_object([]) do |node, heredocs|
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
- heredocs << (body.first_line...body.last_line)
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 unless contains_guard_clause?(node)
45
+ return if correct_style?(node)
45
46
 
46
- return if next_line_rescue_or_ensure?(node)
47
- return if next_sibling_parent_empty_or_else?(node)
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
- return if next_line_empty?(node)
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
- add_offense(node)
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?(node)
69
- processed_source[node.last_line].blank?
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) # rubocop:disable Metrics/MethodLength
77
+ def autocorrect(node)
78
78
  lambda do |corrector|
79
79
  if style == :never
80
- corrector.remove(range_with_surrounding_space(range: node.pos,
81
- side: :right))
80
+ remove_comment(corrector, node)
82
81
  else
83
- last_special_comment = last_special_comment(processed_source)
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?
@@ -12,6 +12,11 @@ module RuboCop
12
12
  #
13
13
  # # good
14
14
  # CONST = [1, 2, 3].freeze
15
+ #
16
+ # # good
17
+ # CONST = <<~TESTING.freeze
18
+ # This is a heredoc
19
+ # TESTING
15
20
  class MutableConstant < Cop
16
21
  include FrozenStringLiteral
17
22
 
@@ -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 `Interger` polymorphic.
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