rubocop 0.39.0 → 0.40.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubocop might be problematic. Click here for more details.

Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -1
  3. data/config/default.yml +65 -2
  4. data/config/disabled.yml +0 -28
  5. data/config/enabled.yml +40 -0
  6. data/lib/rubocop.rb +3 -0
  7. data/lib/rubocop/ast_node.rb +28 -13
  8. data/lib/rubocop/cached_data.rb +15 -2
  9. data/lib/rubocop/cli.rb +24 -8
  10. data/lib/rubocop/config.rb +3 -3
  11. data/lib/rubocop/config_loader.rb +0 -7
  12. data/lib/rubocop/cop/cop.rb +2 -2
  13. data/lib/rubocop/cop/lint/condition_position.rb +3 -1
  14. data/lib/rubocop/cop/lint/else_layout.rb +3 -2
  15. data/lib/rubocop/cop/lint/end_alignment.rb +2 -2
  16. data/lib/rubocop/cop/lint/nested_method_definition.rb +15 -9
  17. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
  18. data/lib/rubocop/cop/lint/unused_block_argument.rb +2 -0
  19. data/lib/rubocop/cop/lint/useless_access_modifier.rb +86 -20
  20. data/lib/rubocop/cop/lint/useless_array_splat.rb +56 -0
  21. data/lib/rubocop/cop/metrics/method_length.rb +1 -1
  22. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +11 -25
  23. data/lib/rubocop/cop/mixin/if_node.rb +4 -0
  24. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +14 -12
  25. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +75 -9
  26. data/lib/rubocop/cop/mixin/on_normal_if_unless.rb +1 -1
  27. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -2
  28. data/lib/rubocop/cop/mixin/trailing_comma.rb +15 -5
  29. data/lib/rubocop/cop/performance/case_when_splat.rb +71 -44
  30. data/lib/rubocop/cop/performance/detect.rb +28 -18
  31. data/lib/rubocop/cop/performance/end_with.rb +1 -1
  32. data/lib/rubocop/cop/performance/redundant_merge.rb +29 -11
  33. data/lib/rubocop/cop/performance/start_with.rb +1 -1
  34. data/lib/rubocop/cop/performance/string_replacement.rb +39 -20
  35. data/lib/rubocop/cop/rails/action_filter.rb +1 -2
  36. data/lib/rubocop/cop/rails/date.rb +2 -5
  37. data/lib/rubocop/cop/rails/time_zone.rb +3 -6
  38. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +57 -0
  39. data/lib/rubocop/cop/style/alias.rb +10 -3
  40. data/lib/rubocop/cop/style/align_parameters.rb +8 -2
  41. data/lib/rubocop/cop/style/and_or.rb +29 -21
  42. data/lib/rubocop/cop/style/class_and_module_children.rb +1 -1
  43. data/lib/rubocop/cop/style/collection_methods.rb +1 -2
  44. data/lib/rubocop/cop/style/comment_indentation.rb +1 -1
  45. data/lib/rubocop/cop/style/conditional_assignment.rb +13 -7
  46. data/lib/rubocop/cop/style/empty_case_condition.rb +96 -0
  47. data/lib/rubocop/cop/style/encoding.rb +9 -5
  48. data/lib/rubocop/cop/style/extra_spacing.rb +22 -7
  49. data/lib/rubocop/cop/style/file_name.rb +7 -2
  50. data/lib/rubocop/cop/style/guard_clause.rb +18 -10
  51. data/lib/rubocop/cop/style/if_inside_else.rb +1 -1
  52. data/lib/rubocop/cop/style/if_unless_modifier.rb +2 -1
  53. data/lib/rubocop/cop/style/indentation_width.rb +7 -4
  54. data/lib/rubocop/cop/style/lambda.rb +98 -30
  55. data/lib/rubocop/cop/style/line_end_concatenation.rb +5 -0
  56. data/lib/rubocop/cop/style/multiline_array_brace_layout.rb +34 -9
  57. data/lib/rubocop/cop/style/multiline_assignment_layout.rb +2 -1
  58. data/lib/rubocop/cop/style/multiline_hash_brace_layout.rb +42 -17
  59. data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +39 -14
  60. data/lib/rubocop/cop/style/multiline_method_definition_brace_layout.rb +36 -15
  61. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +8 -6
  62. data/lib/rubocop/cop/style/negated_while.rb +2 -1
  63. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +15 -0
  64. data/lib/rubocop/cop/style/nested_ternary_operator.rb +5 -8
  65. data/lib/rubocop/cop/style/next.rb +1 -1
  66. data/lib/rubocop/cop/style/not.rb +5 -2
  67. data/lib/rubocop/cop/style/parentheses_around_condition.rb +2 -2
  68. data/lib/rubocop/cop/style/raise_args.rb +70 -7
  69. data/lib/rubocop/cop/style/redundant_exception.rb +34 -20
  70. data/lib/rubocop/cop/style/redundant_parentheses.rb +27 -1
  71. data/lib/rubocop/cop/style/space_after_colon.rb +14 -10
  72. data/lib/rubocop/cop/style/space_after_comma.rb +5 -0
  73. data/lib/rubocop/cop/style/space_after_not.rb +3 -4
  74. data/lib/rubocop/cop/style/space_after_semicolon.rb +5 -0
  75. data/lib/rubocop/cop/style/space_around_operators.rb +2 -1
  76. data/lib/rubocop/cop/style/special_global_vars.rb +4 -2
  77. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +1 -1
  78. data/lib/rubocop/cop/style/string_methods.rb +1 -2
  79. data/lib/rubocop/cop/style/symbol_proc.rb +7 -1
  80. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +25 -0
  81. data/lib/rubocop/cop/style/word_array.rb +50 -22
  82. data/lib/rubocop/cop/util.rb +0 -4
  83. data/lib/rubocop/formatter/clang_style_formatter.rb +38 -22
  84. data/lib/rubocop/options.rb +45 -10
  85. data/lib/rubocop/path_util.rb +2 -34
  86. data/lib/rubocop/result_cache.rb +10 -4
  87. data/lib/rubocop/runner.rb +5 -3
  88. data/lib/rubocop/version.rb +1 -1
  89. metadata +7 -4
@@ -6,6 +6,8 @@ module RuboCop
6
6
  module Style
7
7
  # This cop checks for uses if the keyword *not* instead of !.
8
8
  class Not < Cop
9
+ include IfNode
10
+
9
11
  MSG = 'Use `!` instead of `not`.'.freeze
10
12
 
11
13
  OPPOSITE_METHODS = {
@@ -14,7 +16,8 @@ module RuboCop
14
16
  :<= => :>,
15
17
  :> => :<=,
16
18
  :< => :>=,
17
- :>= => :< }.freeze
19
+ :>= => :<
20
+ }.freeze
18
21
 
19
22
  def on_send(node)
20
23
  return unless node.keyword_not?
@@ -35,7 +38,7 @@ module RuboCop
35
38
  OPPOSITE_METHODS[child.method_name].to_s)
36
39
  end
37
40
  elsif child.and_type? || child.or_type? || child.binary_operation? ||
38
- ternary_op?(child)
41
+ ternary?(child)
39
42
  lambda do |corrector|
40
43
  corrector.replace(range, '!(')
41
44
  corrector.insert_after(node.source_range, ')')
@@ -12,7 +12,7 @@ module RuboCop
12
12
  include Parentheses
13
13
 
14
14
  def on_if(node)
15
- return if ternary_op?(node)
15
+ return if ternary?(node)
16
16
  process_control_op(node)
17
17
  end
18
18
 
@@ -41,7 +41,7 @@ module RuboCop
41
41
  end
42
42
 
43
43
  def modifier_op?(node)
44
- return false if ternary_op?(node)
44
+ return false if ternary?(node)
45
45
  return true if node.type == :rescue
46
46
 
47
47
  [:if, :while, :until].include?(node.type) &&
@@ -4,10 +4,48 @@
4
4
  module RuboCop
5
5
  module Cop
6
6
  module Style
7
- # This cop checks the args passed to `fail` and `raise`.
7
+ # This cop checks the args passed to `fail` and `raise`. For exploded
8
+ # style (default), it recommends passing the exception class and message
9
+ # to `raise`, rather than construct an instance of the error. It will
10
+ # still allow passing just a message, or the construction of an error
11
+ # with more than one argument.
12
+ #
13
+ # The exploded style works identically, but with the addition that it
14
+ # will also suggest constructing error objects when the exception is
15
+ # passed multiple arguments.
16
+ #
17
+ # @example
18
+ #
19
+ # # EnforcedStyle: exploded
20
+ #
21
+ # # bad
22
+ # raise StandardError.new("message")
23
+ #
24
+ # # good
25
+ # raise StandardError, "message"
26
+ # fail "message"
27
+ # raise RuntimeError.new(arg1, arg2, arg3)
28
+ #
29
+ # @example
30
+ #
31
+ # # EnforcedStyle: compact
32
+ #
33
+ # # bad
34
+ # raise StandardError, "message"
35
+ # raise RuntimeError, arg1, arg2, arg3
36
+ #
37
+ # # good
38
+ # raise StandardError.new("message")
39
+ # raise RuntimeError.new(arg1, arg2, arg3)
40
+ # fail "message"
8
41
  class RaiseArgs < Cop
9
42
  include ConfigurableEnforcedStyle
10
43
 
44
+ EXPLODED_MSG = 'Provide an exception class and message ' \
45
+ 'as arguments to `%s`.'.freeze
46
+ COMPACT_MSG = 'Provide an exception object ' \
47
+ 'as an argument to `%s`.'.freeze
48
+
11
49
  def on_send(node)
12
50
  return unless node.command?(:raise) || node.command?(:fail)
13
51
 
@@ -21,6 +59,33 @@ module RuboCop
21
59
 
22
60
  private
23
61
 
62
+ def autocorrect(node)
63
+ _scope, method, *args = *node
64
+
65
+ new_exception = if style == :compact
66
+ correction_exploded_to_compact(args)
67
+ else
68
+ correction_compact_to_exploded(args)
69
+ end
70
+ replacement = "#{method} #{new_exception}"
71
+
72
+ ->(corrector) { corrector.replace(node.source_range, replacement) }
73
+ end
74
+
75
+ def correction_compact_to_exploded(node)
76
+ exception_node, _new, message_node = *node.first
77
+
78
+ "#{exception_node.const_name}, #{message_node.source}"
79
+ end
80
+
81
+ def correction_exploded_to_compact(node)
82
+ exception_node, *message_nodes = *node
83
+
84
+ messages = message_nodes.map(&:source).join(', ')
85
+
86
+ "#{exception_node.const_name}.new(#{messages})"
87
+ end
88
+
24
89
  def check_compact(node)
25
90
  _receiver, selector, *args = *node
26
91
 
@@ -55,12 +120,10 @@ module RuboCop
55
120
  end
56
121
 
57
122
  def message(method)
58
- case style
59
- when :compact
60
- "Provide an exception object as an argument to `#{method}`."
61
- when :exploded
62
- 'Provide an exception class and message as ' \
63
- "arguments to `#{method}`."
123
+ if style == :compact
124
+ format(COMPACT_MSG, method)
125
+ else
126
+ format(EXPLODED_MSG, method)
64
127
  end
65
128
  end
66
129
  end
@@ -6,36 +6,50 @@ module RuboCop
6
6
  module Style
7
7
  # This cop checks for RuntimeError as the argument of raise/fail.
8
8
  #
9
- # Currently it checks for code like this:
9
+ # It checks for code like this:
10
10
  #
11
11
  # @example
12
- #
12
+ # # Bad
13
13
  # raise RuntimeError, 'message'
14
+ #
15
+ # # Bad
16
+ # raise RuntimeError.new('message')
17
+ #
18
+ # # Good
19
+ # raise 'message'
14
20
  class RedundantException < Cop
15
- MSG = 'Redundant `RuntimeError` argument can be removed.'.freeze
16
-
17
- TARGET_NODE = s(:const, nil, :RuntimeError)
21
+ MSG_1 = 'Redundant `RuntimeError` argument can be removed.'.freeze
22
+ MSG_2 = 'Redundant `RuntimeError.new` call can be replaced with ' \
23
+ 'just the message.'.freeze
18
24
 
19
25
  def on_send(node)
20
- return unless node.command?(:raise) || node.command?(:fail)
21
-
22
- _receiver, _selector, *args = *node
23
-
24
- return unless args.size == 2
25
-
26
- first_arg, = *args
27
-
28
- add_offense(first_arg, :expression) if first_arg == TARGET_NODE
26
+ exploded?(node) { return add_offense(node, :expression, MSG_1) }
27
+ compact?(node) { add_offense(node, :expression, MSG_2) }
29
28
  end
30
29
 
31
- # switch `raise RuntimeError, 'message'` to `raise 'message'`
30
+ # Switch `raise RuntimeError, 'message'` to `raise 'message'`, and
31
+ # `raise RuntimeError.new('message')` to `raise 'message'`.
32
32
  def autocorrect(node)
33
- start_range = node.source_range.begin
34
- no_comma = range_with_surrounding_comma(node.source_range.end, :right)
35
- comma_range = start_range.join(no_comma)
36
- final_range = range_with_surrounding_space(comma_range, :right)
37
- ->(corrector) { corrector.replace(final_range, '') }
33
+ exploded?(node) do |command, message|
34
+ return lambda do |corrector|
35
+ corrector.replace(node.source_range,
36
+ "#{command} #{message.source}")
37
+ end
38
+ end
39
+ compact?(node) do |new_call, message|
40
+ lambda do |corrector|
41
+ corrector.replace(new_call.source_range, message.source)
42
+ end
43
+ end
38
44
  end
45
+
46
+ def_node_matcher :exploded?, <<-PATTERN
47
+ (send nil ${:raise :fail} (const nil :RuntimeError) $_)
48
+ PATTERN
49
+
50
+ def_node_matcher :compact?, <<-PATTERN
51
+ (send nil {:raise :fail} $(send (const nil :RuntimeError) :new $_))
52
+ PATTERN
39
53
  end
40
54
  end
41
55
  end
@@ -42,7 +42,13 @@ module RuboCop
42
42
  # don't flag `rescue(ExceptionClass)`
43
43
  rescue?(node) ||
44
44
  # don't flag `method (arg) { }`
45
- (arg_in_call_with_block?(node) && !parentheses?(parent))
45
+ (arg_in_call_with_block?(node) && !parentheses?(parent)) ||
46
+ # don't flag
47
+ # ```
48
+ # { a: (1
49
+ # ), }
50
+ # ```
51
+ allowed_array_or_hash_element?(node)
46
52
  end
47
53
 
48
54
  def check(begin_node)
@@ -83,6 +89,26 @@ module RuboCop
83
89
  node.parent && node.parent.keyword?
84
90
  end
85
91
 
92
+ def allowed_array_or_hash_element?(node)
93
+ (hash_element?(node) || array_element?(node)) &&
94
+ only_closing_paren_before_comma?(node)
95
+ end
96
+
97
+ def hash_element?(node)
98
+ node.parent && node.parent.pair_type?
99
+ end
100
+
101
+ def array_element?(node)
102
+ node.parent && node.parent.array_type?
103
+ end
104
+
105
+ def only_closing_paren_before_comma?(node)
106
+ source_buffer = node.source_range.source_buffer
107
+ line_range = source_buffer.line_range(node.loc.end.line)
108
+
109
+ line_range.source =~ /^\s*\)\s*,/
110
+ end
111
+
86
112
  def disallowed_literal?(node)
87
113
  node.literal? && !ALLOWED_LITERALS.include?(node.type)
88
114
  end
@@ -5,29 +5,33 @@ module RuboCop
5
5
  module Cop
6
6
  module Style
7
7
  # Checks for colon (:) not followed by some kind of space.
8
+ # N.B. this cop does not handle spaces after a ternary operator, which are
9
+ # instead handled by Style/SpaceAroundOperators.
8
10
  class SpaceAfterColon < Cop
9
11
  include IfNode
10
12
 
11
13
  MSG = 'Space missing after colon.'.freeze
12
14
 
13
15
  def on_pair(node)
14
- oper = node.loc.operator
15
- return unless oper.is?(':') && followed_by_space?(oper)
16
+ colon = node.loc.operator
16
17
 
17
- add_offense(oper, oper)
18
- end
18
+ return unless colon.is?(':')
19
19
 
20
- def on_if(node)
21
- return unless ternary_op?(node)
20
+ add_offense(colon, colon) unless followed_by_space?(colon)
21
+ end
22
22
 
23
- colon = node.loc.colon
24
- return unless followed_by_space?(colon)
23
+ def on_kwoptarg(node)
24
+ # We have no direct reference to the colon source range following an
25
+ # optional keyword argument's name, so must construct one.
26
+ colon = node.loc.name.end.resize(1)
25
27
 
26
- add_offense(colon, colon)
28
+ add_offense(colon, colon) unless followed_by_space?(colon)
27
29
  end
28
30
 
31
+ private
32
+
29
33
  def followed_by_space?(colon)
30
- colon.source_buffer.source[colon.end_pos] =~ /\S/
34
+ colon.source_buffer.source[colon.end_pos] =~ /\s/
31
35
  end
32
36
 
33
37
  def autocorrect(range)
@@ -8,6 +8,11 @@ module RuboCop
8
8
  class SpaceAfterComma < Cop
9
9
  include SpaceAfterPunctuation
10
10
 
11
+ def space_style_before_rcurly
12
+ cfg = config.for_cop('Style/SpaceInsideHashLiteralBraces')
13
+ cfg['EnforcedStyle'] || 'space'
14
+ end
15
+
11
16
  def kind(token)
12
17
  'comma' if token.type == :tCOMMA
13
18
  end
@@ -16,13 +16,12 @@ module RuboCop
16
16
  MSG = 'Do not leave space between `!` and its argument.'.freeze
17
17
 
18
18
  def on_send(node)
19
- _receiver, method_name, *_args = *node
19
+ receiver, method_name, *_args = *node
20
20
 
21
21
  return unless method_name == :!
22
- return unless node.source =~ /^!\s+\w+/
22
+ return unless receiver.loc.column - node.loc.column > 1
23
23
 
24
- # TODO: Improve source range to highlight the redundant whitespace.
25
- add_offense(node, :selector)
24
+ add_offense(node, :expression)
26
25
  end
27
26
 
28
27
  def autocorrect(node)
@@ -8,6 +8,11 @@ module RuboCop
8
8
  class SpaceAfterSemicolon < Cop
9
9
  include SpaceAfterPunctuation
10
10
 
11
+ def space_style_before_rcurly
12
+ cfg = config.for_cop('Style/SpaceInsideBlockBraces')
13
+ cfg['EnforcedStyle'] || 'space'
14
+ end
15
+
11
16
  def kind(token)
12
17
  'semicolon' if token.type == :tSEMI
13
18
  end
@@ -7,6 +7,7 @@ module RuboCop
7
7
  # Checks that operators have space around them, except for **
8
8
  # which should not have surrounding space.
9
9
  class SpaceAroundOperators < Cop
10
+ include IfNode
10
11
  include PrecedingFollowingAlignment
11
12
  include HashNode # any_pairs_on_the_same_line?
12
13
 
@@ -22,7 +23,7 @@ module RuboCop
22
23
  end
23
24
 
24
25
  def on_if(node)
25
- return unless node.loc.respond_to?(:question)
26
+ return unless ternary?(node)
26
27
  _, if_branch, else_branch = *node
27
28
 
28
29
  check_operator(node.loc.question, if_branch.source_range)
@@ -43,9 +43,11 @@ module RuboCop
43
43
  Hash[ENGLISH_VARS.flat_map { |k, vs| vs.map { |v| [v, [k]] } }]
44
44
 
45
45
  ENGLISH_VARS.merge!(
46
- Hash[ENGLISH_VARS.flat_map { |_, vs| vs.map { |v| [v, [v]] } }])
46
+ Hash[ENGLISH_VARS.flat_map { |_, vs| vs.map { |v| [v, [v]] } }]
47
+ )
47
48
  PERL_VARS.merge!(
48
- Hash[PERL_VARS.flat_map { |_, vs| vs.map { |v| [v, [v]] } }])
49
+ Hash[PERL_VARS.flat_map { |_, vs| vs.map { |v| [v, [v]] } }]
50
+ )
49
51
  ENGLISH_VARS.each { |_, v| v.freeze }.freeze
50
52
  PERL_VARS.each { |_, v| v.freeze }.freeze
51
53
 
@@ -16,7 +16,7 @@ module RuboCop
16
16
  # # require_no_parentheses - bad
17
17
  # ->(a,b,c) { a + b + c }
18
18
  #
19
- # # require_parentheses - good
19
+ # # require_no_parentheses - good
20
20
  # ->a,b,c { a + b + c}
21
21
  class StabbyLambdaParentheses < Cop
22
22
  include ConfigurableEnforcedStyle
@@ -17,8 +17,7 @@ module RuboCop
17
17
  add_offense(node, :selector,
18
18
  format(MSG,
19
19
  preferred_method(method_name),
20
- method_name)
21
- )
20
+ method_name))
22
21
  end
23
22
 
24
23
  def autocorrect(node)
@@ -113,7 +113,7 @@ module RuboCop
113
113
  def can_shorten?(block_args, block_body)
114
114
  # something { |x, y| ... }
115
115
  return false unless block_args.children.size == 1
116
- return false if block_args.children.first.blockarg_type?
116
+ return false if non_shortenable_args?(block_args)
117
117
  return false unless block_body && block_body.type == :send
118
118
 
119
119
  receiver, _method_name, args = *block_body
@@ -131,6 +131,12 @@ module RuboCop
131
131
  def super?(node)
132
132
  [:super, :zsuper].include?(node.type)
133
133
  end
134
+
135
+ def non_shortenable_args?(block_args)
136
+ # something { |&x| ... }
137
+ # something { |*x| ... }
138
+ [:blockarg, :restarg].include?(block_args.children.first.type)
139
+ end
134
140
  end
135
141
  end
136
142
  end
@@ -40,6 +40,31 @@ module RuboCop
40
40
  check(node, args, 'parameter of %s method call',
41
41
  args.last.source_range.end_pos, node.source_range.end_pos)
42
42
  end
43
+
44
+ private
45
+
46
+ def avoid_autocorrect?(args)
47
+ hash_with_braces?(args.last) && braces_will_be_removed?(args)
48
+ end
49
+
50
+ def hash_with_braces?(node)
51
+ node.hash_type? && node.loc.begin
52
+ end
53
+
54
+ # Returns true if running with --auto-correct would remove the braces
55
+ # of the last argument.
56
+ def braces_will_be_removed?(args)
57
+ brace_config = config.for_cop('Style/BracesAroundHashParameters')
58
+ return false unless brace_config['Enabled']
59
+ return false if brace_config['AutoCorrect'] == false
60
+
61
+ brace_style = brace_config['EnforcedStyle']
62
+ return true if brace_style == 'no_braces'
63
+
64
+ return false unless brace_style == 'context_dependent'
65
+
66
+ args.size == 1 || !args[-2].hash_type?
67
+ end
43
68
  end
44
69
  end
45
70
  end