rubocop 0.36.0 → 0.37.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 (111) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -2
  3. data/README.md +10 -1
  4. data/assets/output.html.erb +55 -1
  5. data/config/default.yml +9 -3
  6. data/config/disabled.yml +21 -0
  7. data/config/enabled.yml +11 -10
  8. data/lib/rubocop.rb +9 -2
  9. data/lib/rubocop/ast_node.rb +67 -19
  10. data/lib/rubocop/ast_node/builder.rb +1 -0
  11. data/lib/rubocop/ast_node/sexp.rb +1 -0
  12. data/lib/rubocop/ast_node/traversal.rb +171 -0
  13. data/lib/rubocop/cached_data.rb +4 -1
  14. data/lib/rubocop/cli.rb +1 -1
  15. data/lib/rubocop/config.rb +36 -20
  16. data/lib/rubocop/config_loader.rb +6 -5
  17. data/lib/rubocop/cop/commissioner.rb +27 -18
  18. data/lib/rubocop/cop/cop.rb +7 -6
  19. data/lib/rubocop/cop/lint/duplicated_key.rb +1 -8
  20. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +1 -1
  21. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +18 -1
  22. data/lib/rubocop/cop/lint/nested_method_definition.rb +5 -1
  23. data/lib/rubocop/cop/lint/unneeded_disable.rb +1 -1
  24. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +1 -0
  25. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +9 -2
  26. data/lib/rubocop/cop/mixin/check_assignment.rb +1 -1
  27. data/lib/rubocop/cop/mixin/classish_length.rb +3 -4
  28. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +8 -4
  29. data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
  30. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +2 -1
  31. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +35 -0
  32. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -1
  33. data/lib/rubocop/cop/mixin/min_body_length.rb +1 -1
  34. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +58 -0
  35. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  36. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  37. data/lib/rubocop/cop/mixin/trailing_comma.rb +3 -2
  38. data/lib/rubocop/cop/performance/case_when_splat.rb +7 -0
  39. data/lib/rubocop/cop/performance/casecmp.rb +56 -17
  40. data/lib/rubocop/cop/performance/redundant_block_call.rb +17 -3
  41. data/lib/rubocop/cop/performance/redundant_merge.rb +7 -1
  42. data/lib/rubocop/cop/performance/times_map.rb +3 -4
  43. data/lib/rubocop/cop/severity.rb +1 -1
  44. data/lib/rubocop/cop/style/align_hash.rb +1 -1
  45. data/lib/rubocop/cop/style/align_parameters.rb +1 -1
  46. data/lib/rubocop/cop/style/and_or.rb +1 -1
  47. data/lib/rubocop/cop/style/block_comments.rb +2 -0
  48. data/lib/rubocop/cop/style/conditional_assignment.rb +2 -0
  49. data/lib/rubocop/cop/style/copyright.rb +2 -2
  50. data/lib/rubocop/cop/style/documentation.rb +19 -29
  51. data/lib/rubocop/cop/style/each_with_object.rb +1 -1
  52. data/lib/rubocop/cop/style/else_alignment.rb +2 -2
  53. data/lib/rubocop/cop/style/encoding.rb +1 -1
  54. data/lib/rubocop/cop/style/first_parameter_indentation.rb +1 -1
  55. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +2 -12
  56. data/lib/rubocop/cop/style/guard_clause.rb +2 -1
  57. data/lib/rubocop/cop/style/if_unless_modifier.rb +1 -8
  58. data/lib/rubocop/cop/style/indent_assignment.rb +1 -1
  59. data/lib/rubocop/cop/style/indentation_width.rb +3 -7
  60. data/lib/rubocop/cop/style/method_call_parentheses.rb +2 -1
  61. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  62. data/lib/rubocop/cop/style/multiline_array_brace_layout.rb +3 -41
  63. data/lib/rubocop/cop/style/multiline_hash_brace_layout.rb +57 -0
  64. data/lib/rubocop/cop/style/multiline_method_call_brace_layout.rb +65 -0
  65. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +5 -4
  66. data/lib/rubocop/cop/style/multiline_method_definition_brace_layout.rb +62 -0
  67. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +9 -3
  68. data/lib/rubocop/cop/style/mutable_constant.rb +18 -3
  69. data/lib/rubocop/cop/style/nested_modifier.rb +5 -2
  70. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +2 -1
  71. data/lib/rubocop/cop/style/next.rb +32 -11
  72. data/lib/rubocop/cop/style/option_hash.rb +1 -1
  73. data/lib/rubocop/cop/style/redundant_freeze.rb +13 -3
  74. data/lib/rubocop/cop/style/redundant_parentheses.rb +33 -7
  75. data/lib/rubocop/cop/style/send.rb +1 -1
  76. data/lib/rubocop/cop/style/space_around_keyword.rb +198 -0
  77. data/lib/rubocop/cop/style/space_around_operators.rb +2 -12
  78. data/lib/rubocop/cop/style/space_inside_block_braces.rb +1 -1
  79. data/lib/rubocop/cop/style/special_global_vars.rb +4 -4
  80. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  81. data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -1
  82. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +1 -0
  83. data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +1 -0
  84. data/lib/rubocop/cop/style/trivial_accessors.rb +1 -1
  85. data/lib/rubocop/cop/style/zero_length_predicate.rb +55 -0
  86. data/lib/rubocop/cop/team.rb +30 -5
  87. data/lib/rubocop/cop/util.rb +16 -1
  88. data/lib/rubocop/cop/variable_force.rb +3 -12
  89. data/lib/rubocop/cop/variable_force/assignment.rb +3 -3
  90. data/lib/rubocop/cop/variable_force/locatable.rb +25 -6
  91. data/lib/rubocop/cop/variable_force/reference.rb +3 -3
  92. data/lib/rubocop/cop/variable_force/scope.rb +8 -7
  93. data/lib/rubocop/cop/variable_force/variable.rb +3 -3
  94. data/lib/rubocop/cop/variable_force/variable_table.rb +1 -1
  95. data/lib/rubocop/formatter/formatter_set.rb +2 -2
  96. data/lib/rubocop/node_pattern.rb +1 -1
  97. data/lib/rubocop/options.rb +10 -10
  98. data/lib/rubocop/path_util.rb +5 -0
  99. data/lib/rubocop/processed_source.rb +8 -2
  100. data/lib/rubocop/result_cache.rb +1 -1
  101. data/lib/rubocop/runner.rb +1 -1
  102. data/lib/rubocop/token.rb +2 -2
  103. data/lib/rubocop/version.rb +1 -1
  104. data/relnotes/v0.30.1.md +1 -0
  105. data/relnotes/v0.33.0.md +1 -1
  106. data/relnotes/v0.36.0.md +2 -1
  107. data/relnotes/v0.37.0.md +200 -0
  108. data/rubocop.gemspec +2 -1
  109. metadata +28 -7
  110. data/lib/rubocop/cop/style/space_after_control_keyword.rb +0 -35
  111. data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +0 -38
@@ -56,14 +56,6 @@ module RuboCop
56
56
 
57
57
  SEND_TYPE = :send
58
58
 
59
- def self.wrap_with_top_level_scope_node(root_node)
60
- if root_node.begin_type?
61
- root_node
62
- else
63
- Node.new(:begin, [root_node])
64
- end
65
- end
66
-
67
59
  def variable_table
68
60
  @variable_table ||= VariableTable.new(self)
69
61
  end
@@ -73,10 +65,9 @@ module RuboCop
73
65
  root_node = processed_source.ast
74
66
  return unless root_node
75
67
 
76
- # Wrap the root node with begin node if it's a standalone node.
77
- root_node = self.class.wrap_with_top_level_scope_node(root_node)
78
-
79
- inspect_variables_in_scope(root_node)
68
+ variable_table.push_scope(root_node)
69
+ process_node(root_node)
70
+ variable_table.pop_scope
80
71
  end
81
72
 
82
73
  # This is called for each scope recursively.
@@ -16,9 +16,9 @@ module RuboCop
16
16
 
17
17
  def initialize(node, variable)
18
18
  unless VARIABLE_ASSIGNMENT_TYPES.include?(node.type)
19
- fail ArgumentError,
20
- "Node type must be any of #{VARIABLE_ASSIGNMENT_TYPES}, " \
21
- "passed #{node.type}"
19
+ raise ArgumentError,
20
+ "Node type must be any of #{VARIABLE_ASSIGNMENT_TYPES}, " \
21
+ "passed #{node.type}"
22
22
  end
23
23
 
24
24
  @node = node
@@ -16,12 +16,18 @@ module RuboCop
16
16
  ENSURE_TYPE = :ensure
17
17
  ENSURE_INDEX_OF_ENSURE_NODE = 1
18
18
 
19
+ FOR_LOOP_TYPE = :for
20
+ FOR_LOOP_CHILD_INDEX = 2
21
+
22
+ NON_FOR_LOOP_TYPES = LOOP_TYPES - [FOR_LOOP_TYPE]
23
+ NON_FOR_LOOP_TYPES_CHILD_INDEX = 1
24
+
19
25
  def node
20
- fail '#node must be declared!'
26
+ raise '#node must be declared!'
21
27
  end
22
28
 
23
29
  def scope
24
- fail '#scope must be declared!'
30
+ raise '#scope must be declared!'
25
31
  end
26
32
 
27
33
  def inside_of_branch?
@@ -84,7 +90,8 @@ module RuboCop
84
90
  when RESCUE_TYPE then rescue_body_name
85
91
  when ENSURE_TYPE then ensure_body_name
86
92
  when *LOGICAL_OPERATOR_TYPES then logical_operator_body_name
87
- else fail InvalidBranchBodyError
93
+ when *LOOP_TYPES then loop_body_name
94
+ else raise InvalidBranchBodyError
88
95
  end
89
96
  rescue InvalidBranchBodyError
90
97
  raise InvalidBranchBodyError,
@@ -97,7 +104,7 @@ module RuboCop
97
104
  case body_index
98
105
  when 1 then 'true'
99
106
  when 2 then 'false'
100
- else fail InvalidBranchBodyError
107
+ else raise InvalidBranchBodyError
101
108
  end
102
109
  end
103
110
 
@@ -112,7 +119,7 @@ module RuboCop
112
119
  def logical_operator_body_name
113
120
  case body_index
114
121
  when 1 then 'right'
115
- else fail InvalidBranchBodyError
122
+ else raise InvalidBranchBodyError
116
123
  end
117
124
  end
118
125
 
@@ -129,10 +136,18 @@ module RuboCop
129
136
  def ensure_body_name
130
137
  case body_index
131
138
  when 0 then 'main'
132
- else fail InvalidBranchBodyError
139
+ else raise InvalidBranchBodyError
133
140
  end
134
141
  end
135
142
 
143
+ def loop_body_name
144
+ loop_indices = [FOR_LOOP_CHILD_INDEX, NON_FOR_LOOP_TYPES_CHILD_INDEX]
145
+
146
+ raise InvalidBranchBodyError unless loop_indices.include?(body_index)
147
+
148
+ 'main'
149
+ end
150
+
136
151
  def body_index
137
152
  branch_point_node.children.index { |n| n.equal?(branch_body_node) }
138
153
  end
@@ -162,10 +177,14 @@ module RuboCop
162
177
  true
163
178
  when ENSURE_TYPE
164
179
  child_index != ENSURE_INDEX_OF_ENSURE_NODE
180
+ when FOR_LOOP_TYPE
181
+ child_index == FOR_LOOP_CHILD_INDEX
165
182
  when *BRANCH_TYPES
166
183
  child_index != CONDITION_INDEX_OF_BRANCH_NODE
167
184
  when *LOGICAL_OPERATOR_TYPES
168
185
  child_index != LEFT_SIDE_INDEX_OF_LOGICAL_OPERATOR_NODE
186
+ when *NON_FOR_LOOP_TYPES
187
+ child_index == NON_FOR_LOOP_TYPES_CHILD_INDEX
169
188
  else
170
189
  false
171
190
  end
@@ -18,9 +18,9 @@ module RuboCop
18
18
 
19
19
  def initialize(node, scope)
20
20
  unless VARIABLE_REFERENCE_TYPES.include?(node.type)
21
- fail ArgumentError,
22
- "Node type must be any of #{VARIABLE_REFERENCE_TYPES}, " \
23
- "passed #{node.type}"
21
+ raise ArgumentError,
22
+ "Node type must be any of #{VARIABLE_REFERENCE_TYPES}, " \
23
+ "passed #{node.type}"
24
24
  end
25
25
 
26
26
  @node = node
@@ -19,11 +19,11 @@ module RuboCop
19
19
  attr_reader :node, :variables
20
20
 
21
21
  def initialize(node)
22
- # Accept begin node for top level scope.
23
- unless SCOPE_TYPES.include?(node.type) || node.type == :begin
24
- fail ArgumentError,
25
- "Node type must be any of #{SCOPE_TYPES}, " \
26
- "passed #{node.type}"
22
+ # Accept any node type for top level scope
23
+ unless SCOPE_TYPES.include?(node.type) || !node.parent
24
+ raise ArgumentError,
25
+ "Node type must be any of #{SCOPE_TYPES}, " \
26
+ "passed #{node.type}"
27
27
  end
28
28
  @node = node
29
29
  @variables = {}
@@ -43,13 +43,12 @@ module RuboCop
43
43
 
44
44
  def body_node
45
45
  child_index = case @node.type
46
- when :begin then 0
47
46
  when :module, :sclass then 1
48
47
  when :def, :class, :block then 2
49
48
  when :defs then 3
50
49
  end
51
50
 
52
- @node.children[child_index]
51
+ child_index ? @node.children[child_index] : @node
53
52
  end
54
53
 
55
54
  def each_node(&block)
@@ -60,6 +59,8 @@ module RuboCop
60
59
  private
61
60
 
62
61
  def scan_node(node, &block)
62
+ yield node unless node.parent
63
+
63
64
  node.each_child_node do |child_node|
64
65
  next if belong_to_another_scope?(child_node)
65
66
  yield child_node
@@ -17,9 +17,9 @@ module RuboCop
17
17
 
18
18
  def initialize(name, declaration_node, scope)
19
19
  unless VARIABLE_DECLARATION_TYPES.include?(declaration_node.type)
20
- fail ArgumentError,
21
- "Node type must be any of #{VARIABLE_DECLARATION_TYPES}, " \
22
- "passed #{declaration_node.type}"
20
+ raise ArgumentError,
21
+ "Node type must be any of #{VARIABLE_DECLARATION_TYPES}, " \
22
+ "passed #{declaration_node.type}"
23
23
  end
24
24
 
25
25
  @name = name.to_sym
@@ -58,7 +58,7 @@ module RuboCop
58
58
  variable = find_variable(name)
59
59
 
60
60
  unless variable
61
- fail "Assigning to undeclared local variable \"#{name}\" " \
61
+ raise "Assigning to undeclared local variable \"#{name}\" " \
62
62
  "at #{node.source_range}, #{node.inspect}"
63
63
  end
64
64
 
@@ -81,9 +81,9 @@ module RuboCop
81
81
  end
82
82
 
83
83
  if matching_keys.empty?
84
- fail %(No formatter for "#{specified_key}")
84
+ raise %(No formatter for "#{specified_key}")
85
85
  elsif matching_keys.size > 1
86
- fail %(Cannot determine formatter for "#{specified_key}")
86
+ raise %(Cannot determine formatter for "#{specified_key}")
87
87
  end
88
88
 
89
89
  BUILTIN_FORMATTERS_FOR_KEYS[matching_keys.first]
@@ -407,7 +407,7 @@ module RuboCop
407
407
  end
408
408
 
409
409
  def fail_due_to(message)
410
- fail Invalid, "Couldn't compile due to #{message}. Pattern: #{@string}"
410
+ raise Invalid, "Couldn't compile due to #{message}. Pattern: #{@string}"
411
411
  end
412
412
  end
413
413
 
@@ -23,7 +23,7 @@ module RuboCop
23
23
  @validator.validate_compatibility
24
24
 
25
25
  if @options[:stdin] && !args.one?
26
- fail ArgumentError, '-s/--stdin requires exactly one path.'
26
+ raise ArgumentError, '-s/--stdin requires exactly one path.'
27
27
  end
28
28
 
29
29
  [@options, args]
@@ -170,7 +170,7 @@ module RuboCop
170
170
  next if namespaces.include?(name)
171
171
  next if %w(Syntax Lint/Syntax).include?(name)
172
172
 
173
- fail ArgumentError, "Unrecognized cop or namespace: #{name}."
173
+ raise ArgumentError, "Unrecognized cop or namespace: #{name}."
174
174
  end
175
175
  end
176
176
 
@@ -181,36 +181,36 @@ module RuboCop
181
181
  def validate_compatibility
182
182
  if @options.key?(:only) &&
183
183
  (@options[:only] & %w(Lint/UnneededDisable UnneededDisable)).any?
184
- fail ArgumentError, 'Lint/UnneededDisable can not be used with --only.'
184
+ raise ArgumentError, 'Lint/UnneededDisable can not be used with --only.'
185
185
  end
186
186
  if @options.key?(:except) &&
187
187
  (@options[:except] & %w(Lint/Syntax Syntax)).any?
188
- fail ArgumentError, 'Syntax checking can not be turned off.'
188
+ raise ArgumentError, 'Syntax checking can not be turned off.'
189
189
  end
190
190
  if @options.key?(:cache) && !%w(true false).include?(@options[:cache])
191
- fail ArgumentError, '-C/--cache argument must be true or false'
191
+ raise ArgumentError, '-C/--cache argument must be true or false'
192
192
  end
193
193
  if @options.key?(:no_offense_counts) && !@options.key?(:auto_gen_config)
194
- fail ArgumentError, '--no-offense-counts can only be used together ' \
194
+ raise ArgumentError, '--no-offense-counts can only be used together ' \
195
195
  'with --auto-gen-config.'
196
196
  end
197
197
  return if (incompat = @options.keys & Options::EXITING_OPTIONS).size <= 1
198
- fail ArgumentError, "Incompatible cli options: #{incompat.inspect}"
198
+ raise ArgumentError, "Incompatible cli options: #{incompat.inspect}"
199
199
  end
200
200
 
201
201
  def validate_exclude_limit_option(args)
202
202
  if @options[:exclude_limit] !~ /^\d+$/
203
203
  # Emulate OptionParser's behavior to make failures consistent regardless
204
204
  # of option order.
205
- fail OptionParser::MissingArgument
205
+ raise OptionParser::MissingArgument
206
206
  end
207
207
 
208
208
  # --exclude-limit is valid if there's a parsed or yet unparsed
209
209
  # --auto-gen-config.
210
210
  return if @options[:auto_gen_config] || args.include?('--auto-gen-config')
211
211
 
212
- fail ArgumentError,
213
- '--exclude-limit can only be used with --auto-gen-config.'
212
+ raise ArgumentError,
213
+ '--exclude-limit can only be used with --auto-gen-config.'
214
214
  end
215
215
  end
216
216
 
@@ -55,5 +55,10 @@ module RuboCop
55
55
  def hidden?(path_component)
56
56
  path_component =~ /^\.[^.]/
57
57
  end
58
+
59
+ # Returns true for an absolute Unix or Windows path.
60
+ def absolute?(path)
61
+ path =~ %r{\A([A-Z]:)?/}
62
+ end
58
63
  end
59
64
  end
@@ -44,11 +44,16 @@ module RuboCop
44
44
  comment_config.cop_disabled_line_ranges
45
45
  end
46
46
 
47
+ def ast_with_comments
48
+ return if !ast || !comments
49
+ @ast_with_comments ||= Parser::Source::Comment.associate(ast, comments)
50
+ end
51
+
47
52
  # Returns the source lines, line break characters removed, excluding a
48
53
  # possible __END__ and everything that comes after.
49
54
  def lines
50
55
  @lines ||= begin
51
- all_lines = raw_source.lines.map(&:chomp)
56
+ all_lines = @buffer.source_lines
52
57
  last_token_line = tokens.any? ? tokens.last.pos.line : all_lines.size
53
58
  result = []
54
59
  all_lines.each_with_index do |line, ix|
@@ -90,6 +95,7 @@ module RuboCop
90
95
 
91
96
  begin
92
97
  @ast, @comments, tokens = parser.tokenize(@buffer)
98
+ @ast.complete! if @ast
93
99
  rescue Parser::SyntaxError # rubocop:disable Lint/HandleExceptions
94
100
  # All errors are in diagnostics. No need to handle exception.
95
101
  end
@@ -115,7 +121,7 @@ module RuboCop
115
121
  require 'parser/ruby23'
116
122
  Parser::Ruby23
117
123
  else
118
- fail ArgumentError, "Unknown Ruby version: #{ruby_version.inspect}"
124
+ raise ArgumentError, "Unknown Ruby version: #{ruby_version.inspect}"
119
125
  end
120
126
  end
121
127
 
@@ -56,7 +56,7 @@ module RuboCop
56
56
 
57
57
  def initialize(file, options, config_store, cache_root = nil)
58
58
  cache_root ||= ResultCache.cache_root(config_store)
59
- @path = File.join(cache_root, rubocop_checksum, RUBY_VERSION,
59
+ @path = File.join(cache_root, rubocop_checksum,
60
60
  relevant_options(options),
61
61
  file_checksum(file, config_store))
62
62
  @cached_data = CachedData.new(file)
@@ -181,7 +181,7 @@ module RuboCop
181
181
  checksum = processed_source.checksum
182
182
 
183
183
  if @processed_sources.include?(checksum)
184
- fail InfiniteCorrectionLoop.new(processed_source.path, offenses)
184
+ raise InfiniteCorrectionLoop.new(processed_source.path, offenses)
185
185
  end
186
186
 
187
187
  @processed_sources << checksum
@@ -7,8 +7,8 @@ module RuboCop
7
7
  attr_reader :pos, :type, :text
8
8
 
9
9
  def self.from_parser_token(parser_token)
10
- type, details = *parser_token
11
- text, range = *details
10
+ type, details = parser_token
11
+ text, range = details
12
12
  new(range, type, text)
13
13
  end
14
14
 
@@ -4,7 +4,7 @@
4
4
  module RuboCop
5
5
  # This module holds the RuboCop version information.
6
6
  module Version
7
- STRING = '0.36.0'.freeze
7
+ STRING = '0.37.0'.freeze
8
8
 
9
9
  MSG = '%s (using Parser %s, running on %s %s %s)'.freeze
10
10
 
@@ -14,6 +14,7 @@ Enjoy all those bug-fixes!
14
14
  * [#1806](https://github.com/bbatsov/rubocop/issues/1806): Require a newer version of `parser` and use its corrected solution for comment association in `Style/Documentation`. ([@jonas054][])
15
15
  * [#1792](https://github.com/bbatsov/rubocop/issues/1792): Fix bugs in `Sample` that did not account for array selectors with a range and passing random to shuffle. ([@rrosenblum][])
16
16
  * [#1770](https://github.com/bbatsov/rubocop/pull/1770): Add more acceptable methods to `Rails/TimeZone` (`utc`, `localtime`, `to_i`, `iso8601` etc). ([@palkan][])
17
+ * [#1767](https://github.com/bbatsov/rubocop/pull/1767): Do not register offenses on non-enumerable select/find_all by `Performance/Detect`. ([@palkan][])
17
18
  * [#1795](https://github.com/bbatsov/rubocop/pull/1795): Fix bug in `TrailingBlankLines` that caused a crash for files containing only newlines. ([@renuo][])
18
19
 
19
20
  [@bbatsov]: https://github.com/bbatsov
@@ -12,7 +12,7 @@
12
12
  * [#2060](https://github.com/bbatsov/rubocop/issues/2060): New cop `Style/RescueEnsureAlignment` checks for bad alignment of `rescue` and `ensure` keywords. ([@lumeet][])
13
13
  * New cop `Style/OptionalArguments` checks for optional arguments that do not appear at the end of an argument list. ([@rrosenblum][])
14
14
  * New cop `Lint/CircularArgumentReference` checks for "circular argument references" in keyword arguments, which Ruby 2.2 warns against. ([@maxjacobson][], [@sliuu][])
15
- * [#2030](https://github.com/bbatsov/rubocop/issues/2030): New cop `Lint/OptionHash` checks for option hashes and encourages changing them to keyword arguments (disabled by default). ([@maxjacobson][])
15
+ * [#2030](https://github.com/bbatsov/rubocop/issues/2030): New cop `Style/OptionHash` checks for option hashes and encourages changing them to keyword arguments (disabled by default). ([@maxjacobson][])
16
16
 
17
17
  ### Changes
18
18
 
@@ -2,7 +2,7 @@ An epic release - the one which contains the most new features and
2
2
  bugfixes since the inception of the project! A huge thanks to the
3
3
  amazing contributors who helped make it a reality!
4
4
 
5
- Notabley, this release adds support for Ruby 2.3 and introduces the
5
+ Notably, this release adds support for Ruby 2.3 and introduces the
6
6
  important concept of a target Ruby version - meaning RuboCop will no
7
7
  longer try to parse the code with a parser matching the interpreter
8
8
  you're using, but a parser matching the target Ruby version you
@@ -17,6 +17,7 @@ Enjoy!
17
17
  * [#2598](https://github.com/bbatsov/rubocop/pull/2598): New cop `Lint/RandOne` checks for `rand(1)`, `Kernel.rand(1.0)` and similar calls. Such call are most likely a mistake because they always return `0`. ([@DNNX][])
18
18
  * [#2590](https://github.com/bbatsov/rubocop/pull/2590): New cop `Performance/DoubleStartEndWith` checks for two `start_with?` (or `end_with?`) calls joined by `||` with the same receiver, like `str.start_with?('x') || str.start_with?('y')` and suggests using one call instead: `str.start_with?('x', 'y')`. ([@DNNX][])
19
19
  * [#2583](https://github.com/bbatsov/rubocop/pull/2583): New cop `Performance/TimesMap` checks for `x.times.map{}` and suggests replacing them with `Array.new(x){}`. ([@DNNX][])
20
+ * [#2581](https://github.com/bbatsov/rubocop/pull/2581): New cop `Lint/NextWithoutAccumulator` finds bare `next` in `reduce`/`inject` blocks which assigns `nil` to the accumulator. ([@mvidner][])
20
21
  * [#2529](https://github.com/bbatsov/rubocop/pull/2529): Add EnforcedStyle config parameter to IndentArray. ([@jawshooah][])
21
22
  * [#2479](https://github.com/bbatsov/rubocop/pull/2479): Add option `AllowHeredoc` to `Metrics/LineLength`. ([@fphilipe][])
22
23
  * [#2416](https://github.com/bbatsov/rubocop/pull/2416): New cop `Style/ConditionalAssignment` checks for assignment of the same variable in all branches of conditionals and replaces them with a single assignment to the return of the conditional. ([@rrosenblum][])
@@ -0,0 +1,200 @@
1
+ ### New features
2
+
3
+ * [#2620](https://github.com/bbatsov/rubocop/pull/2620): New cop `Style/ZeroLengthPredicate` checks for `object.size == 0` and variants, and suggests replacing them with an appropriate `empty?` predicate. ([@drenmi][])
4
+ * [#2657](https://github.com/bbatsov/rubocop/pull/2657): Floating headers in HTML output. ([@mattparlane][])
5
+ * Add new `Style/SpaceAroundKeyword` cop. ([@lumeet][])
6
+ * [#2745](https://github.com/bbatsov/rubocop/pull/2745): New cop `Style/MultilineHashBraceLayout` checks that the closing brace in a hash literal is symmetrical with respect to the opening brace and the hash elements. ([@panthomakos][])
7
+ * [#2761](https://github.com/bbatsov/rubocop/pull/2761): New cop `Style/MultilineMethodDefinitionBraceLayout` checks that the closing brace in a method definition is symmetrical with respect to the opening brace and the method parameters. ([@panthomakos][])
8
+ * [#2699](https://github.com/bbatsov/rubocop/pull/2699): `Performance/Casecmp` can register offenses when `str.downcase` or `str.upcase` are passed to an equality method. ([@rrosenblum][])
9
+ * [#2766](https://github.com/bbatsov/rubocop/pull/2766): New cop `Style/MultilineMethodCallBraceLayout` checks that the closing brace in a method call is symmetrical with respect to the opening brace and the method arguments. ([@panthomakos][])
10
+
11
+ ### Bug fixes
12
+
13
+ * [#2723](https://github.com/bbatsov/rubocop/issues/2723): Fix NoMethodError in Style/GuardClause. ([@drenmi][])
14
+ * [#2674](https://github.com/bbatsov/rubocop/issues/2674): Also check for Hash#update alias in `Performance/RedundantMerge`. ([@drenmi][])
15
+ * [#2630](https://github.com/bbatsov/rubocop/issues/2630): Take frozen string literals into account in `Style/MutableConstant`. ([@segiddins][])
16
+ * [#2642](https://github.com/bbatsov/rubocop/issues/2642): Support assignment via `||=` in `Style/MutableConstant`. ([@segiddins][])
17
+ * [#2646](https://github.com/bbatsov/rubocop/issues/2646): Fix auto-correcting assignment to a constant in `Style/ConditionalAssignment`. ([@segiddins][])
18
+ * [#2614](https://github.com/bbatsov/rubocop/issues/2614): Check for zero return value from `casecmp` in `Performance/casecmp`. ([@segiddins][])
19
+ * [#2647](https://github.com/bbatsov/rubocop/issues/2647): Allow `xstr` interpolations in `Lint/LiteralInInterpolation`. ([@segiddins][])
20
+ * Report a violation when `freeze` is called on a frozen string literal in `Style/RedundantFreeze`. ([@segiddins][])
21
+ * [#2641](https://github.com/bbatsov/rubocop/issues/2641): Fix crashing on empty methods with block args in `Perfomance/RedundantBlockCall`. ([@segiddins][])
22
+ * `Lint/DuplicateMethods` doesn't crash when `class_eval` is used with an implicit receiver. ([@lumeet][])
23
+ * [#2654](https://github.com/bbatsov/rubocop/issues/2654): Fix handling of unary operations in `Style/RedundantParentheses`. ([@lumeet][])
24
+ * [#2661](https://github.com/bbatsov/rubocop/issues/2661): `Style/Next` doesn't crash when auto-correcting modifier `if/unless`. ([@lumeet][])
25
+ * [#2665](https://github.com/bbatsov/rubocop/pull/2665): Make specs pass when running on Windows. ([@jonas054][])
26
+ * [#2691](https://github.com/bbatsov/rubocop/pull/2691): Do not register an offense in `Performance/TimesMap` for calling `map` or `collect` on a variable named `times`. ([@rrosenblum][])
27
+ * [#2689](https://github.com/bbatsov/rubocop/pull/2689): Change `Performance/RedundantBlockCall` to respect parentheses usage. ([@rrosenblum][])
28
+ * [#2694](https://github.com/bbatsov/rubocop/issues/2694): Fix caching when using a different JSON gem such as Oj. ([@stormbreakerbg][])
29
+ * [#2707](https://github.com/bbatsov/rubocop/pull/2707): Change `Lint/NestedMethodDefinition` to respect `Class.new` and `Module.new`. ([@owst][])
30
+ * [#2701](https://github.com/bbatsov/rubocop/pull/2701): Do not consider assignments to the same variable as useless if later assignments are within a loop. ([@owst][])
31
+ * [#2696](https://github.com/bbatsov/rubocop/issues/2696): `Style/NestedModifier` adds parentheses around a condition when needed. ([@lumeet][])
32
+ * [#2666](https://github.com/bbatsov/rubocop/issues/2666): Fix bug when auto-correcting symbol literals in `Lint/LiteralInInterpolation`. ([@lumeet][])
33
+ * [#2664](https://github.com/bbatsov/rubocop/issues/2664): `Performance/Casecmp` can auto-correct case comparison to variables and method calls without error. ([@rrosenblum][])
34
+ * [#2729](https://github.com/bbatsov/rubocop/issues/2729): Fix handling of hash literal as the first argument in `Style/RedundantParentheses`. ([@lumeet][])
35
+ * [#2703](https://github.com/bbatsov/rubocop/issues/2703): Handle byte order mark in `Style/IndentationWidth`, `Style/ElseAlignment`, `Lint/EndAlignment`, and `Lint/DefEndAlignment`. ([@jonas054][])
36
+ * [#2710](https://github.com/bbatsov/rubocop/pull/2710): Fix handling of fullwidth characters in some cops. ([@seikichi][])
37
+ * [#2690](https://github.com/bbatsov/rubocop/issues/2690): Fix alignment of operands that are part of an assignment in `Style/MultilineOperationIndentation`. ([@jonas054][])
38
+ * [#2228](https://github.com/bbatsov/rubocop/issues/2228): Use the config of a related cop whether it's enabled or not. ([@madwort][])
39
+ * [#2721](https://github.com/bbatsov/rubocop/issues/2721): Do not register an offense for constants wrapped in parentheses passed to `rescue` in `Style/RedundantParentheses`. ([@rrosenblum][])
40
+ * [#2742](https://github.com/bbatsov/rubocop/issues/2742): Fix `Style/TrailingCommaInArguments` & `Style/TrailingCommaInLiteral` for inline single element arrays. ([@annih][])
41
+ * [#2768](https://github.com/bbatsov/rubocop/issues/2768): Allow parentheses after keyword `not` in `Style/MethodCallParentheses`. ([@lumeet][])
42
+ * [#2758](https://github.com/bbatsov/rubocop/issues/2758): Allow leading underscores in camel case variable names.([@mmcguinn][])
43
+
44
+ ### Changes
45
+
46
+ * Remove `Style/SpaceAfterControlKeyword` and `Style/SpaceBeforeModifierKeyword` as the more generic `Style/SpaceAroundKeyword` handles the same cases. ([@lumeet][])
47
+ * Handle comparisons with `!=` in `Performance/casecmp`. ([@segiddins][])
48
+ * [#2684](https://github.com/bbatsov/rubocop/pull/2684): Do not base `Style/FrozenStringLiteralComment` on the version of Ruby that is running. ([@rrosenblum][])
49
+ * [#2732](https://github.com/bbatsov/rubocop/issues/2732): Change the default style of `Style/SignalException` to `only_raise`. ([@bbatsov][])
50
+
51
+ [@bbatsov]: https://github.com/bbatsov
52
+ [@jonas054]: https://github.com/jonas054
53
+ [@yujinakayama]: https://github.com/yujinakayama
54
+ [@dblock]: https://github.com/dblock
55
+ [@nevir]: https://github.com/nevir
56
+ [@daviddavis]: https://github.com/daviddavis
57
+ [@sds]: https://github.com/sds
58
+ [@fancyremarker]: https://github.com/fancyremarker
59
+ [@sinisterchipmunk]: https://github.com/sinisterchipmunk
60
+ [@vonTronje]: https://github.com/vonTronje
61
+ [@agrimm]: https://github.com/agrimm
62
+ [@pmenglund]: https://github.com/pmenglund
63
+ [@chulkilee]: https://github.com/chulkilee
64
+ [@codez]: https://github.com/codez
65
+ [@emou]: https://github.com/emou
66
+ [@skanev]: http://github.com/skanev
67
+ [@claco]: http://github.com/claco
68
+ [@rifraf]: http://github.com/rifraf
69
+ [@scottmatthewman]: https://github.com/scottmatthewman
70
+ [@ma2gedev]: http://github.com/ma2gedev
71
+ [@jeremyolliver]: https://github.com/jeremyolliver
72
+ [@hannestyden]: https://github.com/hannestyden
73
+ [@geniou]: https://github.com/geniou
74
+ [@jkogara]: https://github.com/jkogara
75
+ [@tmorris-fiksu]: https://github.com/tmorris-fiksu
76
+ [@mockdeep]: https://github.com/mockdeep
77
+ [@hiroponz]: https://github.com/hiroponz
78
+ [@tamird]: https://github.com/tamird
79
+ [@fshowalter]: https://github.com/fshowalter
80
+ [@cschramm]: https://github.com/cschramm
81
+ [@bquorning]: https://github.com/bquorning
82
+ [@bcobb]: https://github.com/bcobb
83
+ [@irrationalfab]: https://github.com/irrationalfab
84
+ [@tommeier]: https://github.com/tommeier
85
+ [@sfeldon]: https://github.com/sfeldon
86
+ [@biinari]: https://github.com/biinari
87
+ [@barunio]: https://github.com/barunio
88
+ [@molawson]: https://github.com/molawson
89
+ [@wndhydrnt]: https://github.com/wndhydrnt
90
+ [@ggilder]: https://github.com/ggilder
91
+ [@salbertson]: https://github.com/salbertson
92
+ [@camilleldn]: https://github.com/camilleldn
93
+ [@mcls]: https://github.com/mcls
94
+ [@yous]: https://github.com/yous
95
+ [@vrthra]: https://github.com/vrthra
96
+ [@SkuliOskarsson]: https://github.com/SkuliOskarsson
97
+ [@jspanjers]: https://github.com/jspanjers
98
+ [@sch1zo]: https://github.com/sch1zo
99
+ [@smangelsdorf]: https://github.com/smangelsdorf
100
+ [@mvz]: https://github.com/mvz
101
+ [@jfelchner]: https://github.com/jfelchner
102
+ [@janraasch]: https://github.com/janraasch
103
+ [@jcarbo]: https://github.com/jcarbo
104
+ [@oneamtu]: https://github.com/oneamtu
105
+ [@toy]: https://github.com/toy
106
+ [@Koronen]: https://github.com/Koronen
107
+ [@blainesch]: https://github.com/blainesch
108
+ [@marxarelli]: https://github.com/marxarelli
109
+ [@katieschilling]: https://github.com/katieschilling
110
+ [@kakutani]: https://github.com/kakutani
111
+ [@rrosenblum]: https://github.com/rrosenblum
112
+ [@mattjmcnaughton]: https://github.com/mattjmcnaughton
113
+ [@huerlisi]: https://github.com/huerlisi
114
+ [@volkert]: https://github.com/volkert
115
+ [@lumeet]: https://github.com/lumeet
116
+ [@mmozuras]: https://github.com/mmozuras
117
+ [@d4rk5eed]: https://github.com/d4rk5eed
118
+ [@cshaffer]: https://github.com/cshaffer
119
+ [@eitoball]: https://github.com/eitoball
120
+ [@iainbeeston]: https://github.com/iainbeeston
121
+ [@pimterry]: https://github.com/pimterry
122
+ [@palkan]: https://github.com/palkan
123
+ [@jdoconnor]: https://github.com/jdoconnor
124
+ [@meganemura]: https://github.com/meganemura
125
+ [@zvkemp]: https://github.com/zvkemp
126
+ [@vassilevsky]: https://github.com/vassilevsky
127
+ [@gerry3]: https://github.com/gerry3
128
+ [@ypresto]: https://github.com/ypresto
129
+ [@clowder]: https://github.com/clowder
130
+ [@mudge]: https://github.com/mudge
131
+ [@mzp]: https://github.com/mzp
132
+ [@bankair]: https://github.com/bankair
133
+ [@crimsonknave]: https://github.com/crimsonknave
134
+ [@renuo]: https://github.com/renuo
135
+ [@sdeframond]: https://github.com/sdeframond
136
+ [@til]: https://github.com/til
137
+ [@carhartl]: https://github.com/carhartl
138
+ [@dylandavidson]: https://github.com/dylandavidson
139
+ [@tmr08c]: https://github.com/tmr08c
140
+ [@hbd225]: https://github.com/hbd225
141
+ [@l8nite]: https://github.com/l8nite
142
+ [@sumeet]: https://github.com/sumeet
143
+ [@ojab]: https://github.com/ojab
144
+ [@chastell]: https://github.com/chastell
145
+ [@glasnt]: https://github.com/glasnt
146
+ [@crazydog115]: https://github.com/crazydog115
147
+ [@RGBD]: https://github.com/RGBD
148
+ [@panthomakos]: https://github.com/panthomakos
149
+ [@matugm]: https://github.com/matugm
150
+ [@m1foley]: https://github.com/m1foley
151
+ [@tejasbubane]: https://github.com/tejasbubane
152
+ [@bmorrall]: https://github.com/bmorrall
153
+ [@fphilipe]: https://github.com/fphilipe
154
+ [@gotrevor]: https://github.com/gotrevor
155
+ [@awwaiid]: https://github.com/awwaiid
156
+ [@segiddins]: https://github.com/segiddins
157
+ [@urbanautomaton]: https://github.com/urbanautomaton.com
158
+ [@unmanbearpig]: https://github.com/unmanbearpig
159
+ [@maxjacobson]: https://github.com/maxjacobson
160
+ [@sliuu]: https://github.com/sliuu
161
+ [@edmz]: https://github.com/edmz
162
+ [@syndbg]: https://github.com/syndbg
163
+ [@wli]: https://github.com/wli
164
+ [@caseywebdev]: https://github.com/caseywebdev
165
+ [@MGerrior]: https://github.com/MGerrior
166
+ [@imtayadeway]: https://github.com/imtayadeway
167
+ [@mrfoto]: https://github.com/mrfoto
168
+ [@karreiro]: https://github.com/karreiro
169
+ [@dreyks]: https://github.com/dreyks
170
+ [@hmadison]: https://github.com/hmadison
171
+ [@miquella]: https://github.com/miquella
172
+ [@jhansche]: https://github.com/jhansche
173
+ [@cornelius]: https://github.com/cornelius
174
+ [@eagletmt]: https://github.com/eagletmt
175
+ [@apiology]: https://github.com/apiology
176
+ [@alexdowad]: https://github.com/alexdowad
177
+ [@minustehbare]: https://github.com/minustehbare
178
+ [@tansaku]: https://github.com/tansaku
179
+ [@ptrippett]: https://github.com/ptrippett
180
+ [@br3nda]: https://github.com/br3nda
181
+ [@jujugrrr]: https://github.com/jujugrrr
182
+ [@sometimesfood]: https://github.com/sometimesfood
183
+ [@cgriego]: https://github.com/cgriego
184
+ [@savef]: https://github.com/savef
185
+ [@volmer]: https://github.com/volmer
186
+ [@domcleal]: https://github.com/domcleal
187
+ [@codebeige]: https://github.com/codebeige
188
+ [@weh]: https://github.com/weh
189
+ [@bfontaine]: https://github.com/bfontaine
190
+ [@jawshooah]: https://github.com/jawshooah
191
+ [@DNNX]: https://github.com/DNNX
192
+ [@mvidner]: https://github.com/mvidner
193
+ [@mattparlane]: https://github.com/mattparlane
194
+ [@drenmi]: https://github.com/drenmi
195
+ [@stormbreakerbg]: https://github.com/stormbreakerbg
196
+ [@owst]: https://github.com/owst
197
+ [@seikichi]: https://github.com/seikichi
198
+ [@madwort]: https://github.com/madwort
199
+ [@annih]: https://github.com/annih
200
+ [@mmcguinn]: https://github.com/mmcguinn