rubocop 0.41.2 → 0.42.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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -3
  3. data/config/default.yml +13 -0
  4. data/config/disabled.yml +5 -0
  5. data/config/enabled.yml +20 -0
  6. data/lib/rubocop.rb +4 -0
  7. data/lib/rubocop/ast_node.rb +4 -3
  8. data/lib/rubocop/config.rb +1 -1
  9. data/lib/rubocop/config_loader.rb +2 -7
  10. data/lib/rubocop/cop/cop.rb +3 -3
  11. data/lib/rubocop/cop/lint/block_alignment.rb +18 -16
  12. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +34 -19
  13. data/lib/rubocop/cop/lint/next_without_accumulator.rb +9 -1
  14. data/lib/rubocop/cop/lint/shadowed_exception.rb +23 -3
  15. data/lib/rubocop/cop/lint/unneeded_disable.rb +1 -1
  16. data/lib/rubocop/cop/lint/useless_access_modifier.rb +41 -4
  17. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +1 -1
  18. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +1 -1
  19. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +3 -5
  20. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +4 -4
  21. data/lib/rubocop/cop/mixin/space_inside.rb +23 -8
  22. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  23. data/lib/rubocop/cop/offense.rb +33 -10
  24. data/lib/rubocop/cop/performance/case_when_splat.rb +16 -14
  25. data/lib/rubocop/cop/performance/sample.rb +0 -1
  26. data/lib/rubocop/cop/rails/save_bang.rb +77 -0
  27. data/lib/rubocop/cop/rails/validation.rb +15 -15
  28. data/lib/rubocop/cop/style/access_modifier_indentation.rb +1 -1
  29. data/lib/rubocop/cop/style/align_hash.rb +1 -1
  30. data/lib/rubocop/cop/style/block_comments.rb +1 -3
  31. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +19 -10
  32. data/lib/rubocop/cop/style/closing_parenthesis_indentation.rb +1 -1
  33. data/lib/rubocop/cop/style/comment_annotation.rb +14 -14
  34. data/lib/rubocop/cop/style/comment_indentation.rb +1 -1
  35. data/lib/rubocop/cop/style/conditional_assignment.rb +25 -26
  36. data/lib/rubocop/cop/style/dot_position.rb +24 -19
  37. data/lib/rubocop/cop/style/each_for_simple_loop.rb +22 -8
  38. data/lib/rubocop/cop/style/each_with_object.rb +11 -1
  39. data/lib/rubocop/cop/style/else_alignment.rb +1 -1
  40. data/lib/rubocop/cop/style/empty_lines.rb +22 -11
  41. data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +9 -6
  42. data/lib/rubocop/cop/style/empty_lines_around_block_body.rb +14 -14
  43. data/lib/rubocop/cop/style/empty_lines_around_class_body.rb +8 -5
  44. data/lib/rubocop/cop/style/empty_lines_around_method_body.rb +12 -8
  45. data/lib/rubocop/cop/style/empty_lines_around_module_body.rb +17 -4
  46. data/lib/rubocop/cop/style/empty_literal.rb +12 -7
  47. data/lib/rubocop/cop/style/for.rb +1 -1
  48. data/lib/rubocop/cop/style/indent_array.rb +1 -1
  49. data/lib/rubocop/cop/style/indent_hash.rb +1 -1
  50. data/lib/rubocop/cop/style/indentation_width.rb +1 -1
  51. data/lib/rubocop/cop/style/initial_indentation.rb +1 -1
  52. data/lib/rubocop/cop/style/lambda.rb +2 -3
  53. data/lib/rubocop/cop/style/method_call_parentheses.rb +6 -4
  54. data/lib/rubocop/cop/style/method_missing.rb +74 -0
  55. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +1 -1
  56. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +1 -1
  57. data/lib/rubocop/cop/style/nested_modifier.rb +23 -13
  58. data/lib/rubocop/cop/style/next.rb +1 -1
  59. data/lib/rubocop/cop/style/numeric_predicate.rb +142 -0
  60. data/lib/rubocop/cop/style/op_method.rb +12 -4
  61. data/lib/rubocop/cop/style/parallel_assignment.rb +11 -3
  62. data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +9 -6
  63. data/lib/rubocop/cop/style/single_line_block_params.rb +3 -2
  64. data/lib/rubocop/cop/style/space_inside_block_braces.rb +1 -1
  65. data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +1 -1
  66. data/lib/rubocop/cop/style/symbol_array.rb +18 -10
  67. data/lib/rubocop/cop/style/ternary_parentheses.rb +94 -0
  68. data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -1
  69. data/lib/rubocop/cop/style/unneeded_percent_q.rb +12 -6
  70. data/lib/rubocop/cop/util.rb +1 -1
  71. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  72. data/lib/rubocop/cop/variable_force/locatable.rb +1 -1
  73. data/lib/rubocop/formatter/disabled_config_formatter.rb +18 -7
  74. data/lib/rubocop/formatter/html_formatter.rb +25 -11
  75. data/lib/rubocop/formatter/text_util.rb +1 -1
  76. data/lib/rubocop/node_pattern.rb +2 -0
  77. data/lib/rubocop/processed_source.rb +3 -0
  78. data/lib/rubocop/rake_task.rb +1 -1
  79. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  80. data/lib/rubocop/runner.rb +18 -7
  81. data/lib/rubocop/string_util.rb +2 -5
  82. data/lib/rubocop/version.rb +1 -1
  83. metadata +7 -3
@@ -27,7 +27,7 @@ module RuboCop
27
27
  configured_indentation_width + offset
28
28
  @column_delta = expected_column - actual_column
29
29
 
30
- if @column_delta == 0
30
+ if @column_delta.zero?
31
31
  # which column was actually used as 'base column' for indentation?
32
32
  # (not the column which we think should be the 'base column',
33
33
  # but the one which has actually been used for that purpose)
@@ -77,7 +77,7 @@ module RuboCop
77
77
  begins_its_line?(current.source_range)
78
78
  @column_delta = base_column - display_column(current.source_range)
79
79
 
80
- yield current if @column_delta != 0
80
+ yield current if @column_delta.nonzero?
81
81
  end
82
82
  prev_line = current.loc.line
83
83
  end
@@ -28,12 +28,10 @@ module RuboCop
28
28
  # the presence OR absence of an empty line
29
29
  # But if style is `no_empty_lines`, there must not be an empty line
30
30
  return unless body || style == :no_empty_lines
31
+ return if node.single_line?
31
32
 
32
- start_line = node.loc.keyword.line
33
- end_line = node.loc.end.line
34
- return if start_line == end_line
35
-
36
- check_source(start_line, end_line)
33
+ check_source(node.loc.expression.first_line,
34
+ node.loc.expression.last_line)
37
35
  end
38
36
 
39
37
  def check_source(start_line, end_line)
@@ -60,24 +60,24 @@ module RuboCop
60
60
  def handle_new_line(node)
61
61
  return unless closing_brace_on_same_line?(node)
62
62
 
63
- add_offense(node, :expression, self.class::ALWAYS_NEW_LINE_MESSAGE)
63
+ add_offense(node, :end, self.class::ALWAYS_NEW_LINE_MESSAGE)
64
64
  end
65
65
 
66
66
  def handle_same_line(node)
67
67
  return if closing_brace_on_same_line?(node)
68
68
 
69
- add_offense(node, :expression, self.class::ALWAYS_SAME_LINE_MESSAGE)
69
+ add_offense(node, :end, self.class::ALWAYS_SAME_LINE_MESSAGE)
70
70
  end
71
71
 
72
72
  def handle_symmetrical(node)
73
73
  if opening_brace_on_same_line?(node)
74
74
  return if closing_brace_on_same_line?(node)
75
75
 
76
- add_offense(node, :expression, self.class::SAME_LINE_MESSAGE)
76
+ add_offense(node, :end, self.class::SAME_LINE_MESSAGE)
77
77
  else
78
78
  return unless closing_brace_on_same_line?(node)
79
79
 
80
- add_offense(node, :expression, self.class::NEW_LINE_MESSAGE)
80
+ add_offense(node, :end, self.class::NEW_LINE_MESSAGE)
81
81
  end
82
82
  end
83
83
 
@@ -11,24 +11,39 @@ module RuboCop
11
11
 
12
12
  def investigate(processed_source)
13
13
  @processed_source = processed_source
14
+ each_extraneous_space(processed_source.tokens) do |kind, range|
15
+ add_offense(range, range, format(MSG, kind))
16
+ end
17
+ end
18
+
19
+ def autocorrect(range)
20
+ ->(corrector) { corrector.remove(range) }
21
+ end
22
+
23
+ private
24
+
25
+ def each_extraneous_space(tokens)
14
26
  brackets = Brackets.new(*specifics)
15
- processed_source.tokens.each_cons(2) do |t1, t2|
16
- next unless brackets.left_side?(t1) || brackets.right_side?(t2)
27
+ tokens.each_cons(2) do |t1, t2|
28
+ next unless matching_brackets?(brackets, t1, t2)
17
29
 
18
30
  # If the second token is a comment, that means that a line break
19
31
  # follows, and that the rules for space inside don't apply.
20
32
  next if t2.type == :tCOMMENT
21
33
  next unless t2.pos.line == t1.pos.line && space_between?(t1, t2)
22
34
 
23
- range = Parser::Source::Range.new(processed_source.buffer,
24
- t1.pos.end_pos,
25
- t2.pos.begin_pos)
26
- add_offense(range, range, format(MSG, brackets.kind))
35
+ yield brackets.kind, range_between_tokens(t1, t2)
27
36
  end
28
37
  end
29
38
 
30
- def autocorrect(range)
31
- ->(corrector) { corrector.remove(range) }
39
+ def matching_brackets?(brackets, t1, t2)
40
+ brackets.left_side?(t1) || brackets.right_side?(t2)
41
+ end
42
+
43
+ def range_between_tokens(t1, t2)
44
+ Parser::Source::Range.new(processed_source.buffer,
45
+ t1.pos.end_pos,
46
+ t2.pos.begin_pos)
32
47
  end
33
48
 
34
49
  # Wraps info about the brackets. Makes it easy to check whether a token
@@ -15,7 +15,7 @@ module RuboCop
15
15
 
16
16
  body_length = body_length(body)
17
17
 
18
- return false if body_length == 0
18
+ return false if body_length.zero?
19
19
  return false if cond.each_node.any?(&:lvasgn_type?)
20
20
  return false if body_has_comment?(body)
21
21
  return false if end_keyword_has_comment?(node)
@@ -92,15 +92,9 @@ module RuboCop
92
92
  # @return [Parser::Source::Range]
93
93
  # the range of the code that is highlighted
94
94
  def highlighted_area
95
- column_length = if location.first_line == location.last_line
96
- location.column_range.count
97
- else
98
- location.source_line.length - location.column
99
- end
100
-
101
- Parser::Source::Range.new(location.source_line,
102
- location.column,
103
- location.column + column_length)
95
+ Parser::Source::Range.new(source_line,
96
+ column,
97
+ column + column_length)
104
98
  end
105
99
 
106
100
  # @api private
@@ -120,6 +114,35 @@ module RuboCop
120
114
  location.column
121
115
  end
122
116
 
117
+ # @api private
118
+ def source_line
119
+ location.source_line
120
+ end
121
+
122
+ # @api private
123
+ def column_length
124
+ if first_line == last_line
125
+ column_range.count
126
+ else
127
+ source_line.length - column
128
+ end
129
+ end
130
+
131
+ # @api private
132
+ def first_line
133
+ location.first_line
134
+ end
135
+
136
+ # @api private
137
+ def last_line
138
+ location.last_line
139
+ end
140
+
141
+ # @api private
142
+ def column_range
143
+ location.column_range
144
+ end
145
+
123
146
  # @api private
124
147
  #
125
148
  # Internally we use column number that start at 0, but when
@@ -157,7 +180,7 @@ module RuboCop
157
180
  def <=>(other)
158
181
  COMPARISON_ATTRIBUTES.each do |attribute|
159
182
  result = send(attribute) <=> other.send(attribute)
160
- return result unless result == 0
183
+ return result unless result.zero?
161
184
  end
162
185
  0
163
186
  end
@@ -81,29 +81,31 @@ module RuboCop
81
81
  def autocorrect(node)
82
82
  *conditions, _body = *node
83
83
 
84
- new_condition =
85
- conditions.each_with_object([]) do |condition, correction|
86
- variable, = *condition
87
- if variable.respond_to?(:array_type?) && variable.array_type?
88
- correction << expand_percent_array(variable)
89
- next
90
- end
91
-
92
- correction << condition.source
93
- end
94
- new_condition = new_condition.join(', ')
95
-
96
84
  lambda do |corrector|
97
85
  if needs_reorder?(conditions)
98
- reorder_condition(corrector, node, new_condition)
86
+ reorder_condition(corrector, node, replacement(conditions))
99
87
  else
100
- inline_fix_branch(corrector, node, conditions, new_condition)
88
+ inline_fix_branch(corrector, node, conditions,
89
+ replacement(conditions))
101
90
  end
102
91
  end
103
92
  end
104
93
 
105
94
  private
106
95
 
96
+ def replacement(conditions)
97
+ new_condition = conditions.map do |condition|
98
+ variable, = *condition
99
+ if variable.respond_to?(:array_type?) && variable.array_type?
100
+ expand_percent_array(variable)
101
+ else
102
+ condition.source
103
+ end
104
+ end
105
+
106
+ new_condition.join(', ')
107
+ end
108
+
107
109
  def inline_fix_branch(corrector, node, conditions, new_condition)
108
110
  range =
109
111
  Parser::Source::Range.new(node.loc.expression.source_buffer,
@@ -89,7 +89,6 @@ module RuboCop
89
89
  arg.source if arg
90
90
  end
91
91
 
92
- # FIXME: use Range#size once Ruby 1.9 support is dropped
93
92
  def range_size(range_node)
94
93
  vals = *range_node
95
94
  return :unknown unless vals.all?(&:int_type?)
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module RuboCop
5
+ module Cop
6
+ module Rails
7
+ # This cop identifies possible cases where Active Record save! or related
8
+ # should be used instead of save because the model might have failed to
9
+ # save and an exception is better than unhandled failure.
10
+ #
11
+ # This will ignore calls that are assigned to a variable or used as the
12
+ # condition in an if/unless statement. It will also ignore any call with
13
+ # more than 2 arguments as that is likely not an Active Record call or
14
+ # if a Model.update(id, attributes) call.
15
+ #
16
+ # @example
17
+ #
18
+ # # bad
19
+ # user.save
20
+ # user.update(name: 'Joe')
21
+ # user.find_or_create_by(name: 'Joe')
22
+ # user.destroy
23
+ #
24
+ # # good
25
+ # unless user.save
26
+ # . . .
27
+ # end
28
+ # user.save!
29
+ # user.update!(name: 'Joe')
30
+ # user.find_or_create_by!(name: 'Joe')
31
+ # user.destroy!
32
+ class SaveBang < Cop
33
+ MSG = 'Use `%s` instead of `%s` if the return value is not checked.'
34
+ .freeze
35
+
36
+ PERSIST_METHODS = [:save, :create, :update, :destroy,
37
+ :first_or_create, :find_or_create_by].freeze
38
+
39
+ def on_send(node)
40
+ return unless PERSIST_METHODS.include?(node.method_name)
41
+ return if return_value_used?(node)
42
+ return unless expected_signature?(node)
43
+
44
+ add_offense(node, node.loc.selector,
45
+ format(MSG,
46
+ "#{node.method_name}!",
47
+ node.method_name.to_s))
48
+ end
49
+
50
+ def autocorrect(node)
51
+ save_loc = node.loc.selector
52
+ new_method = "#{node.method_name}!"
53
+
54
+ ->(corrector) { corrector.replace(save_loc, new_method) }
55
+ end
56
+
57
+ private
58
+
59
+ # Ignore simple assignment or if condition
60
+ def return_value_used?(node)
61
+ return false unless node.parent
62
+ node.parent.lvasgn_type? ||
63
+ (node.parent.if_type? && node.sibling_index.zero?)
64
+ end
65
+
66
+ # Check argument signature as no arguments or one hash
67
+ def expected_signature?(node)
68
+ node.method_args.empty? ||
69
+ (node.method_args.length == 1 &&
70
+ node.method_name != :destroy &&
71
+ (node.method_args.first.hash_type? ||
72
+ !node.method_args.first.literal?))
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -43,23 +43,23 @@ module RuboCop
43
43
  end
44
44
 
45
45
  def autocorrect(node)
46
- _receiver, method_name, *args = *node
47
- options = args.find { |arg| arg.type != :sym }
48
46
  lambda do |corrector|
49
- validate_type = method_name.to_s.split('_')[1]
50
47
  corrector.replace(node.loc.selector, 'validates')
51
- cop_config['AllowUnusedKeywordArguments']
52
- if options
53
- corrector.replace(
54
- options.loc.expression,
55
- "#{validate_type}: { #{options.source} }"
56
- )
57
- else
58
- corrector.insert_after(
59
- node.loc.expression,
60
- ", #{validate_type}: true"
61
- )
62
- end
48
+ correct_validate_type(corrector, node)
49
+ end
50
+ end
51
+
52
+ def correct_validate_type(corrector, node)
53
+ _receiver, method_name, *args = *node
54
+ options = args.find { |arg| arg.type != :sym }
55
+ validate_type = method_name.to_s.split('_')[1]
56
+
57
+ if options
58
+ corrector.replace(options.loc.expression,
59
+ "#{validate_type}: { #{options.source} }")
60
+ else
61
+ corrector.insert_after(node.loc.expression,
62
+ ", #{validate_type}: true")
63
63
  end
64
64
  end
65
65
  end
@@ -49,7 +49,7 @@ module RuboCop
49
49
  offset = access_modifier_start_col - class_start_col
50
50
 
51
51
  @column_delta = expected_indent_offset - offset
52
- if @column_delta == 0
52
+ if @column_delta.zero?
53
53
  correct_style_detected
54
54
  else
55
55
  add_offense(send_node, :expression) do
@@ -248,7 +248,7 @@ module RuboCop
248
248
  end
249
249
 
250
250
  def good_alignment?
251
- @column_deltas.values.compact.none? { |v| v != 0 }
251
+ @column_deltas.values.compact.all?(&:zero?)
252
252
  end
253
253
  end
254
254
  end
@@ -23,15 +23,13 @@ module RuboCop
23
23
 
24
24
  lambda do |corrector|
25
25
  corrector.remove(eq_begin)
26
- # rubocop:disable Style/ZeroLengthPredicate
27
- unless contents.length == 0
26
+ unless contents.length.zero?
28
27
  corrector.replace(contents,
29
28
  contents.source
30
29
  .gsub(/\A/, '# ')
31
30
  .gsub(/\n\n/, "\n#\n")
32
31
  .gsub(/\n(?=[^\z#])/, "\n# "))
33
32
  end
34
- # rubocop:enable Style/ZeroLengthPredicate
35
33
  corrector.remove(eq_end)
36
34
  end
37
35
  end
@@ -59,26 +59,21 @@ module RuboCop
59
59
  node = args.last
60
60
  lambda do |corrector|
61
61
  if braces?(node)
62
- remove_braces(corrector, node)
62
+ remove_braces_with_whitespace(corrector, node)
63
63
  else
64
64
  add_braces(corrector, node)
65
65
  end
66
66
  end
67
67
  end
68
68
 
69
- def remove_braces(corrector, node)
70
- comments = processed_source.comments
71
- right_brace_and_space = range_with_surrounding_space(node.loc.end,
72
- :left)
73
- right_brace_and_space =
74
- range_with_surrounding_comma(right_brace_and_space, :left)
69
+ def remove_braces_with_whitespace(corrector, node)
70
+ right_brace_and_space = right_brace_and_space(node.loc.end)
75
71
 
76
- if comments.any? { |c| c.loc.line == right_brace_and_space.line }
72
+ if comment_on_line?(right_brace_and_space.line)
77
73
  # Removing a line break between a comment and the closing
78
74
  # parenthesis would cause a syntax error, so we only remove the
79
75
  # braces in that case.
80
- corrector.remove(node.loc.begin)
81
- corrector.remove(node.loc.end)
76
+ remove_braces(corrector, node)
82
77
  else
83
78
  left_brace_and_space = range_with_surrounding_space(node.loc.begin,
84
79
  :right)
@@ -87,6 +82,20 @@ module RuboCop
87
82
  end
88
83
  end
89
84
 
85
+ def right_brace_and_space(loc_end)
86
+ brace_and_space = range_with_surrounding_space(loc_end, :left)
87
+ range_with_surrounding_comma(brace_and_space, :left)
88
+ end
89
+
90
+ def comment_on_line?(line)
91
+ processed_source.comments.any? { |c| c.loc.line == line }
92
+ end
93
+
94
+ def remove_braces(corrector, node)
95
+ corrector.remove(node.loc.begin)
96
+ corrector.remove(node.loc.end)
97
+ end
98
+
90
99
  def add_braces(corrector, node)
91
100
  corrector.insert_before(node.source_range, '{')
92
101
  corrector.insert_after(node.source_range, '}')