rubocop 0.80.1 → 0.81.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +62 -15
  4. data/lib/rubocop.rb +4 -1
  5. data/lib/rubocop/ast/builder.rb +2 -0
  6. data/lib/rubocop/ast/node.rb +11 -6
  7. data/lib/rubocop/ast/node/block_node.rb +5 -1
  8. data/lib/rubocop/ast/node/case_match_node.rb +56 -0
  9. data/lib/rubocop/ast/traversal.rb +11 -9
  10. data/lib/rubocop/config_obsoletion.rb +1 -0
  11. data/lib/rubocop/cop/layout/array_alignment.rb +53 -10
  12. data/lib/rubocop/cop/layout/block_end_newline.rb +5 -3
  13. data/lib/rubocop/cop/layout/else_alignment.rb +8 -0
  14. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  15. data/lib/rubocop/cop/lint/boolean_symbol.rb +12 -0
  16. data/lib/rubocop/cop/lint/erb_new_arguments.rb +1 -1
  17. data/lib/rubocop/cop/lint/loop.rb +6 -4
  18. data/lib/rubocop/cop/lint/nested_method_definition.rb +2 -2
  19. data/lib/rubocop/cop/lint/raise_exception.rb +39 -0
  20. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +1 -1
  21. data/lib/rubocop/cop/lint/struct_new_override.rb +58 -0
  22. data/lib/rubocop/cop/lint/suppressed_exception.rb +12 -22
  23. data/lib/rubocop/cop/lint/unused_method_argument.rb +32 -6
  24. data/lib/rubocop/cop/migration/department_name.rb +22 -9
  25. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +6 -1
  26. data/lib/rubocop/cop/mixin/method_complexity.rb +5 -0
  27. data/lib/rubocop/cop/naming/method_name.rb +30 -0
  28. data/lib/rubocop/cop/style/access_modifier_declarations.rb +26 -6
  29. data/lib/rubocop/cop/style/collection_methods.rb +2 -0
  30. data/lib/rubocop/cop/style/documentation.rb +43 -5
  31. data/lib/rubocop/cop/style/end_block.rb +6 -0
  32. data/lib/rubocop/cop/style/hash_each_methods.rb +2 -0
  33. data/lib/rubocop/cop/style/hash_transform_keys.rb +6 -2
  34. data/lib/rubocop/cop/style/hash_transform_values.rb +6 -2
  35. data/lib/rubocop/cop/style/inverse_methods.rb +1 -1
  36. data/lib/rubocop/cop/style/lambda.rb +1 -0
  37. data/lib/rubocop/cop/style/module_function.rb +56 -10
  38. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -2
  39. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -2
  40. data/lib/rubocop/cop/style/redundant_sort.rb +2 -2
  41. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +34 -0
  42. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +41 -0
  43. data/lib/rubocop/cop/style/trailing_comma_in_block_args.rb +85 -0
  44. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +44 -0
  45. data/lib/rubocop/formatter/clang_style_formatter.rb +1 -1
  46. data/lib/rubocop/formatter/junit_formatter.rb +17 -6
  47. data/lib/rubocop/formatter/tap_formatter.rb +1 -1
  48. data/lib/rubocop/processed_source.rb +1 -1
  49. data/lib/rubocop/version.rb +1 -1
  50. metadata +8 -5
  51. data/lib/rubocop/cop/lint/end_in_method.rb +0 -40
@@ -19,6 +19,7 @@ module RuboCop
19
19
  'Layout/LeadingBlankLines' => 'Layout/LeadingEmptyLines',
20
20
  'Layout/TrailingBlankLines' => 'Layout/TrailingEmptyLines',
21
21
  'Lint/DuplicatedKey' => 'Lint/DuplicateHashKey',
22
+ 'Lint/EndInMethod' => 'Style/EndBlock',
22
23
  'Lint/HandleExceptions' => 'Lint/SuppressedException',
23
24
  'Lint/MultipleCompare' => 'Lint/MultipleComparison',
24
25
  'Lint/StringConversionInInterpolation' => 'Lint/RedundantStringCoercion',
@@ -6,33 +6,76 @@ module RuboCop
6
6
  # Here we check if the elements of a multi-line array literal are
7
7
  # aligned.
8
8
  #
9
- # @example
9
+ # @example EnforcedStyle: with_first_element (default)
10
+ # # good
11
+ #
12
+ # array = [1, 2, 3,
13
+ # 4, 5, 6]
14
+ # array = ['run',
15
+ # 'forrest',
16
+ # 'run']
17
+ #
10
18
  # # bad
11
- # a = [1, 2, 3,
19
+ #
20
+ # array = [1, 2, 3,
12
21
  # 4, 5, 6]
13
22
  # array = ['run',
14
23
  # 'forrest',
15
24
  # 'run']
16
25
  #
26
+ # @example EnforcedStyle: with_fixed_indentation
17
27
  # # good
18
- # a = [1, 2, 3,
19
- # 4, 5, 6]
20
- # a = ['run',
21
- # 'forrest',
22
- # 'run']
28
+ #
29
+ # array = [1, 2, 3,
30
+ # 4, 5, 6]
31
+ #
32
+ # # bad
33
+ #
34
+ # array = [1, 2, 3,
35
+ # 4, 5, 6]
23
36
  class ArrayAlignment < Cop
24
37
  include Alignment
25
38
 
26
- MSG = 'Align the elements of an array literal if they span more ' \
27
- 'than one line.'
39
+ ALIGN_ELEMENTS_MSG = 'Align the elements of an array literal ' \
40
+ 'if they span more than one line.'
41
+
42
+ FIXED_INDENT_MSG = 'Use one level of indentation for elements ' \
43
+ 'following the first line of a multi-line array.'
28
44
 
29
45
  def on_array(node)
30
- check_alignment(node.children)
46
+ return if node.children.size < 2
47
+
48
+ check_alignment(node.children, base_column(node, node.children))
31
49
  end
32
50
 
33
51
  def autocorrect(node)
34
52
  AlignmentCorrector.correct(processed_source, node, column_delta)
35
53
  end
54
+
55
+ private
56
+
57
+ def message(_node)
58
+ fixed_indentation? ? FIXED_INDENT_MSG : ALIGN_ELEMENTS_MSG
59
+ end
60
+
61
+ def fixed_indentation?
62
+ cop_config['EnforcedStyle'] == 'with_fixed_indentation'
63
+ end
64
+
65
+ def base_column(node, args)
66
+ if fixed_indentation?
67
+ lineno = target_method_lineno(node)
68
+ line = node.source_range.source_buffer.source_line(lineno)
69
+ indentation_of_line = /\S.*/.match(line).begin(0)
70
+ indentation_of_line + configured_indentation_width
71
+ else
72
+ display_column(args.first.source_range)
73
+ end
74
+ end
75
+
76
+ def target_method_lineno(node)
77
+ node.loc.line
78
+ end
36
79
  end
37
80
  end
38
81
  end
@@ -52,9 +52,11 @@ module RuboCop
52
52
  end
53
53
 
54
54
  def delimiter_range(node)
55
- Parser::Source::Range.new(node.loc.expression.source_buffer,
56
- node.children.last.loc.expression.end_pos,
57
- node.loc.expression.end_pos)
55
+ Parser::Source::Range.new(
56
+ node.loc.expression.source_buffer,
57
+ node.children.compact.last.loc.expression.end_pos,
58
+ node.loc.expression.end_pos
59
+ )
58
60
  end
59
61
  end
60
62
  end
@@ -59,6 +59,14 @@ module RuboCop
59
59
  check_alignment(node.when_branches.last.loc.keyword, node.loc.else)
60
60
  end
61
61
 
62
+ def on_case_match(node)
63
+ return unless node.else?
64
+
65
+ check_alignment(
66
+ node.in_pattern_branches.last.loc.keyword, node.loc.else
67
+ )
68
+ end
69
+
62
70
  def autocorrect(node)
63
71
  AlignmentCorrector.correct(processed_source, node, column_delta)
64
72
  end
@@ -193,7 +193,7 @@ module RuboCop
193
193
  node = node.receiver while node.receiver
194
194
  # ascend to first call which has a dot
195
195
  node = node.parent
196
- node = node.parent until node.loc.dot
196
+ node = node.parent until node.loc.respond_to?(:dot) && node.loc.dot
197
197
 
198
198
  return if node.loc.dot.line != node.first_line
199
199
 
@@ -32,6 +32,18 @@ module RuboCop
32
32
 
33
33
  add_offense(node, message: format(MSG, boolean: node.value))
34
34
  end
35
+
36
+ def autocorrect(node)
37
+ lambda do |corrector|
38
+ boolean_literal = node.source.delete(':')
39
+ parent = node.parent
40
+ if parent&.pair_type?
41
+ corrector.remove(parent.loc.operator)
42
+ boolean_literal = "#{node.source} =>"
43
+ end
44
+ corrector.replace(node.loc.expression, boolean_literal)
45
+ end
46
+ end
35
47
  end
36
48
  end
37
49
  end
@@ -84,7 +84,7 @@ module RuboCop
84
84
 
85
85
  def on_send(node)
86
86
  erb_new_with_non_keyword_arguments(node) do |arguments|
87
- return if correct_arguments?(arguments)
87
+ return if arguments.empty? || correct_arguments?(arguments)
88
88
 
89
89
  arguments[1..3].each_with_index do |argument, i|
90
90
  next if !argument || argument.hash_type?
@@ -27,18 +27,20 @@ module RuboCop
27
27
  #
28
28
  # # good
29
29
  #
30
- # # using while
31
- # while some_condition
30
+ # # while replacement
31
+ # loop do
32
32
  # do_something
33
+ # break unless some_condition
33
34
  # end
34
35
  #
35
36
  # @example
36
37
  #
37
38
  # # good
38
39
  #
39
- # # using until
40
- # until some_condition
40
+ # # until replacement
41
+ # loop do
41
42
  # do_something
43
+ # break if some_condition
42
44
  # end
43
45
  class Loop < Cop
44
46
  MSG = 'Use `Kernel#loop` with `break` rather than ' \
@@ -31,14 +31,14 @@ module RuboCop
31
31
  # # good
32
32
  #
33
33
  # def foo
34
- # self.class_eval do
34
+ # self.class.class_eval do
35
35
  # def bar
36
36
  # end
37
37
  # end
38
38
  # end
39
39
  #
40
40
  # def foo
41
- # self.module_exec do
41
+ # self.class.module_exec do
42
42
  # def bar
43
43
  # end
44
44
  # end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks for `raise` or `fail` statements which are
7
+ # raising `Exception` class.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # raise Exception, 'Error message here'
12
+ #
13
+ # # good
14
+ # raise StandardError, 'Error message here'
15
+ class RaiseException < Cop
16
+ MSG = 'Use `StandardError` over `Exception`.'
17
+
18
+ def_node_matcher :exception?, <<~PATTERN
19
+ (send nil? ${:raise :fail} (const _ :Exception) ... )
20
+ PATTERN
21
+
22
+ def_node_matcher :exception_new_with_message?, <<~PATTERN
23
+ (send nil? ${:raise :fail}
24
+ (send (const _ :Exception) :new ... ))
25
+ PATTERN
26
+
27
+ def on_send(node)
28
+ add_offense(node) if raise_exception?(node)
29
+ end
30
+
31
+ private
32
+
33
+ def raise_exception?(node)
34
+ exception?(node) || exception_new_with_message?(node)
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -32,7 +32,7 @@ module RuboCop
32
32
  def_node_matcher :bad_method?, <<~PATTERN
33
33
  {
34
34
  (send $(csend ...) $_ ...)
35
- (send $(block (csend ...) ...) $_ ...)
35
+ (send $({block numblock} (csend ...) ...) $_ ...)
36
36
  }
37
37
  PATTERN
38
38
 
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Lint
6
+ # This cop checks unexpected overrides of the `Struct` built-in methods
7
+ # via `Struct.new`.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # Bad = Struct.new(:members, :clone, :count)
12
+ # b = Bad.new([], true, 1)
13
+ # b.members #=> [] (overriding `Struct#members`)
14
+ # b.clone #=> true (overriding `Object#clone`)
15
+ # b.count #=> 1 (overriding `Enumerable#count`)
16
+ #
17
+ # # good
18
+ # Good = Struct.new(:id, :name)
19
+ # g = Good.new(1, "foo")
20
+ # g.members #=> [:id, :name]
21
+ # g.clone #=> #<struct Good id=1, name="foo">
22
+ # g.count #=> 2
23
+ #
24
+ class StructNewOverride < Cop
25
+ MSG = '`%<member_name>s` member overrides `Struct#%<method_name>s`' \
26
+ ' and it may be unexpected.'
27
+
28
+ STRUCT_METHOD_NAMES = Struct.instance_methods
29
+ STRUCT_MEMBER_NAME_TYPES = %i[sym str].freeze
30
+
31
+ def_node_matcher :struct_new, <<~PATTERN
32
+ (send
33
+ (const ${nil? cbase} :Struct) :new ...)
34
+ PATTERN
35
+
36
+ def on_send(node)
37
+ return unless struct_new(node) do
38
+ node.arguments.each_with_index do |arg, index|
39
+ # Ignore if the first argument is a class name
40
+ next if index.zero? && arg.str_type?
41
+
42
+ # Ignore if the argument is not a member name
43
+ next unless STRUCT_MEMBER_NAME_TYPES.include?(arg.type)
44
+
45
+ member_name = arg.value
46
+
47
+ next unless STRUCT_METHOD_NAMES.include?(member_name.to_sym)
48
+
49
+ message = format(MSG, member_name: member_name.inspect,
50
+ method_name: member_name.to_s)
51
+ add_offense(arg, message: message)
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -5,7 +5,7 @@ module RuboCop
5
5
  module Lint
6
6
  # This cop checks for *rescue* blocks with no body.
7
7
  #
8
- # @example AllowComments: false (default)
8
+ # @example
9
9
  #
10
10
  # # bad
11
11
  # def some_method
@@ -14,25 +14,11 @@ module RuboCop
14
14
  # end
15
15
  #
16
16
  # # bad
17
- # def some_method
18
- # do_something
19
- # rescue
20
- # # do nothing
21
- # end
22
- #
23
- # # bad
24
17
  # begin
25
18
  # do_something
26
19
  # rescue
27
20
  # end
28
21
  #
29
- # # bad
30
- # begin
31
- # do_something
32
- # rescue
33
- # # do nothing
34
- # end
35
- #
36
22
  # # good
37
23
  # def some_method
38
24
  # do_something
@@ -47,32 +33,36 @@ module RuboCop
47
33
  # handle_exception
48
34
  # end
49
35
  #
50
- # @example AllowComments: true
36
+ # @example AllowComments: true (default)
51
37
  #
52
- # # bad
38
+ # # good
53
39
  # def some_method
54
40
  # do_something
55
41
  # rescue
42
+ # # do nothing
56
43
  # end
57
44
  #
58
- # # bad
45
+ # # good
59
46
  # begin
60
47
  # do_something
61
48
  # rescue
49
+ # # do nothing
62
50
  # end
63
51
  #
64
- # # good
52
+ # @example AllowComments: false
53
+ #
54
+ # # bad
65
55
  # def some_method
66
56
  # do_something
67
57
  # rescue
68
- # # do nothing but comment
58
+ # # do nothing
69
59
  # end
70
60
  #
71
- # # good
61
+ # # bad
72
62
  # begin
73
63
  # do_something
74
64
  # rescue
75
- # # do nothing but comment
65
+ # # do nothing
76
66
  # end
77
67
  class SuppressedException < Cop
78
68
  MSG = 'Do not suppress exceptions.'
@@ -38,9 +38,34 @@ module RuboCop
38
38
  # def do_something(unused)
39
39
  # end
40
40
  #
41
+ # @example IgnoreNotImplementedMethods: true (default)
42
+ # # good
43
+ # def do_something(unused)
44
+ # raise NotImplementedError
45
+ # end
46
+ #
47
+ # def do_something_else(unused)
48
+ # fail "TODO"
49
+ # end
50
+ #
51
+ # @example IgnoreNotImplementedMethods: false
52
+ # # bad
53
+ # def do_something(unused)
54
+ # raise NotImplementedError
55
+ # end
56
+ #
57
+ # def do_something_else(unused)
58
+ # fail "TODO"
59
+ # end
60
+ #
41
61
  class UnusedMethodArgument < Cop
42
62
  include UnusedArgument
43
63
 
64
+ def_node_matcher :not_implemented?, <<~PATTERN
65
+ {(send nil? :raise (const nil? :NotImplementedError))
66
+ (send nil? :fail ...)}
67
+ PATTERN
68
+
44
69
  def autocorrect(node)
45
70
  UnusedArgCorrector.correct(processed_source, node)
46
71
  end
@@ -51,16 +76,17 @@ module RuboCop
51
76
  return unless variable.method_argument?
52
77
  return if variable.keyword_argument? &&
53
78
  cop_config['AllowUnusedKeywordArguments']
54
-
55
- if cop_config['IgnoreEmptyMethods']
56
- body = variable.scope.node.body
57
-
58
- return if body.nil?
59
- end
79
+ return if ignored_method?(variable.scope.node.body)
60
80
 
61
81
  super
62
82
  end
63
83
 
84
+ def ignored_method?(body)
85
+ cop_config['IgnoreEmptyMethods'] && body.nil? ||
86
+ cop_config['IgnoreNotImplementedMethods'] &&
87
+ not_implemented?(body)
88
+ end
89
+
64
90
  def message(variable)
65
91
  message = +"Unused method argument - `#{variable.name}`."
66
92