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.
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