rubocop 0.26.1 → 0.27.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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -0
  3. data/.rubocop_todo.yml +10 -6
  4. data/.travis.yml +2 -0
  5. data/CHANGELOG.md +30 -0
  6. data/README.md +9 -2
  7. data/assets/logo.png +0 -0
  8. data/assets/output.html.erb +68 -65
  9. data/config/default.yml +42 -7
  10. data/config/disabled.yml +5 -0
  11. data/config/enabled.yml +32 -7
  12. data/lib/rubocop.rb +10 -2
  13. data/lib/rubocop/comment_config.rb +11 -17
  14. data/lib/rubocop/config.rb +20 -16
  15. data/lib/rubocop/config_loader.rb +8 -12
  16. data/lib/rubocop/cop/cop.rb +13 -12
  17. data/lib/rubocop/cop/lint/block_alignment.rb +4 -6
  18. data/lib/rubocop/cop/lint/def_end_alignment.rb +2 -2
  19. data/lib/rubocop/cop/lint/require_parentheses.rb +1 -1
  20. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -3
  21. data/lib/rubocop/cop/lint/useless_setter_call.rb +2 -2
  22. data/lib/rubocop/cop/metrics/abc_size.rb +27 -0
  23. data/lib/rubocop/cop/metrics/block_nesting.rb +2 -4
  24. data/lib/rubocop/cop/metrics/class_length.rb +1 -1
  25. data/lib/rubocop/cop/metrics/line_length.rb +2 -5
  26. data/lib/rubocop/cop/metrics/method_length.rb +2 -2
  27. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +24 -15
  28. data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +15 -2
  29. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +63 -0
  30. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -1
  31. data/lib/rubocop/cop/mixin/if_node.rb +3 -1
  32. data/lib/rubocop/cop/mixin/method_complexity.rb +3 -3
  33. data/lib/rubocop/cop/mixin/{on_method.rb → on_method_def.rb} +3 -3
  34. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +2 -2
  35. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  36. data/lib/rubocop/cop/mixin/statement_modifier.rb +2 -2
  37. data/lib/rubocop/cop/mixin/string_literals_help.rb +28 -0
  38. data/lib/rubocop/cop/rails/delegate.rb +2 -2
  39. data/lib/rubocop/cop/style/access_modifier_indentation.rb +2 -2
  40. data/lib/rubocop/cop/style/accessor_method_name.rb +2 -2
  41. data/lib/rubocop/cop/style/align_hash.rb +16 -12
  42. data/lib/rubocop/cop/style/align_parameters.rb +1 -1
  43. data/lib/rubocop/cop/style/and_or.rb +14 -6
  44. data/lib/rubocop/cop/style/array_join.rb +1 -1
  45. data/lib/rubocop/cop/style/block_comments.rb +16 -8
  46. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +6 -30
  47. data/lib/rubocop/cop/style/case_indentation.rb +20 -12
  48. data/lib/rubocop/cop/style/collection_methods.rb +4 -4
  49. data/lib/rubocop/cop/style/colon_method_call.rb +9 -0
  50. data/lib/rubocop/cop/style/comment_annotation.rb +1 -1
  51. data/lib/rubocop/cop/style/comment_indentation.rb +22 -22
  52. data/lib/rubocop/cop/style/def_with_parentheses.rb +2 -2
  53. data/lib/rubocop/cop/style/deprecated_hash_methods.rb +1 -1
  54. data/lib/rubocop/cop/style/double_negation.rb +6 -1
  55. data/lib/rubocop/cop/style/else_alignment.rb +93 -0
  56. data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -1
  57. data/lib/rubocop/cop/style/empty_lines.rb +1 -1
  58. data/lib/rubocop/cop/style/empty_lines_around_class_body.rb +34 -0
  59. data/lib/rubocop/cop/style/empty_lines_around_method_body.rb +37 -0
  60. data/lib/rubocop/cop/style/empty_lines_around_module_body.rb +30 -0
  61. data/lib/rubocop/cop/style/encoding.rb +1 -1
  62. data/lib/rubocop/cop/style/format_string.rb +4 -4
  63. data/lib/rubocop/cop/style/indent_array.rb +2 -2
  64. data/lib/rubocop/cop/style/indent_hash.rb +17 -12
  65. data/lib/rubocop/cop/style/indentation_width.rb +27 -19
  66. data/lib/rubocop/cop/style/method_call_parentheses.rb +3 -3
  67. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -1
  68. data/lib/rubocop/cop/style/method_def_parentheses.rb +17 -11
  69. data/lib/rubocop/cop/style/method_name.rb +1 -1
  70. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +174 -0
  71. data/lib/rubocop/cop/style/non_nil_check.rb +12 -15
  72. data/lib/rubocop/cop/style/not.rb +1 -1
  73. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +12 -17
  74. data/lib/rubocop/cop/style/percent_q_literals.rb +1 -1
  75. data/lib/rubocop/cop/style/predicate_name.rb +2 -2
  76. data/lib/rubocop/cop/style/redundant_begin.rb +2 -2
  77. data/lib/rubocop/cop/style/redundant_return.rb +3 -3
  78. data/lib/rubocop/cop/style/redundant_self.rb +3 -3
  79. data/lib/rubocop/cop/style/regexp_literal.rb +17 -13
  80. data/lib/rubocop/cop/style/rescue_modifier.rb +2 -2
  81. data/lib/rubocop/cop/style/single_line_methods.rb +7 -4
  82. data/lib/rubocop/cop/style/space_after_method_name.rb +2 -2
  83. data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +17 -11
  84. data/lib/rubocop/cop/style/space_before_block_braces.rb +1 -1
  85. data/lib/rubocop/cop/style/space_inside_block_braces.rb +17 -14
  86. data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +10 -6
  87. data/lib/rubocop/cop/style/string_literals.rb +13 -16
  88. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +41 -0
  89. data/lib/rubocop/cop/style/trailing_comma.rb +1 -3
  90. data/lib/rubocop/cop/style/trivial_accessors.rb +3 -3
  91. data/lib/rubocop/cop/style/unneeded_capital_w.rb +1 -1
  92. data/lib/rubocop/cop/style/unneeded_percent_q.rb +2 -2
  93. data/lib/rubocop/cop/style/word_array.rb +23 -19
  94. data/lib/rubocop/cop/team.rb +13 -26
  95. data/lib/rubocop/cop/util.rb +5 -0
  96. data/lib/rubocop/cop/variable_force/locatable.rb +7 -13
  97. data/lib/rubocop/formatter/disabled_config_formatter.rb +1 -1
  98. data/lib/rubocop/formatter/formatter_set.rb +9 -1
  99. data/lib/rubocop/formatter/html_formatter.rb +83 -55
  100. data/lib/rubocop/formatter/simple_text_formatter.rb +2 -2
  101. data/lib/rubocop/formatter/text_util.rb +25 -0
  102. data/lib/rubocop/options.rb +14 -7
  103. data/lib/rubocop/path_util.rb +11 -7
  104. data/lib/rubocop/runner.rb +7 -2
  105. data/lib/rubocop/version.rb +1 -1
  106. data/relnotes/v0.27.0.md +77 -0
  107. data/rubocop.gemspec +1 -1
  108. data/spec/fixtures/html_formatter/expected.html +495 -0
  109. data/spec/fixtures/html_formatter/project/app/controllers/application_controller.rb +5 -0
  110. data/spec/fixtures/html_formatter/project/app/controllers/books_controller.rb +74 -0
  111. data/spec/fixtures/html_formatter/project/app/models/book.rb +5 -0
  112. data/spec/rubocop/cli_spec.rb +56 -13
  113. data/spec/rubocop/cop/lint/invalid_character_literal_spec.rb +1 -1
  114. data/spec/rubocop/cop/metrics/abc_size_spec.rb +99 -0
  115. data/spec/rubocop/cop/rails/action_filter_spec.rb +1 -0
  116. data/spec/rubocop/cop/style/access_modifier_indentation_spec.rb +23 -1
  117. data/spec/rubocop/cop/style/align_hash_spec.rb +13 -0
  118. data/spec/rubocop/cop/style/align_parameters_spec.rb +44 -33
  119. data/spec/rubocop/cop/style/blocks_spec.rb +8 -0
  120. data/spec/rubocop/cop/style/braces_around_hash_parameters_spec.rb +9 -9
  121. data/spec/rubocop/cop/style/case_indentation_spec.rb +3 -2
  122. data/spec/rubocop/cop/style/colon_method_call_spec.rb +5 -0
  123. data/spec/rubocop/cop/style/comment_indentation_spec.rb +6 -1
  124. data/spec/rubocop/cop/style/else_alignment_spec.rb +437 -0
  125. data/spec/rubocop/cop/style/empty_lines_around_class_body_spec.rb +75 -0
  126. data/spec/rubocop/cop/style/{empty_lines_around_body_spec.rb → empty_lines_around_method_body_spec.rb} +9 -50
  127. data/spec/rubocop/cop/style/empty_lines_around_module_body_spec.rb +79 -0
  128. data/spec/rubocop/cop/style/file_name_spec.rb +1 -1
  129. data/spec/rubocop/cop/style/format_string_spec.rb +12 -0
  130. data/spec/rubocop/cop/style/indent_array_spec.rb +6 -1
  131. data/spec/rubocop/cop/style/indent_hash_spec.rb +2 -1
  132. data/spec/rubocop/cop/style/indentation_width_spec.rb +765 -722
  133. data/spec/rubocop/cop/style/multiline_operation_indentation_spec.rb +414 -0
  134. data/spec/rubocop/cop/style/non_nil_check_spec.rb +86 -55
  135. data/spec/rubocop/cop/style/single_line_methods_spec.rb +5 -1
  136. data/spec/rubocop/cop/style/space_before_block_braces_spec.rb +2 -1
  137. data/spec/rubocop/cop/style/space_inside_block_braces_spec.rb +2 -1
  138. data/spec/rubocop/cop/style/string_literals_in_interpolation_spec.rb +63 -0
  139. data/spec/rubocop/cop/style/string_literals_spec.rb +2 -2
  140. data/spec/rubocop/cop/style/word_array_spec.rb +15 -1
  141. data/spec/rubocop/formatter/base_formatter_spec.rb +1 -1
  142. data/spec/rubocop/formatter/disabled_lines_formatter_spec.rb +0 -1
  143. data/spec/rubocop/formatter/formatter_set_spec.rb +9 -0
  144. data/spec/rubocop/formatter/html_formatter_spec.rb +25 -122
  145. data/spec/rubocop/formatter/offense_count_formatter_spec.rb +0 -1
  146. data/spec/rubocop/runner_spec.rb +1 -1
  147. data/spec/spec_helper.rb +12 -130
  148. data/spec/support/cop_helper.rb +72 -0
  149. data/spec/support/coverage.rb +15 -0
  150. data/spec/support/{offenses_matcher.rb → custom_matchers.rb} +28 -0
  151. data/spec/support/jruby_workaround.rb +15 -0
  152. data/spec/support/{isolated_environment.rb → shared_contexts.rb} +19 -0
  153. metadata +49 -14
  154. data/lib/rubocop/cop/style/empty_lines_around_body.rb +0 -75
  155. data/spec/support/shared_context.rb +0 -20
@@ -11,7 +11,7 @@ module RuboCop
11
11
  def on_def(node)
12
12
  if @prev_def_end && (def_start(node) - @prev_def_end) == 1
13
13
  unless @prev_was_single_line && singe_line_def?(node) &&
14
- cop_config['AllowAdjacentOneLineDefs']
14
+ cop_config['AllowAdjacentOneLineDefs']
15
15
  add_offense(node, :keyword)
16
16
  end
17
17
  end
@@ -24,7 +24,7 @@ module RuboCop
24
24
  ((prev_line + 1)...cur_line).each do |line|
25
25
  # we check if the prev and current lines are empty
26
26
  next unless processed_source[line - 2].empty? &&
27
- processed_source[line - 1].empty?
27
+ processed_source[line - 1].empty?
28
28
 
29
29
  range = source_range(processed_source.buffer, line, 0)
30
30
  add_offense(range, range)
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cops checks if empty lines around the bodies of classes match the
7
+ # configuration.
8
+ #
9
+ # @example
10
+ #
11
+ # class Test
12
+ #
13
+ # def something
14
+ # ...
15
+ # end
16
+ #
17
+ # end
18
+ #
19
+ class EmptyLinesAroundClassBody < Cop
20
+ include EmptyLinesAroundBody
21
+
22
+ KIND = 'class'
23
+
24
+ def on_class(node)
25
+ check(node)
26
+ end
27
+
28
+ def on_sclass(node)
29
+ check(node)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cops checks if empty lines around the bodies of methods match
7
+ # the configuration.
8
+ #
9
+ # @example
10
+ #
11
+ # def something(arg)
12
+ #
13
+ # ...
14
+ # end
15
+ #
16
+ class EmptyLinesAroundMethodBody < Cop
17
+ include EmptyLinesAroundBody
18
+ include OnMethodDef
19
+
20
+ KIND = 'method'
21
+
22
+ private
23
+
24
+ def on_method_def(node, _method_name, _args, _body)
25
+ check(node)
26
+ end
27
+
28
+ # Override ConfigurableEnforcedStyle#style and hard-code
29
+ # configuration. It's difficult to imagine that anybody would want
30
+ # empty lines around a method body, so we don't make it configurable.
31
+ def style
32
+ :no_empty_lines
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cops checks if empty lines around the bodies of modules match
7
+ # the configuration.
8
+ #
9
+ # @example
10
+ #
11
+ # module Test
12
+ #
13
+ # def something
14
+ # ...
15
+ # end
16
+ #
17
+ # end
18
+ #
19
+ class EmptyLinesAroundModuleBody < Cop
20
+ include EmptyLinesAroundBody
21
+
22
+ KIND = 'module'
23
+
24
+ def on_module(node)
25
+ check(node)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -46,7 +46,7 @@ module RuboCop
46
46
 
47
47
  def encoding_line_number(processed_source)
48
48
  line_number = 0
49
- line_number += 1 if processed_source[line_number] =~ /^#!/
49
+ line_number += 1 if processed_source[line_number].start_with?('#!')
50
50
  line_number
51
51
  end
52
52
  end
@@ -33,11 +33,11 @@ module RuboCop
33
33
  def format_method?(name, node)
34
34
  receiver, method_name, args = *node
35
35
 
36
- # we do an argument count check to reduce false positives
37
- return false if args && args.children.size < 2
38
-
39
36
  # commands have no explicit receiver
40
- !receiver && method_name == name
37
+ return false unless !receiver && method_name == name
38
+
39
+ # we do an argument count check to reduce false positives
40
+ args && args.children.size >= 2
41
41
  end
42
42
 
43
43
  def format?(node)
@@ -28,13 +28,13 @@ module RuboCop
28
28
  return if expr.line == left_bracket.line
29
29
 
30
30
  base_column = left_bracket.source_line =~ /\S/
31
- expected_column = base_column + IndentationWidth::CORRECT_INDENTATION
31
+ expected_column = base_column + configured_indentation_width
32
32
  @column_delta = expected_column - expr.column
33
33
  return if @column_delta == 0
34
34
 
35
35
  msg = format('Use %d spaces for indentation in an array, relative ' \
36
36
  'to the start of the line where the left bracket is.',
37
- IndentationWidth::CORRECT_INDENTATION)
37
+ configured_indentation_width)
38
38
  add_offense(first_pair, :expression, msg)
39
39
  end
40
40
 
@@ -95,20 +95,26 @@ module RuboCop
95
95
  def check_first_pair(first_pair, left_brace, left_parenthesis, offset)
96
96
  column = first_pair.loc.expression.column
97
97
  expected_column = base_column(left_brace, left_parenthesis) +
98
- IndentationWidth::CORRECT_INDENTATION + offset
98
+ configured_indentation_width + offset
99
99
  @column_delta = expected_column - column
100
100
 
101
101
  if @column_delta == 0
102
102
  correct_style_detected
103
103
  else
104
- add_offense(first_pair, :expression,
105
- message(base_description(left_parenthesis))) do
106
- if column == unexpected_column(left_brace, left_parenthesis,
107
- offset)
108
- opposite_style_detected
109
- else
110
- unrecognized_style_detected
111
- end
104
+ incorrect_style_detected(column, offset, first_pair,
105
+ left_parenthesis, left_brace)
106
+ end
107
+ end
108
+
109
+ def incorrect_style_detected(column, offset, first_pair,
110
+ left_parenthesis, left_brace)
111
+ add_offense(first_pair, :expression,
112
+ message(base_description(left_parenthesis))) do
113
+ if column == unexpected_column(left_brace, left_parenthesis,
114
+ offset)
115
+ opposite_style_detected
116
+ else
117
+ unrecognized_style_detected
112
118
  end
113
119
  end
114
120
  end
@@ -146,13 +152,12 @@ module RuboCop
146
152
  end
147
153
  end
148
154
 
149
- unexpected_base_column + IndentationWidth::CORRECT_INDENTATION +
150
- offset
155
+ unexpected_base_column + configured_indentation_width + offset
151
156
  end
152
157
 
153
158
  def message(base_description)
154
159
  format('Use %d spaces for indentation in a hash, relative to %s.',
155
- IndentationWidth::CORRECT_INDENTATION, base_description)
160
+ configured_indentation_width, base_description)
156
161
  end
157
162
  end
158
163
  end
@@ -14,13 +14,11 @@ module RuboCop
14
14
  # end
15
15
  class IndentationWidth < Cop # rubocop:disable Metrics/ClassLength
16
16
  include AutocorrectAlignment
17
- include OnMethod
17
+ include OnMethodDef
18
18
  include CheckAssignment
19
19
  include IfNode
20
20
  include AccessModifierNode
21
21
 
22
- CORRECT_INDENTATION = 2
23
-
24
22
  def on_rescue(node)
25
23
  _begin_node, *rescue_nodes, else_node = *node
26
24
  rescue_nodes.each do |rescue_node|
@@ -72,7 +70,7 @@ module RuboCop
72
70
  ignore_node(args.first)
73
71
  end
74
72
 
75
- def on_method(node, _method_name, _args, body)
73
+ def on_method_def(node, _method_name, _args, body)
76
74
  check_indentation(node.loc.keyword, body) unless ignored_node?(node)
77
75
  end
78
76
 
@@ -84,7 +82,7 @@ module RuboCop
84
82
  def on_while(node, base = node)
85
83
  _condition, body = *node
86
84
  return unless node.loc.keyword.begin_pos ==
87
- node.loc.expression.begin_pos
85
+ node.loc.expression.begin_pos
88
86
 
89
87
  check_indentation(base.loc, body)
90
88
  end
@@ -175,20 +173,10 @@ module RuboCop
175
173
  end
176
174
 
177
175
  def check_indentation(base_loc, body_node)
178
- return unless body_node
179
-
180
- # Don't check if expression is on same line as "then" keyword, etc.
181
- return if body_node.loc.line == base_loc.line
182
-
183
- return if starts_with_access_modifier?(body_node)
184
-
185
- # Don't check indentation if the line doesn't start with the body.
186
- # For example, lines like "else do_something".
187
- first_char_pos_on_line = body_node.loc.expression.source_line =~ /\S/
188
- return unless body_node.loc.column == first_char_pos_on_line
176
+ return unless indentation_to_check?(base_loc, body_node)
189
177
 
190
178
  indentation = body_node.loc.column - base_loc.column
191
- @column_delta = CORRECT_INDENTATION - indentation
179
+ @column_delta = configured_indentation_width - indentation
192
180
  return if @column_delta == 0
193
181
 
194
182
  # This cop only auto-corrects the first statement in a def body, for
@@ -204,13 +192,33 @@ module RuboCop
204
192
 
205
193
  r = Parser::Source::Range.new(expr.source_buffer, pos.begin, pos.end)
206
194
  add_offense(body_node, r,
207
- format("Use #{CORRECT_INDENTATION} (not %d) spaces " \
208
- 'for indentation.', indentation))
195
+ format("Use #{configured_indentation_width} (not %d) " \
196
+ 'spaces for indentation.', indentation))
197
+ end
198
+
199
+ def indentation_to_check?(base_loc, body_node)
200
+ return false unless body_node
201
+
202
+ # Don't check if expression is on same line as "then" keyword, etc.
203
+ return false if body_node.loc.line == base_loc.line
204
+
205
+ return false if starts_with_access_modifier?(body_node)
206
+
207
+ # Don't check indentation if the line doesn't start with the body.
208
+ # For example, lines like "else do_something".
209
+ first_char_pos_on_line = body_node.loc.expression.source_line =~ /\S/
210
+ return false unless body_node.loc.column == first_char_pos_on_line
211
+
212
+ true
209
213
  end
210
214
 
211
215
  def starts_with_access_modifier?(body_node)
212
216
  body_node.type == :begin && modifier_node?(body_node.children.first)
213
217
  end
218
+
219
+ def configured_indentation_width
220
+ cop_config['Width']
221
+ end
214
222
  end
215
223
  end
216
224
  end
@@ -19,9 +19,9 @@ module RuboCop
19
19
  def autocorrect(node)
20
20
  # Bail out if the call is going to be auto-corrected by EmptyLiteral.
21
21
  if config.for_cop('Style/EmptyLiteral')['Enabled'] &&
22
- [EmptyLiteral::HASH_NODE,
23
- EmptyLiteral::ARRAY_NODE,
24
- EmptyLiteral::STR_NODE].include?(node)
22
+ [EmptyLiteral::HASH_NODE,
23
+ EmptyLiteral::ARRAY_NODE,
24
+ EmptyLiteral::STR_NODE].include?(node)
25
25
  return
26
26
  end
27
27
  @corrections << lambda do |corrector|
@@ -29,7 +29,7 @@ module RuboCop
29
29
  return if ignored_node?(node)
30
30
  receiver, _method_name, *_args = *node
31
31
  return unless receiver && receiver.type == :block &&
32
- receiver.loc.end.is?('end')
32
+ receiver.loc.end.is?('end')
33
33
 
34
34
  range = Parser::Source::Range.new(receiver.loc.end.source_buffer,
35
35
  receiver.loc.end.begin_pos,
@@ -6,25 +6,18 @@ module RuboCop
6
6
  # This cops checks for parentheses around the arguments in method
7
7
  # definitions. Both instance and class/singleton methods are checked.
8
8
  class MethodDefParentheses < Cop
9
- include OnMethod
9
+ include OnMethodDef
10
10
  include ConfigurableEnforcedStyle
11
11
 
12
- def on_method(node, _method_name, args, _body)
12
+ def on_method_def(node, _method_name, args, _body)
13
13
  if style == :require_parentheses
14
14
  if arguments?(args) && !parentheses?(args)
15
- add_offense(node,
16
- args.loc.expression,
17
- 'Use def with parentheses when there are ' \
18
- 'parameters.') do
19
- opposite_style_detected
20
- end
15
+ missing_parentheses(node, args)
21
16
  else
22
17
  correct_style_detected
23
18
  end
24
19
  elsif parentheses?(args)
25
- add_offense(args, :expression, 'Use def without parentheses.') do
26
- opposite_style_detected
27
- end
20
+ unwanted_parentheses(args)
28
21
  else
29
22
  correct_style_detected
30
23
  end
@@ -49,6 +42,19 @@ module RuboCop
49
42
 
50
43
  private
51
44
 
45
+ def missing_parentheses(node, args)
46
+ add_offense(node, args.loc.expression,
47
+ 'Use def with parentheses when there are parameters.') do
48
+ opposite_style_detected
49
+ end
50
+ end
51
+
52
+ def unwanted_parentheses(args)
53
+ add_offense(args, :expression, 'Use def without parentheses.') do
54
+ opposite_style_detected
55
+ end
56
+ end
57
+
52
58
  def args_node(def_node)
53
59
  if def_node.type == :def
54
60
  _method_name, args, _body = *def_node
@@ -20,7 +20,7 @@ module RuboCop
20
20
  end
21
21
 
22
22
  def message(style)
23
- format('Use %s for methods.', style)
23
+ format('Use %s for method names.', style)
24
24
  end
25
25
  end
26
26
  end
@@ -0,0 +1,174 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cops checks the indentation of the right hand side operand in
7
+ # binary operations that span more than one line.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # if a +
12
+ # b
13
+ # something
14
+ # end
15
+ class MultilineOperationIndentation < Cop
16
+ include ConfigurableEnforcedStyle
17
+ include AutocorrectAlignment
18
+
19
+ def on_and(node)
20
+ check_and_or(node)
21
+ end
22
+
23
+ def on_or(node)
24
+ check_and_or(node)
25
+ end
26
+
27
+ def on_send(node)
28
+ receiver, _method_name, *_args = *node
29
+ return unless receiver
30
+
31
+ lhs, rhs = left_hand_side(receiver), right_hand_side(node)
32
+ range = offending_range(node, lhs, rhs, style)
33
+ check(range, node, lhs, rhs)
34
+ end
35
+
36
+ private
37
+
38
+ def check_and_or(node)
39
+ lhs, rhs = *node
40
+ range = offending_range(node, lhs, rhs.loc.expression, style)
41
+ check(range, node, lhs, rhs.loc.expression)
42
+ end
43
+
44
+ def check(range, node, lhs, rhs)
45
+ if range
46
+ incorrect_style_detected(range, node, lhs, rhs)
47
+ else
48
+ correct_style_detected
49
+ end
50
+ end
51
+
52
+ def incorrect_style_detected(range, node, lhs, rhs)
53
+ add_offense(range, range, message(node, lhs, rhs)) do
54
+ unless offending_range(node, lhs, rhs, alternative_style)
55
+ opposite_style_detected
56
+ end
57
+ end
58
+ end
59
+
60
+ def offending_range(node, lhs, rhs, given_style)
61
+ return false unless begins_its_line?(rhs)
62
+ return false if lhs.loc.line == rhs.line # Needed for unary op.
63
+ return false if not_for_this_cop?(node)
64
+
65
+ correct_column = if should_align?(node, given_style)
66
+ lhs.loc.column
67
+ else
68
+ indentation(lhs) + correct_indentation(node)
69
+ end
70
+ @column_delta = correct_column - rhs.column
71
+ rhs if @column_delta != 0
72
+ end
73
+
74
+ def message(node, lhs, rhs)
75
+ what = operation_description(node)
76
+ if should_align?(node, style)
77
+ "Align the operands of #{what} spanning multiple lines."
78
+ else
79
+ used_indentation = rhs.column - indentation(lhs)
80
+ "Use #{correct_indentation(node)} (not #{used_indentation}) " \
81
+ "spaces for indenting #{what} spanning multiple lines."
82
+ end
83
+ end
84
+
85
+ def indentation(node)
86
+ node.loc.expression.source_line =~ /\S/
87
+ end
88
+
89
+ def operation_description(node)
90
+ ancestor = kw_node_with_special_indentation(node)
91
+ if ancestor
92
+ kw = ancestor.loc.keyword.source
93
+ kind = kw == 'for' ? 'collection' : 'condition'
94
+ article = kw =~ /^[iu]/ ? 'an' : 'a'
95
+ "a #{kind} in #{article} `#{kw}` statement"
96
+ else
97
+ 'an expression' + (assignment?(node) ? ' in an assignment' : '')
98
+ end
99
+ end
100
+
101
+ # In a chain of method calls, we regard the top send node as the base
102
+ # for indentation of all lines following the first. For example:
103
+ # a.
104
+ # b c { block }. <-- b is indented relative to a
105
+ # d <-- d is indented relative to a
106
+ def left_hand_side(receiver)
107
+ lhs = receiver
108
+ lhs = lhs.parent while lhs.parent && lhs.parent.type == :send
109
+ lhs
110
+ end
111
+
112
+ def right_hand_side(send_node)
113
+ _, method_name, *args = *send_node
114
+ if operator?(method_name) && args.any?
115
+ args.first.loc.expression
116
+ elsif send_node.loc.dot &&
117
+ send_node.loc.dot.line == send_node.loc.selector.line
118
+ send_node.loc.dot.join(send_node.loc.selector)
119
+ else
120
+ send_node.loc.selector
121
+ end
122
+ end
123
+
124
+ def correct_indentation(node)
125
+ multiplier = kw_node_with_special_indentation(node) ? 2 : 1
126
+ configured_indentation_width * multiplier
127
+ end
128
+
129
+ def should_align?(node, given_style)
130
+ given_style == :aligned && (kw_node_with_special_indentation(node) ||
131
+ assignment?(node))
132
+ end
133
+
134
+ def kw_node_with_special_indentation(node)
135
+ node.each_ancestor.find do |a|
136
+ next unless a.loc.respond_to?(:keyword)
137
+
138
+ case a.type
139
+ when :if, :while, :until then condition, = *a
140
+ when :for then _, collection, _ = *a
141
+ end
142
+
143
+ if condition || collection
144
+ within_node?(node, condition || collection)
145
+ end
146
+ end
147
+ end
148
+
149
+ def assignment?(node)
150
+ node.each_ancestor.find { |a| ASGN_NODES.include?(a.type) }
151
+ end
152
+
153
+ def not_for_this_cop?(node)
154
+ node.each_ancestor.find do |ancestor|
155
+ grouped_expression?(ancestor) ||
156
+ inside_arg_list_parentheses?(node, ancestor)
157
+ end
158
+ end
159
+
160
+ def grouped_expression?(node)
161
+ node.type == :begin && node.loc.respond_to?(:begin) && node.loc.begin
162
+ end
163
+
164
+ def inside_arg_list_parentheses?(node, ancestor)
165
+ a = ancestor.loc
166
+ return false unless ancestor.type == :send && a.begin &&
167
+ a.begin.is?('(')
168
+ n = node.loc.expression
169
+ n.begin_pos > a.begin.begin_pos && n.end_pos < a.end.end_pos
170
+ end
171
+ end
172
+ end
173
+ end
174
+ end