rubocop 0.60.0 → 0.61.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/config/default.yml +573 -560
  4. data/lib/rubocop.rb +5 -0
  5. data/lib/rubocop/ast/node.rb +1 -1
  6. data/lib/rubocop/ast/sexp.rb +1 -1
  7. data/lib/rubocop/cli.rb +9 -14
  8. data/lib/rubocop/config.rb +4 -3
  9. data/lib/rubocop/config_loader.rb +25 -22
  10. data/lib/rubocop/config_loader_resolver.rb +3 -2
  11. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +53 -0
  12. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +73 -0
  13. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +138 -0
  14. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +52 -46
  15. data/lib/rubocop/cop/generator.rb +13 -17
  16. data/lib/rubocop/cop/generator/configuration_injector.rb +60 -0
  17. data/lib/rubocop/cop/layout/align_hash.rb +3 -0
  18. data/lib/rubocop/cop/layout/comment_indentation.rb +32 -2
  19. data/lib/rubocop/cop/layout/indent_heredoc.rb +11 -5
  20. data/lib/rubocop/cop/layout/indentation_width.rb +7 -1
  21. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +11 -11
  22. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +1 -1
  23. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  24. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  25. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +16 -3
  26. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +30 -17
  27. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +11 -0
  28. data/lib/rubocop/cop/lint/shadowed_exception.rb +2 -5
  29. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
  30. data/lib/rubocop/cop/metrics/line_length.rb +2 -2
  31. data/lib/rubocop/cop/mixin/trailing_comma.rb +11 -15
  32. data/lib/rubocop/cop/offense.rb +1 -1
  33. data/lib/rubocop/cop/performance/open_struct.rb +46 -0
  34. data/lib/rubocop/cop/performance/redundant_merge.rb +18 -4
  35. data/lib/rubocop/cop/rails/bulk_change_table.rb +2 -2
  36. data/lib/rubocop/cop/rails/dynamic_find_by.rb +15 -8
  37. data/lib/rubocop/cop/rails/http_positional_arguments.rb +17 -14
  38. data/lib/rubocop/cop/rails/http_status.rb +4 -4
  39. data/lib/rubocop/cop/rails/inverse_of.rb +2 -2
  40. data/lib/rubocop/cop/rails/reversible_migration.rb +1 -1
  41. data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -1
  42. data/lib/rubocop/cop/rails/validation.rb +4 -4
  43. data/lib/rubocop/cop/security/open.rb +31 -11
  44. data/lib/rubocop/cop/style/begin_block.rb +6 -0
  45. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
  46. data/lib/rubocop/cop/style/empty_case_condition.rb +13 -7
  47. data/lib/rubocop/cop/style/for.rb +9 -78
  48. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +6 -4
  49. data/lib/rubocop/cop/style/global_vars.rb +1 -1
  50. data/lib/rubocop/cop/style/infinite_loop.rb +42 -6
  51. data/lib/rubocop/cop/style/lambda.rb +4 -87
  52. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +221 -16
  53. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  54. data/lib/rubocop/cop/style/regexp_literal.rb +62 -10
  55. data/lib/rubocop/cop/style/unneeded_condition.rb +2 -2
  56. data/lib/rubocop/cop/variable_force.rb +4 -2
  57. data/lib/rubocop/cop/variable_force/variable.rb +2 -0
  58. data/lib/rubocop/magic_comment.rb +1 -1
  59. data/lib/rubocop/remote_config.rb +13 -4
  60. data/lib/rubocop/rspec/expect_offense.rb +1 -1
  61. data/lib/rubocop/runner.rb +15 -4
  62. data/lib/rubocop/version.rb +1 -1
  63. metadata +7 -2
@@ -5,58 +5,64 @@ module RuboCop
5
5
  # Autocorrection logic for the closing brace of a literal either
6
6
  # on the same line as the last contained elements, or a new line.
7
7
  class MultilineLiteralBraceCorrector
8
- extend MultilineLiteralBraceLayout
9
- extend RangeHelp
10
-
11
- class << self
12
- attr_reader :processed_source
13
-
14
- # rubocop:disable Metrics/MethodLength
15
- def correct(processed_source, node)
16
- @processed_source = processed_source
17
- if closing_brace_on_same_line?(node)
18
- lambda do |corrector|
19
- corrector.insert_before(node.loc.end, "\n".freeze)
20
- end
21
- else
22
- # When a comment immediately before the closing brace gets in the
23
- # way of an easy correction, the offense is reported but not auto-
24
- # corrected. The user must handle the delicate decision of where to
25
- # put the comment.
26
- return if new_line_needed_before_closing_brace?(node)
27
-
28
- lambda do |corrector|
29
- corrector.remove(range_with_surrounding_space(range: node.loc.end,
30
- side: :left))
31
-
32
- corrector.insert_after(
33
- last_element_range_with_trailing_comma(node),
34
- node.loc.end.source
35
- )
36
- end
37
- end
38
- end
39
- # rubocop:enable Metrics/MethodLength
8
+ include MultilineLiteralBraceLayout
9
+ include RangeHelp
10
+
11
+ def initialize(node, processed_source)
12
+ @node = node
13
+ @processed_source = processed_source
14
+ end
40
15
 
41
- private
16
+ def call(corrector)
17
+ if closing_brace_on_same_line?(node)
18
+ correct_same_line_brace(corrector)
19
+ else
20
+ # When a comment immediately before the closing brace gets in the
21
+ # way of an easy correction, the offense is reported but not auto-
22
+ # corrected. The user must handle the delicate decision of where to
23
+ # put the comment.
24
+ return if new_line_needed_before_closing_brace?(node)
42
25
 
43
- def last_element_range_with_trailing_comma(node)
44
- trailing_comma_range = last_element_trailing_comma_range(node)
45
- if trailing_comma_range
46
- children(node).last.source_range.join(trailing_comma_range)
47
- else
48
- children(node).last.source_range
49
- end
26
+ correct_next_line_brace(corrector)
50
27
  end
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :node, :processed_source
33
+
34
+ def correct_same_line_brace(corrector)
35
+ corrector.insert_before(node.loc.end, "\n".freeze)
36
+ end
37
+
38
+ def correct_next_line_brace(corrector)
39
+ corrector.remove(
40
+ range_with_surrounding_space(range: node.loc.end, side: :left)
41
+ )
42
+
43
+ corrector.insert_after(
44
+ last_element_range_with_trailing_comma(node),
45
+ node.loc.end.source
46
+ )
47
+ end
51
48
 
52
- def last_element_trailing_comma_range(node)
53
- range = range_with_surrounding_space(
54
- range: children(node).last.source_range,
55
- side: :right
56
- ).end.resize(1)
57
- range.source == ',' ? range : nil
49
+ def last_element_range_with_trailing_comma(node)
50
+ trailing_comma_range = last_element_trailing_comma_range(node)
51
+ if trailing_comma_range
52
+ children(node).last.source_range.join(trailing_comma_range)
53
+ else
54
+ children(node).last.source_range
58
55
  end
59
56
  end
57
+
58
+ def last_element_trailing_comma_range(node)
59
+ range = range_with_surrounding_space(
60
+ range: children(node).last.source_range,
61
+ side: :right
62
+ ).end.resize(1)
63
+
64
+ range.source == ',' ? range : nil
65
+ end
60
66
  end
61
67
  end
62
68
  end
@@ -98,6 +98,11 @@ module RuboCop
98
98
  end
99
99
  SPEC
100
100
 
101
+ CONFIGURATION_ADDED_MESSAGE = <<-MESSAGE.strip_indent
102
+ [modify] A configuration for the cop is added into %<configuration_file_path>s.
103
+ If you want to disable the cop by default, set `Enabled` option to false.
104
+ MESSAGE
105
+
101
106
  def initialize(name, github_user, output: $stdout)
102
107
  @badge = Badge.parse(name)
103
108
  @github_user = github_user
@@ -123,24 +128,15 @@ module RuboCop
123
128
  end
124
129
 
125
130
  def inject_config(config_file_path: 'config/default.yml')
126
- config = File.readlines(config_file_path)
127
- content = <<-YAML.strip_indent
128
- #{badge}:
129
- Description: 'TODO: Write a description of the cop.'
130
- Enabled: true
131
- VersionAdded: #{bump_minor_version}
132
-
133
- YAML
134
- target_line = config.find.with_index(1) do |line, index|
135
- next if line =~ /^[\s#]/
136
- break index - 1 if badge.to_s < line
131
+ injector =
132
+ ConfigurationInjector.new(configuration_file_path: config_file_path,
133
+ badge: badge,
134
+ version_added: bump_minor_version)
135
+
136
+ injector.inject do
137
+ output.puts(format(CONFIGURATION_ADDED_MESSAGE,
138
+ configuration_file_path: config_file_path))
137
139
  end
138
- config.insert(target_line, content)
139
- File.write(config_file_path, config.join)
140
- output.puts <<-MESSAGE.strip_indent
141
- [modify] A configuration for the cop is added into #{config_file_path}.
142
- If you want to disable the cop by default, set `Enabled` option to false.
143
- MESSAGE
144
140
  end
145
141
 
146
142
  def todo
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ class Generator
6
+ # A class that injects a require directive into the root RuboCop file.
7
+ # It looks for other directives that require files in the same (cop)
8
+ # namespace and injects the provided one in alpha
9
+ class ConfigurationInjector
10
+ TEMPLATE = <<-YAML.strip_indent
11
+ %<badge>s:
12
+ Description: 'TODO: Write a description of the cop.'
13
+ Enabled: true
14
+ VersionAdded: '%<version_added>s'
15
+
16
+ YAML
17
+
18
+ def initialize(configuration_file_path:, badge:, version_added:)
19
+ @configuration_file_path = configuration_file_path
20
+ @badge = badge
21
+ @version_added = version_added
22
+ @output = output
23
+ end
24
+
25
+ def inject
26
+ configuration_entries.insert(find_target_line,
27
+ new_configuration_entry)
28
+
29
+ File.write(configuration_file_path, configuration_entries.join)
30
+
31
+ yield if block_given?
32
+ end
33
+
34
+ private
35
+
36
+ attr_reader :configuration_file_path, :badge, :version_added, :output
37
+
38
+ def configuration_entries
39
+ @configuration_entries ||= File.readlines(configuration_file_path)
40
+ end
41
+
42
+ def new_configuration_entry
43
+ format(TEMPLATE, badge: badge, version_added: version_added)
44
+ end
45
+
46
+ def find_target_line
47
+ configuration_entries.find.with_index do |line, index|
48
+ next if comment?(line)
49
+
50
+ break index if badge.to_s < line
51
+ end
52
+ end
53
+
54
+ def comment?(yaml)
55
+ yaml =~ /^[\s#]/
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -182,6 +182,7 @@ module RuboCop
182
182
 
183
183
  def on_send(node)
184
184
  return if double_splat?(node)
185
+ return unless node.arguments?
185
186
 
186
187
  last_argument = node.last_argument
187
188
 
@@ -190,6 +191,8 @@ module RuboCop
190
191
 
191
192
  ignore_node(last_argument)
192
193
  end
194
+ alias on_super on_send
195
+ alias on_yield on_send
193
196
 
194
197
  def on_hash(node)
195
198
  return if ignored_node?(node)
@@ -42,12 +42,42 @@ module RuboCop
42
42
  processed_source.each_comment { |comment| check(comment) }
43
43
  end
44
44
 
45
- def autocorrect(node)
46
- AlignmentCorrector.correct(processed_source, node, @column_delta)
45
+ def autocorrect(comment)
46
+ corrections = autocorrect_preceding_comments(comment) <<
47
+ autocorrect_one(comment)
48
+ ->(corrector) { corrections.each { |corr| corr.call(corrector) } }
47
49
  end
48
50
 
49
51
  private
50
52
 
53
+ # Corrects all comment lines that occur immediately before the given
54
+ # comment and have the same indentation. This is to avoid a long chain
55
+ # of correcting, saving the file, parsing and inspecting again, and
56
+ # then correcting one more line, and so on.
57
+ def autocorrect_preceding_comments(comment)
58
+ corrections = []
59
+ line_no = comment.loc.line
60
+ column = comment.loc.column
61
+ comments = processed_source.comments
62
+ (comments.index(comment) - 1).downto(0) do |ix|
63
+ previous_comment = comments[ix]
64
+ break unless should_correct?(previous_comment, column, line_no - 1)
65
+
66
+ corrections << autocorrect_one(previous_comment)
67
+ line_no -= 1
68
+ end
69
+ corrections
70
+ end
71
+
72
+ def should_correct?(comment, column, line_no)
73
+ loc = comment.loc
74
+ loc.line == line_no && loc.column == column
75
+ end
76
+
77
+ def autocorrect_one(comment)
78
+ AlignmentCorrector.correct(processed_source, comment, @column_delta)
79
+ end
80
+
51
81
  def check(comment)
52
82
  return unless own_line_comment?(comment)
53
83
 
@@ -99,7 +99,7 @@ module RuboCop
99
99
  return unless body_indent_level.zero?
100
100
  end
101
101
 
102
- return if too_long_line?(node)
102
+ return if line_too_long?(node)
103
103
 
104
104
  add_offense(node, location: :heredoc_body)
105
105
  end
@@ -173,8 +173,8 @@ module RuboCop
173
173
  )
174
174
  end
175
175
 
176
- def too_long_line?(node)
177
- return false if config.for_cop('Metrics/LineLength')['AllowHeredoc']
176
+ def line_too_long?(node)
177
+ return false if unlimited_heredoc_length?
178
178
 
179
179
  body = heredoc_body(node)
180
180
 
@@ -182,9 +182,15 @@ module RuboCop
182
182
  actual_indent = indent_level(body)
183
183
  increase_indent_level = expected_indent - actual_indent
184
184
 
185
- max_line = body.each_line.map { |line| line.chomp.size }.max
185
+ longest_line(body).size + increase_indent_level >= max_line_length
186
+ end
187
+
188
+ def longest_line(lines)
189
+ lines.each_line.max_by { |line| line.chomp.size }.chomp
190
+ end
186
191
 
187
- max_line + increase_indent_level >= max_line_length
192
+ def unlimited_heredoc_length?
193
+ config.for_cop('Metrics/LineLength')['AllowHeredoc']
188
194
  end
189
195
 
190
196
  def max_line_length
@@ -96,6 +96,12 @@ module RuboCop
96
96
  check_members(node.loc.keyword, members)
97
97
  end
98
98
 
99
+ def on_sclass(node)
100
+ _class_name, *members = *node
101
+
102
+ check_members(node.loc.keyword, members)
103
+ end
104
+
99
105
  def on_send(node)
100
106
  super
101
107
  return unless node.adjacent_def_modifier?
@@ -141,7 +147,7 @@ module RuboCop
141
147
  end
142
148
 
143
149
  def on_if(node, base = node)
144
- return if ignored_node?(node) || !node.body
150
+ return if ignored_node?(node)
145
151
  return if node.ternary? || node.modifier_form?
146
152
 
147
153
  check_if(node, node.body, node.else_branch, base.loc)
@@ -91,26 +91,26 @@ module RuboCop
91
91
  class MultilineArrayBraceLayout < Cop
92
92
  include MultilineLiteralBraceLayout
93
93
 
94
- SAME_LINE_MESSAGE = 'Closing array brace must be on the same line as ' \
95
- 'the last array element when opening brace is on the same line as ' \
96
- 'the first array element.'.freeze
94
+ SAME_LINE_MESSAGE = 'The closing array brace must be on the same ' \
95
+ 'line as the last array element when the opening brace is on the ' \
96
+ 'same line as the first array element.'.freeze
97
97
 
98
- NEW_LINE_MESSAGE = 'Closing array brace must be on the line after ' \
99
- 'the last array element when opening brace is on a separate line ' \
100
- 'from the first array element.'.freeze
98
+ NEW_LINE_MESSAGE = 'The closing array brace must be on the line ' \
99
+ 'after the last array element when the opening brace is on a ' \
100
+ 'separate line from the first array element.'.freeze
101
101
 
102
- ALWAYS_NEW_LINE_MESSAGE = 'Closing array brace must be on the line ' \
103
- 'after the last array element.'.freeze
102
+ ALWAYS_NEW_LINE_MESSAGE = 'The closing array brace must be on the ' \
103
+ 'line after the last array element.'.freeze
104
104
 
105
- ALWAYS_SAME_LINE_MESSAGE = 'Closing array brace must be on the same ' \
106
- 'line as the last array element.'.freeze
105
+ ALWAYS_SAME_LINE_MESSAGE = 'The closing array brace must be on the ' \
106
+ 'same line as the last array element.'.freeze
107
107
 
108
108
  def on_array(node)
109
109
  check_brace_layout(node)
110
110
  end
111
111
 
112
112
  def autocorrect(node)
113
- MultilineLiteralBraceCorrector.correct(processed_source, node)
113
+ MultilineLiteralBraceCorrector.new(node, processed_source)
114
114
  end
115
115
  end
116
116
  end
@@ -114,7 +114,7 @@ module RuboCop
114
114
  end
115
115
 
116
116
  def autocorrect(node)
117
- MultilineLiteralBraceCorrector.correct(processed_source, node)
117
+ MultilineLiteralBraceCorrector.new(node, processed_source)
118
118
  end
119
119
  end
120
120
  end
@@ -110,7 +110,7 @@ module RuboCop
110
110
  end
111
111
 
112
112
  def autocorrect(node)
113
- MultilineLiteralBraceCorrector.correct(processed_source, node)
113
+ MultilineLiteralBraceCorrector.new(node, processed_source)
114
114
  end
115
115
 
116
116
  private
@@ -123,7 +123,7 @@ module RuboCop
123
123
  alias on_defs on_def
124
124
 
125
125
  def autocorrect(node)
126
- MultilineLiteralBraceCorrector.correct(processed_source, node)
126
+ MultilineLiteralBraceCorrector.new(node, processed_source)
127
127
  end
128
128
  end
129
129
  end
@@ -28,8 +28,9 @@ module RuboCop
28
28
  'aligned with `%<beginning>s` at ' \
29
29
  '%<begin_loc_line>d, %<begin_loc_column>d.'.freeze
30
30
  ANCESTOR_TYPES = %i[kwbegin def defs class module].freeze
31
- RUBY_2_5_ANCESTOR_TYPES = (ANCESTOR_TYPES + [:block]).freeze
31
+ RUBY_2_5_ANCESTOR_TYPES = (ANCESTOR_TYPES + %i[block]).freeze
32
32
  ANCESTOR_TYPES_WITH_ACCESS_MODIFIERS = %i[def defs].freeze
33
+ ASSIGNMENT_TYPES = %i[lvasgn].freeze
33
34
 
34
35
  def on_resbody(node)
35
36
  check(node) unless modifier?(node)
@@ -115,10 +116,13 @@ module RuboCop
115
116
  ancestor_node = ancestor_node(node)
116
117
  return nil if ancestor_node.nil?
117
118
 
119
+ assignment_node = assignment_node(ancestor_node)
120
+ return assignment_node unless assignment_node.nil?
121
+
118
122
  access_modifier_node = access_modifier_node(ancestor_node)
119
- return ancestor_node if access_modifier_node.nil?
123
+ return access_modifier_node unless access_modifier_node.nil?
120
124
 
121
- access_modifier_node
125
+ ancestor_node
122
126
  end
123
127
 
124
128
  def ancestor_node(node)
@@ -132,6 +136,15 @@ module RuboCop
132
136
  node.each_ancestor(*ancestor_types).first
133
137
  end
134
138
 
139
+ def assignment_node(node)
140
+ assignment_node = node.ancestors.first
141
+ return nil unless
142
+ assignment_node &&
143
+ ASSIGNMENT_TYPES.include?(assignment_node.type)
144
+
145
+ assignment_node
146
+ end
147
+
135
148
  def access_modifier_node(node)
136
149
  return nil unless
137
150
  ANCESTOR_TYPES_WITH_ACCESS_MODIFIERS.include?(node.type)