rubocop 1.8.1 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +34 -4
  4. data/lib/rubocop.rb +5 -0
  5. data/lib/rubocop/cli/command/auto_genenerate_config.rb +5 -4
  6. data/lib/rubocop/config.rb +2 -2
  7. data/lib/rubocop/config_loader.rb +7 -14
  8. data/lib/rubocop/config_store.rb +12 -1
  9. data/lib/rubocop/cop/base.rb +1 -1
  10. data/lib/rubocop/cop/generator.rb +1 -3
  11. data/lib/rubocop/cop/internal_affairs.rb +5 -1
  12. data/lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb +68 -0
  13. data/lib/rubocop/cop/internal_affairs/example_description.rb +89 -0
  14. data/lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb +61 -0
  15. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +64 -0
  16. data/lib/rubocop/cop/layout/class_structure.rb +7 -2
  17. data/lib/rubocop/cop/lint/number_conversion.rb +41 -6
  18. data/lib/rubocop/cop/lint/numbered_parameter_assignment.rb +47 -0
  19. data/lib/rubocop/cop/lint/or_assignment_to_constant.rb +39 -0
  20. data/lib/rubocop/cop/lint/symbol_conversion.rb +102 -0
  21. data/lib/rubocop/cop/lint/triple_quotes.rb +71 -0
  22. data/lib/rubocop/cop/mixin/check_line_breakable.rb +5 -0
  23. data/lib/rubocop/cop/mixin/comments_help.rb +0 -1
  24. data/lib/rubocop/cop/naming/rescued_exceptions_variable_name.rb +38 -5
  25. data/lib/rubocop/cop/naming/variable_number.rb +1 -1
  26. data/lib/rubocop/cop/severity.rb +3 -3
  27. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  28. data/lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb +49 -9
  29. data/lib/rubocop/cop/style/eval_with_location.rb +63 -34
  30. data/lib/rubocop/cop/style/float_division.rb +3 -0
  31. data/lib/rubocop/cop/style/format_string_token.rb +18 -2
  32. data/lib/rubocop/cop/style/if_inside_else.rb +14 -7
  33. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +96 -0
  34. data/lib/rubocop/cop/style/nil_comparison.rb +1 -0
  35. data/lib/rubocop/cop/style/non_nil_check.rb +23 -13
  36. data/lib/rubocop/cop/style/single_line_methods.rb +1 -1
  37. data/lib/rubocop/cop/style/sole_nested_conditional.rb +26 -2
  38. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  39. data/lib/rubocop/formatter/git_hub_actions_formatter.rb +1 -0
  40. data/lib/rubocop/magic_comment.rb +30 -1
  41. data/lib/rubocop/options.rb +1 -1
  42. data/lib/rubocop/rspec/expect_offense.rb +5 -2
  43. data/lib/rubocop/runner.rb +1 -0
  44. data/lib/rubocop/version.rb +2 -2
  45. metadata +12 -3
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for redundant `if` with boolean literal branches.
7
+ # It checks only conditions to return boolean value (`true` or `false`) for safe detection.
8
+ # The conditions to be checked are comparison methods, predicate methods, and double negative.
9
+ #
10
+ # @example
11
+ # # bad
12
+ # if foo == bar
13
+ # true
14
+ # else
15
+ # false
16
+ # end
17
+ #
18
+ # # bad
19
+ # foo == bar ? true : false
20
+ #
21
+ # # good
22
+ # foo == bar
23
+ #
24
+ class IfWithBooleanLiteralBranches < Base
25
+ extend AutoCorrector
26
+
27
+ MSG = 'Remove redundant %<keyword>s with boolean literal branches.'
28
+
29
+ def_node_matcher :if_with_boolean_literal_branches?, <<~PATTERN
30
+ (if #return_boolean_value? {(true) (false) | (false) (true)})
31
+ PATTERN
32
+ def_node_matcher :double_negative?, '(send (send _ :!) :!)'
33
+
34
+ def on_if(node)
35
+ return unless if_with_boolean_literal_branches?(node)
36
+
37
+ condition = node.condition
38
+ range, keyword = if node.ternary?
39
+ range = condition.source_range.end.join(node.source_range.end)
40
+
41
+ [range, 'ternary operator']
42
+ else
43
+ keyword = node.loc.keyword
44
+
45
+ [keyword, "`#{keyword.source}`"]
46
+ end
47
+
48
+ add_offense(range, message: format(MSG, keyword: keyword)) do |corrector|
49
+ replacement = replacement_condition(node, condition)
50
+
51
+ corrector.replace(node, replacement)
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def return_boolean_value?(condition)
58
+ if condition.begin_type?
59
+ return_boolean_value?(condition.children.first)
60
+ elsif condition.or_type?
61
+ return_boolean_value?(condition.lhs) && return_boolean_value?(condition.rhs)
62
+ elsif condition.and_type?
63
+ return_boolean_value?(condition.rhs)
64
+ else
65
+ assume_boolean_value?(condition)
66
+ end
67
+ end
68
+
69
+ def assume_boolean_value?(condition)
70
+ return false unless condition.send_type?
71
+
72
+ condition.comparison_method? || condition.predicate_method? || double_negative?(condition)
73
+ end
74
+
75
+ def replacement_condition(node, condition)
76
+ bang = '!' if opposite_condition?(node)
77
+
78
+ if bang && require_parentheses?(condition)
79
+ "#{bang}(#{condition.source})"
80
+ else
81
+ "#{bang}#{condition.source}"
82
+ end
83
+ end
84
+
85
+ def opposite_condition?(node)
86
+ !node.unless? && node.if_branch.false_type? || node.unless? && node.if_branch.true_type?
87
+ end
88
+
89
+ def require_parentheses?(condition)
90
+ condition.and_type? || condition.or_type? ||
91
+ condition.send_type? && condition.comparison_method?
92
+ end
93
+ end
94
+ end
95
+ end
96
+ end
@@ -50,6 +50,7 @@ module RuboCop
50
50
  end
51
51
 
52
52
  corrector.replace(node, new_code)
53
+ corrector.wrap(node, '(', ')') if node.parent&.method?(:!)
53
54
  end
54
55
  end
55
56
  end
@@ -8,6 +8,9 @@ module RuboCop
8
8
  # With `IncludeSemanticChanges` set to `false` by default, this cop
9
9
  # does not report offenses for `!x.nil?` and does no changes that might
10
10
  # change behavior.
11
+ # Also `IncludeSemanticChanges` set to `false` with `EnforcedStyle: comparison` of
12
+ # `Style/NilComparison` cop, this cop does not report offenses for `x != nil` and
13
+ # does no changes to `!x.nil?` style.
11
14
  #
12
15
  # With `IncludeSemanticChanges` set to `true`, this cop reports offenses
13
16
  # for `!x.nil?` and autocorrects that and `x != nil` to solely `x`, which
@@ -41,6 +44,9 @@ module RuboCop
41
44
  class NonNilCheck < Base
42
45
  extend AutoCorrector
43
46
 
47
+ MSG_FOR_REPLACEMENT = 'Prefer `%<prefer>s` over `%<current>s`.'
48
+ MSG_FOR_REDUNDANCY = 'Explicit non-nil checks are usually redundant.'
49
+
44
50
  RESTRICT_ON_SEND = %i[!= nil? !].freeze
45
51
 
46
52
  def_node_matcher :not_equal_to_nil?, '(send _ :!= nil)'
@@ -49,11 +55,12 @@ module RuboCop
49
55
  def_node_matcher :not_and_nil_check?, '(send (send _ :nil?) :!)'
50
56
 
51
57
  def on_send(node)
52
- return if ignored_node?(node)
53
- return unless (offense_node = find_offense_node(node))
58
+ return if ignored_node?(node) ||
59
+ !include_semantic_changes? && nil_comparison_style == 'comparison'
60
+ return unless register_offense?(node)
54
61
 
55
62
  message = message(node)
56
- add_offense(offense_node, message: message) do |corrector|
63
+ add_offense(node, message: message) do |corrector|
57
64
  autocorrect(corrector, node)
58
65
  end
59
66
  end
@@ -73,13 +80,9 @@ module RuboCop
73
80
 
74
81
  private
75
82
 
76
- def find_offense_node(node)
77
- if not_equal_to_nil?(node)
78
- node.loc.selector
79
- elsif include_semantic_changes? &&
80
- (not_and_nil_check?(node) || unless_and_nil_check?(node))
81
- node
82
- end
83
+ def register_offense?(node)
84
+ not_equal_to_nil?(node) ||
85
+ include_semantic_changes? && (not_and_nil_check?(node) || unless_and_nil_check?(node))
83
86
  end
84
87
 
85
88
  def autocorrect(corrector, node)
@@ -101,10 +104,11 @@ module RuboCop
101
104
  end
102
105
 
103
106
  def message(node)
104
- if node.method?(:!=)
105
- 'Prefer `!expression.nil?` over `expression != nil`.'
107
+ if node.method?(:!=) && !include_semantic_changes?
108
+ prefer = "!#{node.receiver.source}.nil?"
109
+ format(MSG_FOR_REPLACEMENT, prefer: prefer, current: node.source)
106
110
  else
107
- 'Explicit non-nil checks are usually redundant.'
111
+ MSG_FOR_REDUNDANCY
108
112
  end
109
113
  end
110
114
 
@@ -138,6 +142,12 @@ module RuboCop
138
142
  corrector.replace(node.parent.loc.keyword, 'if')
139
143
  corrector.replace(node, receiver.source)
140
144
  end
145
+
146
+ def nil_comparison_style
147
+ nil_comparison_conf = config.for_cop('Style/NilComparison')
148
+
149
+ nil_comparison_conf['Enabled'] && nil_comparison_conf['EnforcedStyle']
150
+ end
141
151
  end
142
152
  end
143
153
  end
@@ -8,7 +8,7 @@ module RuboCop
8
8
  #
9
9
  # Endless methods added in Ruby 3.0 are also accepted by this cop.
10
10
  #
11
- # If `Style/EndlessMethod` is enabled with `EnforcedStyle: allow` or
11
+ # If `Style/EndlessMethod` is enabled with `EnforcedStyle: allow_single_line` or
12
12
  # `allow_always`, single-line methods will be auto-corrected to endless
13
13
  # methods if there is only one statement in the body.
14
14
  #
@@ -80,8 +80,11 @@ module RuboCop
80
80
  end
81
81
 
82
82
  def correct_for_guard_condition_style(corrector, node, if_branch, and_operator)
83
+ outer_condition = node.condition
84
+ correct_outer_condition(corrector, outer_condition)
85
+
83
86
  condition = if_branch.condition
84
- corrector.insert_after(node.condition, replacement_condition(and_operator, condition))
87
+ corrector.insert_after(outer_condition, replacement_condition(and_operator, condition))
85
88
 
86
89
  range = range_between(if_branch.loc.keyword.begin_pos, condition.source_range.end_pos)
87
90
  corrector.remove(range_with_surrounding_space(range: range, newlines: false))
@@ -106,8 +109,29 @@ module RuboCop
106
109
  corrector.insert_before(node.loc.keyword, comment_text) unless comments.empty?
107
110
  end
108
111
 
112
+ def correct_outer_condition(corrector, condition)
113
+ return unless requrie_parentheses?(condition)
114
+
115
+ range = range_between(
116
+ condition.loc.selector.end_pos, condition.first_argument.source_range.begin_pos
117
+ )
118
+
119
+ corrector.replace(range, '(')
120
+ corrector.insert_after(condition.last_argument.source_range, ')')
121
+ end
122
+
123
+ def requrie_parentheses?(condition)
124
+ condition.send_type? && !condition.arguments.empty? && !condition.parenthesized?
125
+ end
126
+
127
+ def arguments_range(node)
128
+ range_between(
129
+ node.first_argument.source_range.begin_pos, node.last_argument.source_range.end_pos
130
+ )
131
+ end
132
+
109
133
  def wrap_condition?(node)
110
- node.or_type? ||
134
+ node.and_type? || node.or_type? ||
111
135
  (node.send_type? && node.arguments.any? && !node.parenthesized?)
112
136
  end
113
137
 
@@ -120,7 +120,7 @@ module RuboCop
120
120
  if condition.begin_type?
121
121
  condition.to_a.any? { |x| complex_condition?(x) }
122
122
  else
123
- non_complex_expression?(condition) ? false : true
123
+ !non_complex_expression?(condition)
124
124
  end
125
125
  end
126
126
 
@@ -23,6 +23,7 @@ module RuboCop
23
23
 
24
24
  def minimum_severity_to_fail
25
25
  @minimum_severity_to_fail ||= begin
26
+ # Unless given explicitly as `fail_level`, `:info` severity offenses do not fail
26
27
  name = options.fetch(:fail_level, :refactor)
27
28
  RuboCop::Cop::Severity.new(name)
28
29
  end
@@ -27,7 +27,7 @@ module RuboCop
27
27
  end
28
28
 
29
29
  def any?
30
- frozen_string_literal_specified? || encoding_specified?
30
+ frozen_string_literal_specified? || encoding_specified? || shareable_constant_value_specified?
31
31
  end
32
32
 
33
33
  # Does the magic comment enable the frozen string literal feature.
@@ -46,6 +46,10 @@ module RuboCop
46
46
  [true, false].include?(frozen_string_literal)
47
47
  end
48
48
 
49
+ def valid_shareable_constant_value?
50
+ %w[none literal experimental_everything experimental_copy].include?(shareable_constant_values)
51
+ end
52
+
49
53
  # Was a magic comment for the frozen string literal found?
50
54
  #
51
55
  # @return [Boolean]
@@ -53,6 +57,13 @@ module RuboCop
53
57
  specified?(frozen_string_literal)
54
58
  end
55
59
 
60
+ # Was a shareable_constant_value specified?
61
+ #
62
+ # @return [Boolean]
63
+ def shareable_constant_value_specified?
64
+ specified?(shareable_constant_value)
65
+ end
66
+
56
67
  # Expose the `frozen_string_literal` value coerced to a boolean if possible.
57
68
  #
58
69
  # @return [Boolean] if value is `true` or `false`
@@ -69,6 +80,13 @@ module RuboCop
69
80
  end
70
81
  end
71
82
 
83
+ # Expose the `shareable_constant_value` value coerced to a boolean if possible.
84
+ #
85
+ # @return [String] for shareable_constant_value config
86
+ def shareable_constant_value
87
+ extract_shareable_constant_value
88
+ end
89
+
72
90
  def encoding_specified?
73
91
  specified?(encoding)
74
92
  end
@@ -146,6 +164,10 @@ module RuboCop
146
164
  def extract_frozen_string_literal
147
165
  match('frozen[_-]string[_-]literal')
148
166
  end
167
+
168
+ def extract_shareable_constant_value
169
+ match('shareable[_-]constant[_-]values')
170
+ end
149
171
  end
150
172
 
151
173
  # Wrapper for Vim style magic comments.
@@ -176,6 +198,9 @@ module RuboCop
176
198
 
177
199
  # Vim comments cannot specify frozen string literal behavior.
178
200
  def frozen_string_literal; end
201
+
202
+ # Vim comments cannot specify shareable constant values behavior.
203
+ def shareable_constant_value; end
179
204
  end
180
205
 
181
206
  # Wrapper for regular magic comments not bound to an editor.
@@ -209,6 +234,10 @@ module RuboCop
209
234
  def extract_frozen_string_literal
210
235
  extract(/\A\s*#\s*frozen[_-]string[_-]literal:\s*(#{TOKEN})\s*\z/io)
211
236
  end
237
+
238
+ def extract_shareable_constant_value
239
+ extract(/\A\s*#\s*shareable[_-]constant[_-]value:\s*(#{TOKEN})\s*\z/io)
240
+ end
212
241
  end
213
242
  end
214
243
  end
@@ -470,7 +470,7 @@ module RuboCop
470
470
  'This option applies to the previously',
471
471
  'specified --format, or the default format',
472
472
  'if no format is specified.'],
473
- fail_level: ['Minimum severity (A/R/C/W/E/F) for exit',
473
+ fail_level: ['Minimum severity (A/I/R/C/W/E/F) for exit',
474
474
  'with error code.'],
475
475
  display_time: 'Display elapsed time in seconds.',
476
476
  display_only_failed: ['Only output offense messages. Omit passing',
@@ -111,9 +111,12 @@ module RuboCop
111
111
  source
112
112
  end
113
113
 
114
- def expect_offense(source, file = nil, severity: nil, **replacements)
114
+ def expect_offense(source, file = nil, severity: nil, chomp: false, **replacements)
115
115
  expected_annotations = parse_annotations(source, **replacements)
116
- @processed_source = parse_processed_source(expected_annotations.plain_source, file)
116
+ source = expected_annotations.plain_source
117
+ source = source.chomp if chomp
118
+
119
+ @processed_source = parse_processed_source(source, file)
117
120
  @offenses = _investigate(cop, @processed_source)
118
121
  actual_annotations =
119
122
  expected_annotations.with_offense_annotations(@offenses)
@@ -390,6 +390,7 @@ module RuboCop
390
390
 
391
391
  def minimum_severity_to_fail
392
392
  @minimum_severity_to_fail ||= begin
393
+ # Unless given explicitly as `fail_level`, `:info` severity offenses do not fail
393
394
  name = @options[:fail_level] || :refactor
394
395
  RuboCop::Cop::Severity.new(name)
395
396
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.8.1'
6
+ STRING = '1.9.0'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, '\
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
@@ -37,7 +37,7 @@ module RuboCop
37
37
  features = Util.silence_warnings do
38
38
  # Suppress any config issues when loading the config (ie. deprecations,
39
39
  # pending cops, etc.).
40
- env.config_store.for_pwd.loaded_features.sort
40
+ env.config_store.unvalidated.for_pwd.loaded_features.sort
41
41
  end
42
42
 
43
43
  features.map do |loaded_feature|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.1
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2021-01-11 00:00:00.000000000 Z
13
+ date: 2021-01-28 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parallel
@@ -252,10 +252,14 @@ files:
252
252
  - lib/rubocop/cop/generator/require_file_injector.rb
253
253
  - lib/rubocop/cop/ignored_node.rb
254
254
  - lib/rubocop/cop/internal_affairs.rb
255
+ - lib/rubocop/cop/internal_affairs/empty_line_between_expect_offense_and_correction.rb
256
+ - lib/rubocop/cop/internal_affairs/example_description.rb
255
257
  - lib/rubocop/cop/internal_affairs/method_name_equal.rb
256
258
  - lib/rubocop/cop/internal_affairs/node_destructuring.rb
257
259
  - lib/rubocop/cop/internal_affairs/node_type_predicate.rb
258
260
  - lib/rubocop/cop/internal_affairs/offense_location_keyword.rb
261
+ - lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb
262
+ - lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb
259
263
  - lib/rubocop/cop/internal_affairs/redundant_location_argument.rb
260
264
  - lib/rubocop/cop/internal_affairs/redundant_message_argument.rb
261
265
  - lib/rubocop/cop/internal_affairs/style_detected_api_use.rb
@@ -417,6 +421,8 @@ files:
417
421
  - lib/rubocop/cop/lint/non_deterministic_require_order.rb
418
422
  - lib/rubocop/cop/lint/non_local_exit_from_iterator.rb
419
423
  - lib/rubocop/cop/lint/number_conversion.rb
424
+ - lib/rubocop/cop/lint/numbered_parameter_assignment.rb
425
+ - lib/rubocop/cop/lint/or_assignment_to_constant.rb
420
426
  - lib/rubocop/cop/lint/ordered_magic_comments.rb
421
427
  - lib/rubocop/cop/lint/out_of_range_regexp_ref.rb
422
428
  - lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb
@@ -449,11 +455,13 @@ files:
449
455
  - lib/rubocop/cop/lint/shadowing_outer_local_variable.rb
450
456
  - lib/rubocop/cop/lint/struct_new_override.rb
451
457
  - lib/rubocop/cop/lint/suppressed_exception.rb
458
+ - lib/rubocop/cop/lint/symbol_conversion.rb
452
459
  - lib/rubocop/cop/lint/syntax.rb
453
460
  - lib/rubocop/cop/lint/to_enum_arguments.rb
454
461
  - lib/rubocop/cop/lint/to_json.rb
455
462
  - lib/rubocop/cop/lint/top_level_return_with_argument.rb
456
463
  - lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb
464
+ - lib/rubocop/cop/lint/triple_quotes.rb
457
465
  - lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb
458
466
  - lib/rubocop/cop/lint/unexpected_block_arity.rb
459
467
  - lib/rubocop/cop/lint/unified_integer.rb
@@ -656,6 +664,7 @@ files:
656
664
  - lib/rubocop/cop/style/if_inside_else.rb
657
665
  - lib/rubocop/cop/style/if_unless_modifier.rb
658
666
  - lib/rubocop/cop/style/if_unless_modifier_of_if_unless.rb
667
+ - lib/rubocop/cop/style/if_with_boolean_literal_branches.rb
659
668
  - lib/rubocop/cop/style/if_with_semicolon.rb
660
669
  - lib/rubocop/cop/style/implicit_runtime_error.rb
661
670
  - lib/rubocop/cop/style/infinite_loop.rb
@@ -856,7 +865,7 @@ metadata:
856
865
  homepage_uri: https://rubocop.org/
857
866
  changelog_uri: https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md
858
867
  source_code_uri: https://github.com/rubocop-hq/rubocop/
859
- documentation_uri: https://docs.rubocop.org/rubocop/1.8/
868
+ documentation_uri: https://docs.rubocop.org/rubocop/1.9/
860
869
  bug_tracker_uri: https://github.com/rubocop-hq/rubocop/issues
861
870
  post_install_message:
862
871
  rdoc_options: []