rubocop 1.25.1 → 1.26.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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +14 -4
  4. data/lib/rubocop/cli.rb +1 -1
  5. data/lib/rubocop/cop/badge.rb +7 -1
  6. data/lib/rubocop/cop/gemspec/require_mfa.rb +4 -3
  7. data/lib/rubocop/cop/generator.rb +2 -7
  8. data/lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb +46 -0
  9. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  10. data/lib/rubocop/cop/layout/case_indentation.rb +1 -1
  11. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +7 -8
  12. data/lib/rubocop/cop/lint/inherit_exception.rb +19 -28
  13. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -2
  14. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +5 -0
  15. data/lib/rubocop/cop/lint/useless_times.rb +13 -9
  16. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +1 -1
  17. data/lib/rubocop/cop/security/yaml_load.rb +9 -3
  18. data/lib/rubocop/cop/style/def_with_parentheses.rb +16 -11
  19. data/lib/rubocop/cop/style/for.rb +4 -0
  20. data/lib/rubocop/cop/style/lambda_call.rb +12 -20
  21. data/lib/rubocop/cop/style/nested_file_dirname.rb +66 -0
  22. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +3 -2
  23. data/lib/rubocop/cop/style/string_concatenation.rb +7 -1
  24. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +1 -1
  25. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +1 -1
  26. data/lib/rubocop/cop/variable_force.rb +1 -5
  27. data/lib/rubocop/cops_documentation_generator.rb +2 -2
  28. data/lib/rubocop/formatter/disabled_config_formatter.rb +2 -2
  29. data/lib/rubocop/options.rb +8 -2
  30. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  31. data/lib/rubocop/runner.rb +1 -1
  32. data/lib/rubocop/target_ruby.rb +1 -1
  33. data/lib/rubocop/version.rb +1 -1
  34. data/lib/rubocop.rb +1 -0
  35. metadata +7 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 54b88752efa8bb84dc034391460b9071f31179dcb279550a209d31829e7b8c93
4
- data.tar.gz: 31115cff5fdbf562dee62cf7e07033205d150b61ac5fd11476708f21e67000cf
3
+ metadata.gz: 6f5e4905006f7a87c34929888b4f93424dfd0695f95542fcf04db5091e76f2b4
4
+ data.tar.gz: ca36431854888608b6f57b36eb5a1e04569b7c513585579f30e121f30b231705
5
5
  SHA512:
6
- metadata.gz: acdaf069659a775853b20e05734e85cd65c0c8734b09e568d4360dc9a7440a49ec8e47928b0da78866e1326a588638d18f2564e6e94023bb17b2f39493555027
7
- data.tar.gz: 2765d9c9c10966c485be6cd70190b69a25aa99800c8d483bd67c1fdfe3dc5d13bb97cb1ca7f9f663776869acda5a426bc797f3b40adda17e0241ff8b62a374f1
6
+ metadata.gz: 76d8ae5e1506313617a01d9c7ddd4061b0ced25ad6a47287e199489dee9fe76126907a4193a2ec6b70e5fef1f0274af3b017557d2c2f904d931f9d41805f98cb
7
+ data.tar.gz: 78b0442c8baa4ae704a19e37df8e4490801238989ab880f888d1c355a7b488bab7086f68d1a8f5f3bafd691998b25d9c9dabcafb921b87b6ba5b781a9efba624
data/README.md CHANGED
@@ -53,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
53
53
  in your `Gemfile`:
54
54
 
55
55
  ```rb
56
- gem 'rubocop', '~> 1.25', require: false
56
+ gem 'rubocop', '~> 1.26', require: false
57
57
  ```
58
58
 
59
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
data/config/default.yml CHANGED
@@ -262,7 +262,7 @@ Gemspec/OrderedDependencies:
262
262
  - '**/*.gemspec'
263
263
 
264
264
  Gemspec/RequireMFA:
265
- Description: 'Checks that the gemspec has metadata to require MFA from RubyGems.'
265
+ Description: 'Checks that the gemspec has metadata to require Multi-Factor Authentication from RubyGems.'
266
266
  Enabled: pending
267
267
  VersionAdded: '1.23'
268
268
  Reference:
@@ -1816,12 +1816,14 @@ Lint/IneffectiveAccessModifier:
1816
1816
  Lint/InheritException:
1817
1817
  Description: 'Avoid inheriting from the `Exception` class.'
1818
1818
  Enabled: true
1819
+ SafeAutoCorrect: false
1819
1820
  VersionAdded: '0.41'
1821
+ VersionChanged: '1.26'
1820
1822
  # The default base class in favour of `Exception`.
1821
- EnforcedStyle: runtime_error
1823
+ EnforcedStyle: standard_error
1822
1824
  SupportedStyles:
1823
- - runtime_error
1824
1825
  - standard_error
1826
+ - runtime_error
1825
1827
 
1826
1828
  Lint/InterpolationCheck:
1827
1829
  Description: 'Raise warning for interpolation in single q strs.'
@@ -2011,6 +2013,8 @@ Lint/RedundantDirGlobSort:
2011
2013
  Description: 'Checks for redundant `sort` method to `Dir.glob` and `Dir[]`.'
2012
2014
  Enabled: pending
2013
2015
  VersionAdded: '1.8'
2016
+ VersionChanged: '1.26'
2017
+ SafeAutoCorrect: false
2014
2018
 
2015
2019
  Lint/RedundantRequireStatement:
2016
2020
  Description: 'Checks for unnecessary `require` statement.'
@@ -3542,8 +3546,9 @@ Style/For:
3542
3546
  Description: 'Checks use of for or each in multiline loops.'
3543
3547
  StyleGuide: '#no-for-loops'
3544
3548
  Enabled: true
3549
+ SafeAutoCorrect: false
3545
3550
  VersionAdded: '0.13'
3546
- VersionChanged: '0.59'
3551
+ VersionChanged: '1.26'
3547
3552
  EnforcedStyle: each
3548
3553
  SupportedStyles:
3549
3554
  - each
@@ -4122,6 +4127,11 @@ Style/NegatedWhile:
4122
4127
  Enabled: true
4123
4128
  VersionAdded: '0.20'
4124
4129
 
4130
+ Style/NestedFileDirname:
4131
+ Description: 'Checks for nested `File.dirname`.'
4132
+ Enabled: pending
4133
+ VersionAdded: '1.26'
4134
+
4125
4135
  Style/NestedModifier:
4126
4136
  Description: 'Avoid using nested modifiers.'
4127
4137
  StyleGuide: '#no-nested-modifiers'
data/lib/rubocop/cli.rb CHANGED
@@ -14,7 +14,7 @@ module RuboCop
14
14
  ignore_disable_comments lint only only_guide_cops require safe
15
15
  ].freeze
16
16
 
17
- class Finished < RuntimeError; end
17
+ class Finished < StandardError; end
18
18
 
19
19
  attr_reader :options, :config_store
20
20
 
@@ -19,7 +19,13 @@ module RuboCop
19
19
  end
20
20
 
21
21
  def self.parse(identifier)
22
- new(identifier.split('/'))
22
+ new(identifier.split('/').map { |i| camel_case(i) })
23
+ end
24
+
25
+ def self.camel_case(name_part)
26
+ return 'RSpec' if name_part == 'rspec'
27
+
28
+ name_part.gsub(/^\w|_\w/) { |match| match[-1, 1].upcase }
23
29
  end
24
30
 
25
31
  def initialize(class_name_parts)
@@ -5,9 +5,10 @@ module RuboCop
5
5
  module Gemspec
6
6
  # Requires a gemspec to have `rubygems_mfa_required` metadata set.
7
7
  #
8
- # This setting tells RubyGems that MFA is required for accounts to
9
- # be able perform privileged operations, such as (see
10
- # RubyGems' documentation for the full list of privileged operations):
8
+ # This setting tells RubyGems that MFA (Multi-Factor Authentication) is
9
+ # required for accounts to be able perform privileged operations, such as
10
+ # (see RubyGems' documentation for the full list of privileged
11
+ # operations):
11
12
  #
12
13
  # * `gem push`
13
14
  # * `gem yank`
@@ -8,13 +8,7 @@ module RuboCop
8
8
  # and spec file when given a valid qualified cop name.
9
9
  # @api private
10
10
  class Generator
11
- # NOTE: RDoc 5.1.0 or lower has the following issue.
12
- # https://github.com/rubocop/rubocop/issues/7043
13
- #
14
- # The following `String#gsub` can be replaced with
15
- # squiggly heredoc when RuboCop supports Ruby 2.5 or higher
16
- # (RDoc 6.0 or higher).
17
- SOURCE_TEMPLATE = <<-RUBY.gsub(/^ {8}/, '')
11
+ SOURCE_TEMPLATE = <<~RUBY
18
12
  # frozen_string_literal: true
19
13
 
20
14
  module RuboCop
@@ -68,6 +62,7 @@ module RuboCop
68
62
  # For example
69
63
  MSG = 'Use `#good_method` instead of `#bad_method`.'
70
64
 
65
+ # @!method bad_method?(node)
71
66
  def_node_matcher :bad_method?, <<~PATTERN
72
67
  (send nil? :bad_method ...)
73
68
  PATTERN
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for redundant `:config` parameter in the `context` arguments.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # context 'foo', :config do
12
+ # end
13
+ #
14
+ # # good
15
+ # context 'foo' do
16
+ # end
17
+ #
18
+ class RedundantContextConfigParameter < Base
19
+ include RangeHelp
20
+ extend AutoCorrector
21
+
22
+ MSG = 'Remove the redundant `:config` parameter.'
23
+ RESTRICT_ON_SEND = %i[context].freeze
24
+
25
+ def on_send(node)
26
+ arguments = node.arguments
27
+ config_node = arguments.detect { |argument| argument.source == ':config' }
28
+ return unless config_node
29
+
30
+ add_offense(config_node) do |corrector|
31
+ dup_arguments = arguments.dup
32
+ dup_arguments.delete(config_node)
33
+
34
+ corrector.replace(offense_range(arguments), dup_arguments.map(&:source).join(', '))
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ def offense_range(arguments)
41
+ range_between(arguments.first.source_range.begin_pos, arguments.last.source_range.end_pos)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -9,6 +9,7 @@ require_relative 'internal_affairs/node_destructuring'
9
9
  require_relative 'internal_affairs/node_matcher_directive'
10
10
  require_relative 'internal_affairs/node_type_predicate'
11
11
  require_relative 'internal_affairs/offense_location_keyword'
12
+ require_relative 'internal_affairs/redundant_context_config_parameter'
12
13
  require_relative 'internal_affairs/redundant_described_class_as_subject'
13
14
  require_relative 'internal_affairs/redundant_let_rubocop_config_new'
14
15
  require_relative 'internal_affairs/redundant_location_argument'
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # This cop checks how the `when` and `in`s of a `case` expression
6
+ # This cop checks how the `when` and ``in``s of a `case` expression
7
7
  # are indented in relation to its `case` or `end` keyword.
8
8
  #
9
9
  # It will register a separate offense for each misaligned `when` and `in`.
@@ -3,27 +3,26 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Layout
6
- # This cop checks the indentation of the right hand side operand in
7
- # binary operations that span more than one line.
6
+ # This cop checks the indentation of the right hand side operand in binary operations that
7
+ # span more than one line.
8
8
  #
9
- # The `aligned` style checks that operators are aligned if they are part
10
- # of an `if` or `while` condition, a `return` statement, etc. In other
11
- # contexts, the second operand should be indented regardless of enforced
12
- # style.
9
+ # The `aligned` style checks that operators are aligned if they are part of an `if` or `while`
10
+ # condition, an explicit `return` statement, etc. In other contexts, the second operand should
11
+ # be indented regardless of enforced style.
13
12
  #
14
13
  # @example EnforcedStyle: aligned (default)
15
14
  # # bad
16
15
  # if a +
17
16
  # b
18
17
  # something &&
19
- # something_else
18
+ # something_else
20
19
  # end
21
20
  #
22
21
  # # good
23
22
  # if a +
24
23
  # b
25
24
  # something &&
26
- # something_else
25
+ # something_else
27
26
  # end
28
27
  #
29
28
  # @example EnforcedStyle: indented
@@ -3,12 +3,16 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # This cop looks for error classes inheriting from `Exception`
7
- # and its standard library subclasses, excluding subclasses of
8
- # `StandardError`. It is configurable to suggest using either
9
- # `RuntimeError` (default) or `StandardError` instead.
6
+ # This cop looks for error classes inheriting from `Exception`.
7
+ # It is configurable to suggest using either `StandardError` (default) or
8
+ # `RuntimeError` instead.
10
9
  #
11
- # @example EnforcedStyle: runtime_error (default)
10
+ # @safety
11
+ # This cop's autocorrection is unsafe because `rescue` that omit
12
+ # exception class handle `StandardError` and its subclasses,
13
+ # but not `Exception` and its subclasses.
14
+ #
15
+ # @example EnforcedStyle: standard_error (default)
12
16
  # # bad
13
17
  #
14
18
  # class C < Exception; end
@@ -17,11 +21,11 @@ module RuboCop
17
21
  #
18
22
  # # good
19
23
  #
20
- # class C < RuntimeError; end
24
+ # class C < StandardError; end
21
25
  #
22
- # C = Class.new(RuntimeError)
26
+ # C = Class.new(StandardError)
23
27
  #
24
- # @example EnforcedStyle: standard_error
28
+ # @example EnforcedStyle: runtime_error
25
29
  # # bad
26
30
  #
27
31
  # class C < Exception; end
@@ -30,31 +34,18 @@ module RuboCop
30
34
  #
31
35
  # # good
32
36
  #
33
- # class C < StandardError; end
37
+ # class C < RuntimeError; end
34
38
  #
35
- # C = Class.new(StandardError)
39
+ # C = Class.new(RuntimeError)
36
40
  class InheritException < Base
37
41
  include ConfigurableEnforcedStyle
38
42
  extend AutoCorrector
39
43
 
40
- MSG = 'Inherit from `%<prefer>s` instead of `%<current>s`.'
44
+ MSG = 'Inherit from `%<prefer>s` instead of `Exception`.'
41
45
  PREFERRED_BASE_CLASS = {
42
46
  runtime_error: 'RuntimeError',
43
47
  standard_error: 'StandardError'
44
48
  }.freeze
45
- ILLEGAL_CLASSES = %w[
46
- Exception
47
- SystemStackError
48
- NoMemoryError
49
- SecurityError
50
- NotImplementedError
51
- LoadError
52
- SyntaxError
53
- ScriptError
54
- Interrupt
55
- SignalException
56
- SystemExit
57
- ].freeze
58
49
 
59
50
  RESTRICT_ON_SEND = %i[new].freeze
60
51
 
@@ -66,7 +57,7 @@ module RuboCop
66
57
  PATTERN
67
58
 
68
59
  def on_class(node)
69
- return unless node.parent_class && illegal_class_name?(node.parent_class)
60
+ return unless node.parent_class && exception_class?(node.parent_class)
70
61
 
71
62
  message = message(node.parent_class)
72
63
 
@@ -77,7 +68,7 @@ module RuboCop
77
68
 
78
69
  def on_send(node)
79
70
  constant = class_new_call?(node)
80
- return unless constant && illegal_class_name?(constant)
71
+ return unless constant && exception_class?(constant)
81
72
 
82
73
  message = message(constant)
83
74
 
@@ -92,8 +83,8 @@ module RuboCop
92
83
  format(MSG, prefer: preferred_base_class, current: node.const_name)
93
84
  end
94
85
 
95
- def illegal_class_name?(class_node)
96
- ILLEGAL_CLASSES.include?(class_node.const_name)
86
+ def exception_class?(class_node)
87
+ class_node.const_name == 'Exception'
97
88
  end
98
89
 
99
90
  def preferred_base_class
@@ -19,7 +19,7 @@ module RuboCop
19
19
  include RangeHelp
20
20
  extend AutoCorrector
21
21
 
22
- MSG = '`(...)` interpreted as grouped expression.'
22
+ MSG = '`%<argument>s` interpreted as grouped expression.'
23
23
 
24
24
  def on_send(node)
25
25
  return if valid_context?(node)
@@ -28,8 +28,9 @@ module RuboCop
28
28
  return unless space_length.positive?
29
29
 
30
30
  range = space_range(node.first_argument.source_range, space_length)
31
+ message = format(MSG, argument: node.first_argument.source)
31
32
 
32
- add_offense(range) { |corrector| corrector.remove(range) }
33
+ add_offense(range, message: message) { |corrector| corrector.remove(range) }
33
34
  end
34
35
  alias on_csend on_send
35
36
 
@@ -6,6 +6,11 @@ module RuboCop
6
6
  # Sort globbed results by default in Ruby 3.0.
7
7
  # This cop checks for redundant `sort` method to `Dir.glob` and `Dir[]`.
8
8
  #
9
+ # @safety
10
+ # This cop is unsafe, in case of having a file and a directory with
11
+ # identical names, since directory will be loaded before the file, which
12
+ # will break `exe/files.rb` that rely on `exe.rb` file.
13
+ #
9
14
  # @example
10
15
  #
11
16
  # # bad
@@ -51,20 +51,24 @@ module RuboCop
51
51
  node = node.block_node if node.block_literal?
52
52
 
53
53
  add_offense(node, message: format(MSG, count: count)) do |corrector|
54
- next unless own_line?(node)
55
-
56
- if never_process?(count, node)
57
- remove_node(corrector, node)
58
- elsif !proc_name.empty?
59
- autocorrect_block_pass(corrector, node, proc_name)
60
- else
61
- autocorrect_block(corrector, node)
62
- end
54
+ next if !own_line?(node) || node.parent&.send_type?
55
+
56
+ autocorrect(corrector, count, node, proc_name)
63
57
  end
64
58
  end
65
59
 
66
60
  private
67
61
 
62
+ def autocorrect(corrector, count, node, proc_name)
63
+ if never_process?(count, node)
64
+ remove_node(corrector, node)
65
+ elsif !proc_name.empty?
66
+ autocorrect_block_pass(corrector, node, proc_name)
67
+ else
68
+ autocorrect_block(corrector, node)
69
+ end
70
+ end
71
+
68
72
  def never_process?(count, node)
69
73
  count < 1 || (node.block_type? && node.body.nil?)
70
74
  end
@@ -41,7 +41,7 @@ module RuboCop
41
41
  end
42
42
 
43
43
  def require_hash_value?(hash_key_source, node)
44
- return true if require_hash_value_for_around_hash_literal?(node)
44
+ return true if !node.key.sym_type? || require_hash_value_for_around_hash_literal?(node)
45
45
 
46
46
  hash_value = node.value
47
47
  return true unless hash_value.send_type? || hash_value.lvar_type?
@@ -7,17 +7,21 @@ module RuboCop
7
7
  # potential security issues leading to remote code execution when
8
8
  # loading from an untrusted source.
9
9
  #
10
+ # NOTE: Ruby 3.1+ (Psych 4) uses `Psych.load` as `Psych.safe_load` by default.
11
+ #
10
12
  # @safety
11
13
  # The behaviour of the code might change depending on what was
12
14
  # in the YAML payload, since `YAML.safe_load` is more restrictive.
13
15
  #
14
16
  # @example
15
17
  # # bad
16
- # YAML.load("--- foo")
18
+ # YAML.load("--- !ruby/object:Foo {}") # Psych 3 is unsafe by default
17
19
  #
18
20
  # # good
19
- # YAML.safe_load("--- foo")
20
- # YAML.dump("foo")
21
+ # YAML.safe_load("--- !ruby/object:Foo {}", [Foo]) # Ruby 2.5 (Psych 3)
22
+ # YAML.safe_load("--- !ruby/object:Foo {}", permitted_classes: [Foo]) # Ruby 3.0- (Psych 3)
23
+ # YAML.load("--- !ruby/object:Foo {}", permitted_classes: [Foo]) # Ruby 3.1+ (Psych 4)
24
+ # YAML.dump(foo)
21
25
  #
22
26
  class YAMLLoad < Base
23
27
  extend AutoCorrector
@@ -31,6 +35,8 @@ module RuboCop
31
35
  PATTERN
32
36
 
33
37
  def on_send(node)
38
+ return if target_ruby_version >= 3.1
39
+
34
40
  yaml_load(node) do
35
41
  add_offense(node.loc.selector) do |corrector|
36
42
  corrector.replace(node.loc.selector, 'safe_load')
@@ -11,27 +11,33 @@ module RuboCop
11
11
  #
12
12
  # # bad
13
13
  # def foo()
14
- # # does a thing
14
+ # do_something
15
15
  # end
16
16
  #
17
17
  # # good
18
18
  # def foo
19
- # # does a thing
19
+ # do_something
20
20
  # end
21
21
  #
22
- # # also good
23
- # def foo() does_a_thing end
22
+ # # bad
23
+ # def foo() = do_something
24
+ #
25
+ # # good
26
+ # def foo = do_something
27
+ #
28
+ # # good (without parentheses it's a syntax error)
29
+ # def foo() do_something end
24
30
  #
25
31
  # @example
26
32
  #
27
33
  # # bad
28
34
  # def Baz.foo()
29
- # # does a thing
35
+ # do_something
30
36
  # end
31
37
  #
32
38
  # # good
33
39
  # def Baz.foo
34
- # # does a thing
40
+ # do_something
35
41
  # end
36
42
  class DefWithParentheses < Base
37
43
  extend AutoCorrector
@@ -39,12 +45,11 @@ module RuboCop
39
45
  MSG = "Omit the parentheses in defs when the method doesn't accept any arguments."
40
46
 
41
47
  def on_def(node)
42
- return if node.single_line?
43
- return unless !node.arguments? && (node_arguments_loc_begin = node.arguments.loc.begin)
48
+ return if node.single_line? && !node.endless?
49
+ return unless !node.arguments? && (node_arguments = node.arguments.source_range)
44
50
 
45
- add_offense(node_arguments_loc_begin) do |corrector|
46
- corrector.remove(node_arguments_loc_begin)
47
- corrector.remove(node.arguments.loc.end)
51
+ add_offense(node_arguments) do |corrector|
52
+ corrector.remove(node_arguments)
48
53
  end
49
54
  end
50
55
  alias on_defs on_def
@@ -38,6 +38,10 @@ module RuboCop
38
38
  # end
39
39
  # end
40
40
  #
41
+ # @safety
42
+ # This cop's autocorrection is unsafe because the scope of
43
+ # variables is different between `each` and `for`.
44
+ #
41
45
  class For < Base
42
46
  include ConfigurableEnforcedStyle
43
47
  include RangeHelp
@@ -22,45 +22,37 @@ module RuboCop
22
22
  include ConfigurableEnforcedStyle
23
23
  extend AutoCorrector
24
24
 
25
+ MSG = 'Prefer the use of `%<prefer>s` over `%<current>s`.'
25
26
  RESTRICT_ON_SEND = %i[call].freeze
26
27
 
27
28
  def on_send(node)
28
29
  return unless node.receiver
29
30
 
30
31
  if offense?(node)
31
- add_offense(node) do |corrector|
32
+ prefer = prefer(node)
33
+ current = node.source
34
+
35
+ add_offense(node, message: format(MSG, prefer: prefer, current: current)) do |corrector|
32
36
  opposite_style_detected
33
- autocorrect(corrector, node)
37
+ corrector.replace(node, prefer)
34
38
  end
35
39
  else
36
40
  correct_style_detected
37
41
  end
38
42
  end
39
43
 
40
- def autocorrect(corrector, node)
41
- if explicit_style?
42
- receiver = node.receiver.source
43
- replacement = node.source.sub("#{receiver}.", "#{receiver}.call")
44
-
45
- corrector.replace(node, replacement)
46
- else
47
- add_parentheses(node, corrector) unless node.parenthesized?
48
- corrector.remove(node.loc.selector)
49
- end
50
- end
51
-
52
44
  private
53
45
 
54
46
  def offense?(node)
55
47
  (explicit_style? && node.implicit_call?) || (implicit_style? && !node.implicit_call?)
56
48
  end
57
49
 
58
- def message(_node)
59
- if explicit_style?
60
- 'Prefer the use of `lambda.call(...)` over `lambda.(...)`.'
61
- else
62
- 'Prefer the use of `lambda.(...)` over `lambda.call(...)`.'
63
- end
50
+ def prefer(node)
51
+ receiver = node.receiver.source
52
+ arguments = node.arguments.map(&:source).join(', ')
53
+ method = explicit_style? ? "call(#{arguments})" : "(#{arguments})"
54
+
55
+ "#{receiver}.#{method}"
64
56
  end
65
57
 
66
58
  def implicit_style?
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for nested `File.dirname`.
7
+ # It replaces nested `File.dirname` with the level argument introduced in Ruby 3.1.
8
+ #
9
+ # @example
10
+ #
11
+ # # bad
12
+ # File.dirname(File.dirname(path))
13
+ #
14
+ # # good
15
+ # File.dirname(path, 2)
16
+ #
17
+ class NestedFileDirname < Base
18
+ include RangeHelp
19
+ extend AutoCorrector
20
+ extend TargetRubyVersion
21
+
22
+ MSG = 'Use `dirname(%<path>s, %<level>s)` instead.'
23
+ RESTRICT_ON_SEND = %i[dirname].freeze
24
+
25
+ minimum_target_ruby_version 3.1
26
+
27
+ # @!method file_dirname?(node)
28
+ def_node_matcher :file_dirname?, <<~PATTERN
29
+ (send
30
+ (const {cbase nil?} :File) :dirname ...)
31
+ PATTERN
32
+
33
+ def on_send(node)
34
+ return if file_dirname?(node.parent) || !file_dirname?(node.first_argument)
35
+
36
+ path, level = path_with_dir_level(node, 1)
37
+ return if level < 2
38
+
39
+ message = format(MSG, path: path, level: level)
40
+ range = offense_range(node)
41
+
42
+ add_offense(range, message: message) do |corrector|
43
+ corrector.replace(range, "dirname(#{path}, #{level})")
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def path_with_dir_level(node, level)
50
+ first_argument = node.first_argument
51
+
52
+ if file_dirname?(first_argument)
53
+ level += 1
54
+ path_with_dir_level(first_argument, level)
55
+ else
56
+ [first_argument.source, level]
57
+ end
58
+ end
59
+
60
+ def offense_range(node)
61
+ range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -54,8 +54,9 @@ module RuboCop
54
54
  private
55
55
 
56
56
  def format_message(argument)
57
- source = argument.source
58
- format(MSG, original: source, replacement: source.sub(/\s+=/, ':'))
57
+ replacement = "#{argument.name}: #{argument.default_value.source}"
58
+
59
+ format(MSG, original: argument.source, replacement: replacement)
59
60
  end
60
61
  end
61
62
  end
@@ -134,7 +134,13 @@ module RuboCop
134
134
  end
135
135
 
136
136
  def uncorrectable?(part)
137
- part.multiline? || (part.str_type? && part.heredoc?) || part.each_descendant(:block).any?
137
+ part.multiline? || heredoc?(part) || part.each_descendant(:block).any?
138
+ end
139
+
140
+ def heredoc?(node)
141
+ return false unless node.str_type? || node.dstr_type?
142
+
143
+ node.heredoc?
138
144
  end
139
145
 
140
146
  def corrected_ancestor?(node)
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # last item of all non-empty, multiline array literals.
11
11
  # * `comma`: Requires a comma after last item in an array,
12
12
  # but only when each item is on its own line.
13
- # * `no_comma`: Does not requires a comma after the
13
+ # * `no_comma`: Does not require a comma after the
14
14
  # last item in an array
15
15
  #
16
16
  # @example EnforcedStyleForMultiline: consistent_comma
@@ -10,7 +10,7 @@ module RuboCop
10
10
  # last item of all non-empty, multiline hash literals.
11
11
  # * `comma`: Requires a comma after the last item in a hash,
12
12
  # but only when each item is on its own line.
13
- # * `no_comma`: Does not requires a comma after the
13
+ # * `no_comma`: Does not require a comma after the
14
14
  # last item in a hash
15
15
  #
16
16
  # @example EnforcedStyleForMultiline: consistent_comma
@@ -186,11 +186,7 @@ module RuboCop
186
186
  end
187
187
 
188
188
  def regexp_captured_names(node)
189
- regexp_string = node.children.select(&:str_type?).map do |child|
190
- child.children.first
191
- end.join || ''
192
-
193
- regexp = Regexp.new(regexp_string)
189
+ regexp = node.to_regexp
194
190
 
195
191
  regexp.named_captures.keys
196
192
  end
@@ -191,8 +191,8 @@ class CopsDocumentationGenerator # rubocop:disable Metrics/ClassLength
191
191
 
192
192
  def wrap_backtick(value)
193
193
  if value.is_a?(String)
194
- # Use `+` to prevent text like `**/*.gemspec` from being bold.
195
- value.start_with?('*') ? "`+#{value}+`" : "`#{value}`"
194
+ # Use `+` to prevent text like `**/*.gemspec`, `spec/**/*` from being bold.
195
+ value.include?('*') ? "`+#{value}+`" : "`#{value}`"
196
196
  else
197
197
  "`#{value}`"
198
198
  end
@@ -124,9 +124,9 @@ module RuboCop
124
124
  default_cfg = default_config(cop_name)
125
125
 
126
126
  if supports_safe_auto_correct?(cop_class, default_cfg)
127
- output_buffer.puts '# Cop supports --auto-correct.'
127
+ output_buffer.puts '# This cop supports safe auto-correction (--auto-correct).'
128
128
  elsif supports_unsafe_autocorrect?(cop_class, default_cfg)
129
- output_buffer.puts '# Cop supports --auto-correct-all.'
129
+ output_buffer.puts '# This cop supports unsafe auto-correction (--auto-correct-all).'
130
130
  end
131
131
 
132
132
  return unless default_cfg
@@ -467,8 +467,14 @@ module RuboCop
467
467
  'This option applies to the previously',
468
468
  'specified --format, or the default format',
469
469
  'if no format is specified.'],
470
- fail_level: ['Minimum severity (A/I/R/C/W/E/F) for exit',
471
- 'with error code.'],
470
+ fail_level: ['Minimum severity for exit with error code.',
471
+ ' [A] autocorrect',
472
+ ' [I] info',
473
+ ' [R] refactor',
474
+ ' [C] convention',
475
+ ' [W] warning',
476
+ ' [E] error',
477
+ ' [F] fatal'],
472
478
  display_time: 'Display elapsed time in seconds.',
473
479
  display_only_failed: ['Only output offense messages. Omit passing',
474
480
  'cops. Only valid for --format junit.'],
@@ -135,3 +135,7 @@ end
135
135
  RSpec.shared_context 'ruby 3.1', :ruby31 do
136
136
  let(:ruby_version) { 3.1 }
137
137
  end
138
+
139
+ RSpec.shared_context 'ruby 3.2', :ruby32 do
140
+ let(:ruby_version) { 3.2 }
141
+ end
@@ -8,7 +8,7 @@ module RuboCop
8
8
  class Runner # rubocop:disable Metrics/ClassLength
9
9
  # An exception indicating that the inspection loop got stuck correcting
10
10
  # offenses back and forth.
11
- class InfiniteCorrectionLoop < RuntimeError
11
+ class InfiniteCorrectionLoop < StandardError
12
12
  attr_reader :offenses
13
13
 
14
14
  def initialize(path, offenses_by_iteration, loop_start: -1)
@@ -4,7 +4,7 @@ module RuboCop
4
4
  # The kind of Ruby that code inspected by RuboCop is written in.
5
5
  # @api private
6
6
  class TargetRuby
7
- KNOWN_RUBIES = [2.5, 2.6, 2.7, 3.0, 3.1].freeze
7
+ KNOWN_RUBIES = [2.5, 2.6, 2.7, 3.0, 3.1, 3.2].freeze
8
8
  DEFAULT_VERSION = KNOWN_RUBIES.first
9
9
 
10
10
  OBSOLETE_RUBIES = {
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.25.1'
6
+ STRING = '1.26.0'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, '\
9
9
  'rubocop-ast %<rubocop_ast_version>s, ' \
data/lib/rubocop.rb CHANGED
@@ -552,6 +552,7 @@ require_relative 'rubocop/cop/style/negated_if'
552
552
  require_relative 'rubocop/cop/style/negated_if_else_condition'
553
553
  require_relative 'rubocop/cop/style/negated_unless'
554
554
  require_relative 'rubocop/cop/style/negated_while'
555
+ require_relative 'rubocop/cop/style/nested_file_dirname'
555
556
  require_relative 'rubocop/cop/style/nested_modifier'
556
557
  require_relative 'rubocop/cop/style/nested_parenthesized_calls'
557
558
  require_relative 'rubocop/cop/style/nested_ternary_operator'
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.25.1
4
+ version: 1.26.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: 2022-02-03 00:00:00.000000000 Z
13
+ date: 2022-03-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: parallel
@@ -100,7 +100,7 @@ dependencies:
100
100
  requirements:
101
101
  - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: 1.15.1
103
+ version: 1.16.0
104
104
  - - "<"
105
105
  - !ruby/object:Gem::Version
106
106
  version: '2.0'
@@ -110,7 +110,7 @@ dependencies:
110
110
  requirements:
111
111
  - - ">="
112
112
  - !ruby/object:Gem::Version
113
- version: 1.15.1
113
+ version: 1.16.0
114
114
  - - "<"
115
115
  - !ruby/object:Gem::Version
116
116
  version: '2.0'
@@ -269,6 +269,7 @@ files:
269
269
  - lib/rubocop/cop/internal_affairs/node_matcher_directive.rb
270
270
  - lib/rubocop/cop/internal_affairs/node_type_predicate.rb
271
271
  - lib/rubocop/cop/internal_affairs/offense_location_keyword.rb
272
+ - lib/rubocop/cop/internal_affairs/redundant_context_config_parameter.rb
272
273
  - lib/rubocop/cop/internal_affairs/redundant_described_class_as_subject.rb
273
274
  - lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb
274
275
  - lib/rubocop/cop/internal_affairs/redundant_location_argument.rb
@@ -737,6 +738,7 @@ files:
737
738
  - lib/rubocop/cop/style/negated_if_else_condition.rb
738
739
  - lib/rubocop/cop/style/negated_unless.rb
739
740
  - lib/rubocop/cop/style/negated_while.rb
741
+ - lib/rubocop/cop/style/nested_file_dirname.rb
740
742
  - lib/rubocop/cop/style/nested_modifier.rb
741
743
  - lib/rubocop/cop/style/nested_parenthesized_calls.rb
742
744
  - lib/rubocop/cop/style/nested_ternary_operator.rb
@@ -911,7 +913,7 @@ metadata:
911
913
  homepage_uri: https://rubocop.org/
912
914
  changelog_uri: https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md
913
915
  source_code_uri: https://github.com/rubocop/rubocop/
914
- documentation_uri: https://docs.rubocop.org/rubocop/1.25/
916
+ documentation_uri: https://docs.rubocop.org/rubocop/1.26/
915
917
  bug_tracker_uri: https://github.com/rubocop/rubocop/issues
916
918
  rubygems_mfa_required: 'true'
917
919
  post_install_message: