rubocop 1.25.0 → 1.26.1

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +25 -15
  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/empty_lines_around_exception_handling_keywords.rb +5 -1
  12. data/lib/rubocop/cop/layout/hash_alignment.rb +6 -1
  13. data/lib/rubocop/cop/layout/multiline_operation_indentation.rb +7 -8
  14. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  15. data/lib/rubocop/cop/lint/inherit_exception.rb +19 -28
  16. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +3 -2
  17. data/lib/rubocop/cop/lint/redundant_dir_glob_sort.rb +5 -0
  18. data/lib/rubocop/cop/lint/symbol_conversion.rb +3 -2
  19. data/lib/rubocop/cop/lint/useless_times.rb +13 -9
  20. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +27 -13
  21. data/lib/rubocop/cop/mixin/line_length_help.rb +17 -6
  22. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +3 -1
  23. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  24. data/lib/rubocop/cop/security/yaml_load.rb +9 -3
  25. data/lib/rubocop/cop/style/def_with_parentheses.rb +16 -11
  26. data/lib/rubocop/cop/style/for.rb +4 -0
  27. data/lib/rubocop/cop/style/lambda_call.rb +12 -20
  28. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -5
  29. data/lib/rubocop/cop/style/nested_file_dirname.rb +66 -0
  30. data/lib/rubocop/cop/style/optional_boolean_parameter.rb +3 -2
  31. data/lib/rubocop/cop/style/redundant_begin.rb +2 -6
  32. data/lib/rubocop/cop/style/select_by_regexp.rb +6 -1
  33. data/lib/rubocop/cop/style/sole_nested_conditional.rb +50 -12
  34. data/lib/rubocop/cop/style/string_concatenation.rb +7 -1
  35. data/lib/rubocop/cop/style/swap_values.rb +2 -0
  36. data/lib/rubocop/cop/style/trailing_comma_in_array_literal.rb +1 -1
  37. data/lib/rubocop/cop/style/trailing_comma_in_hash_literal.rb +1 -1
  38. data/lib/rubocop/cop/style/unless_else.rb +4 -0
  39. data/lib/rubocop/cop/variable_force.rb +1 -5
  40. data/lib/rubocop/cops_documentation_generator.rb +2 -2
  41. data/lib/rubocop/formatter/disabled_config_formatter.rb +16 -2
  42. data/lib/rubocop/options.rb +8 -2
  43. data/lib/rubocop/rspec/shared_contexts.rb +4 -0
  44. data/lib/rubocop/runner.rb +1 -1
  45. data/lib/rubocop/target_ruby.rb +1 -1
  46. data/lib/rubocop/version.rb +1 -1
  47. data/lib/rubocop.rb +1 -0
  48. metadata +7 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0e565e6065561954dc1aa6db221e2f6cf7753a96b40bf863a571243a2b567d84
4
- data.tar.gz: e489fdb8174dcc6f755ae18bf57091188808e3649db33ae0c282c507b0ec4f54
3
+ metadata.gz: 10e6b8905d81b2204fd3d0bf60d3278cd902d0cefc2ed387bf2c317062b46034
4
+ data.tar.gz: f27011464d465728f1fa470c85c4779c2b148b3cdc872247c5a25d421f269076
5
5
  SHA512:
6
- metadata.gz: 2c01d7352515c439403d4f479583d4099f4ac339ab8a26503ad6b6fd90db54d5a4bcddd6fc2d2e48f3de8faf2928f0f0930c938a5b22a7cfe1759199f68e873a
7
- data.tar.gz: 3075cb42f837c728c31a936ddf1a61ba5d6aafcae9a984a97d05a519089ef7b9c4ff164cf9e3d45e1cd0ab6505a2348f4870bb6c0044e011c45eae04de123e45
6
+ metadata.gz: 215ee2bb6f0699fdedcd82c7795c40e2350c33fdfbd48117dbb2fdcaa957bcbff9a65ad9c95b9666d4b9c70d6a2e2d8b6ec6904c3c3f01cbbfa8fee2319c9518
7
+ data.tar.gz: 0b33b7c3aecf2b7482e19cdbf1a94a56f21d3cb14035c68c62ce0572385edb34a59faa1ea5fb21d9504b04e18f797b0419c6ade76ff70604311b9f899e28b39d
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:
@@ -430,13 +430,13 @@ Layout/ClassStructure:
430
430
  - prepend
431
431
  - extend
432
432
  ExpectedOrder:
433
- - module_inclusion
434
- - constants
435
- - public_class_methods
436
- - initializer
437
- - public_methods
438
- - protected_methods
439
- - private_methods
433
+ - module_inclusion
434
+ - constants
435
+ - public_class_methods
436
+ - initializer
437
+ - public_methods
438
+ - protected_methods
439
+ - private_methods
440
440
 
441
441
  Layout/ClosingHeredocIndentation:
442
442
  Description: 'Checks the indentation of here document closings.'
@@ -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.'
@@ -1900,7 +1902,7 @@ Lint/NestedPercentLiteral:
1900
1902
  VersionAdded: '0.52'
1901
1903
 
1902
1904
  Lint/NextWithoutAccumulator:
1903
- Description: >-
1905
+ Description: >-
1904
1906
  Do not omit the accumulator when calling `next`
1905
1907
  in a `reduce`/`inject` block.
1906
1908
  Enabled: true
@@ -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.'
@@ -3153,7 +3157,7 @@ Style/ClassMethodsDefinitions:
3153
3157
  StyleGuide: '#def-self-class-methods'
3154
3158
  Enabled: false
3155
3159
  VersionAdded: '0.89'
3156
- EnforcedStyle: def_self
3160
+ EnforcedStyle: def_self
3157
3161
  SupportedStyles:
3158
3162
  - def_self
3159
3163
  - self_class
@@ -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
@@ -3815,8 +3820,8 @@ Style/InverseMethods:
3815
3820
  :>: :<=
3816
3821
  # `ActiveSupport` defines some common inverse methods. They are listed below,
3817
3822
  # and not enabled by default.
3818
- #:present?: :blank?,
3819
- #:include?: :exclude?
3823
+ # :present?: :blank?,
3824
+ # :include?: :exclude?
3820
3825
  # `InverseBlocks` are methods that are inverted by inverting the return
3821
3826
  # of the block that is passed to the method
3822
3827
  InverseBlocks:
@@ -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`.
@@ -81,7 +81,7 @@ module RuboCop
81
81
 
82
82
  locations.each do |loc|
83
83
  line = loc.line
84
- next if line == line_of_def_or_kwbegin
84
+ next if line == line_of_def_or_kwbegin || last_rescue_and_end_on_same_line(body)
85
85
 
86
86
  keyword = loc.source
87
87
  # below the keyword
@@ -91,6 +91,10 @@ module RuboCop
91
91
  end
92
92
  end
93
93
 
94
+ def last_rescue_and_end_on_same_line(body)
95
+ body.rescue_type? && body.resbody_branches.last.loc.line == body.parent.loc.end.line
96
+ end
97
+
94
98
  def message(location, keyword)
95
99
  format(MSG, location: location, keyword: keyword)
96
100
  end
@@ -222,11 +222,16 @@ module RuboCop
222
222
  node.pairs.any? &&
223
223
  node.parent&.call_type?
224
224
 
225
+ left_sibling = argument_before_hash(node)
225
226
  parent_loc = node.parent.loc
226
- selector = parent_loc.selector || parent_loc.expression
227
+ selector = left_sibling || parent_loc.selector || parent_loc.expression
227
228
  same_line?(selector, node.pairs.first)
228
229
  end
229
230
 
231
+ def argument_before_hash(hash_node)
232
+ hash_node.left_sibling.respond_to?(:loc) ? hash_node.left_sibling : nil
233
+ end
234
+
230
235
  def reset!
231
236
  self.offenses_by = {}
232
237
  self.column_deltas = Hash.new { |hash, key| hash[key] = {} }
@@ -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
@@ -143,7 +143,7 @@ module RuboCop
143
143
  return true
144
144
  end
145
145
 
146
- do_keyword_line == selector.line && rescue_keyword_column == selector.column
146
+ do_keyword_line == selector&.line && rescue_keyword_column == selector.column
147
147
  end
148
148
 
149
149
  def aligned_with_leading_dot?(do_keyword_line, send_node_loc, rescue_keyword_column)
@@ -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
@@ -147,13 +147,14 @@ module RuboCop
147
147
  # will be ignored.
148
148
  return unless node.value.to_s.match?(/\A[a-z0-9_]/i)
149
149
 
150
- correction = node.value.inspect.delete_prefix(':')
150
+ correction = node.value.inspect
151
+ correction = correction.delete_prefix(':') if node.parent.colon?
151
152
  return if properly_quoted?(node.source, correction)
152
153
 
153
154
  register_offense(
154
155
  node,
155
156
  correction: correction,
156
- message: format(MSG, correction: "#{correction}:")
157
+ message: format(MSG, correction: node.parent.colon? ? "#{correction}:" : correction)
157
158
  )
158
159
  end
159
160
 
@@ -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
@@ -8,7 +8,7 @@ module RuboCop
8
8
  EXPLICIT_HASH_VALUE_MSG = 'Explicit the hash value.'
9
9
 
10
10
  def on_pair(node)
11
- return if target_ruby_version <= 3.0 || enforced_shorthand_syntax == 'either'
11
+ return if ignore_hash_shorthand_syntax?(node)
12
12
 
13
13
  hash_key_source = node.key.source
14
14
 
@@ -31,12 +31,17 @@ module RuboCop
31
31
 
32
32
  private
33
33
 
34
+ def ignore_hash_shorthand_syntax?(pair_node)
35
+ target_ruby_version <= 3.0 || enforced_shorthand_syntax == 'either' ||
36
+ !pair_node.parent.hash_type?
37
+ end
38
+
34
39
  def enforced_shorthand_syntax
35
40
  cop_config.fetch('EnforcedShorthandSyntax', 'always')
36
41
  end
37
42
 
38
43
  def require_hash_value?(hash_key_source, node)
39
- return true if without_parentheses_call_expr_follows?(node)
44
+ return true if !node.key.sym_type? || require_hash_value_for_around_hash_literal?(node)
40
45
 
41
46
  hash_value = node.value
42
47
  return true unless hash_value.send_type? || hash_value.lvar_type?
@@ -44,24 +49,33 @@ module RuboCop
44
49
  hash_key_source != hash_value.source || hash_key_source.end_with?('!', '?')
45
50
  end
46
51
 
47
- def without_parentheses_call_expr_follows?(node)
52
+ def require_hash_value_for_around_hash_literal?(node)
48
53
  return false unless (ancestor = node.parent.parent)
54
+ return false if ancestor.send_type? && ancestor.method?(:[])
49
55
 
50
- right_sibling = ancestor.right_sibling
51
-
52
- return true if right_sibling.nil? && without_parentheses?(ancestor)
53
- return false unless right_sibling
54
- return true if node_with_block_and_arguments?(right_sibling)
56
+ !node.parent.braces? && !use_element_of_hash_literal_as_receiver?(ancestor, node.parent) &&
57
+ (use_modifier_form_without_parenthesized_method_call?(ancestor) ||
58
+ without_parentheses_call_expr_follows?(ancestor))
59
+ end
55
60
 
56
- without_parentheses?(ancestor) && without_parentheses?(right_sibling)
61
+ def use_element_of_hash_literal_as_receiver?(ancestor, parent)
62
+ # `{value:}.do_something` is a valid syntax.
63
+ ancestor.send_type? && ancestor.receiver == parent
57
64
  end
58
65
 
59
- def without_parentheses?(node)
60
- node.respond_to?(:parenthesized?) && !node.parenthesized?
66
+ def use_modifier_form_without_parenthesized_method_call?(ancestor)
67
+ return false if ancestor.respond_to?(:parenthesized?) && ancestor.parenthesized?
68
+ return false unless (parent = ancestor.parent)
69
+
70
+ parent.respond_to?(:modifier_form?) && parent.modifier_form?
61
71
  end
62
72
 
63
- def node_with_block_and_arguments?(node)
64
- node.respond_to?(:block_type?) && node.block_type? && node.children&.first&.arguments?
73
+ def without_parentheses_call_expr_follows?(ancestor)
74
+ right_sibling = ancestor.right_sibling
75
+ right_sibling ||= ancestor.each_ancestor.find(&:assignment?)&.right_sibling
76
+ return false unless right_sibling
77
+
78
+ ancestor.respond_to?(:parenthesized?) && !ancestor.parenthesized? && !!right_sibling
65
79
  end
66
80
  end
67
81
  end
@@ -39,12 +39,7 @@ module RuboCop
39
39
  pos + indentation_difference(line)
40
40
  end
41
41
 
42
- # Extend the end position until the start of the next word, if any.
43
- # This allows for URIs that are wrapped in quotes or parens to be handled properly
44
- # while not allowing additional words to be added after the URL.
45
- if (match = line[end_position..line_length(line)]&.match(/^\S+(?=\s|$)/))
46
- end_position += match.offset(0).last
47
- end
42
+ end_position = extend_uri_end_position(line, end_position)
48
43
 
49
44
  return nil if begin_position < max_line_length && end_position < max_line_length
50
45
 
@@ -65,6 +60,22 @@ module RuboCop
65
60
  (line.index(/[^\t]/) || 0) * (tab_indentation_width - 1)
66
61
  end
67
62
 
63
+ def extend_uri_end_position(line, end_position)
64
+ # Extend the end position YARD comments with linked URLs of the form {<uri> <title>}
65
+ if line&.match(/{(\s|\S)*}$/)
66
+ match = line[end_position..line_length(line)]&.match(/(\s|\S)*}/)
67
+ end_position += match.offset(0).last
68
+ end
69
+
70
+ # Extend the end position until the start of the next word, if any.
71
+ # This allows for URIs that are wrapped in quotes or parens to be handled properly
72
+ # while not allowing additional words to be added after the URL.
73
+ if (match = line[end_position..line_length(line)]&.match(/^\S+(?=\s|$)/))
74
+ end_position += match.offset(0).last
75
+ end
76
+ end_position
77
+ end
78
+
68
79
  def tab_indentation_width
69
80
  config.for_cop('Layout/IndentationStyle')['IndentationWidth'] ||
70
81
  config.for_cop('Layout/IndentationWidth')['Width']
@@ -29,7 +29,9 @@ module RuboCop
29
29
  # b c { block }. <-- b is indented relative to a
30
30
  # d <-- d is indented relative to a
31
31
  def left_hand_side(lhs)
32
- lhs = lhs.parent while lhs.parent&.send_type? && lhs.parent.loc.dot
32
+ while lhs.parent&.send_type? && lhs.parent.loc.dot && !lhs.parent.assignment_method?
33
+ lhs = lhs.parent
34
+ end
33
35
  lhs
34
36
  end
35
37
 
@@ -26,7 +26,7 @@ module RuboCop
26
26
  # num1 * num2
27
27
  # end
28
28
  #
29
- # # With `MinArgNameLength` set to number greater than 1
29
+ # # With `MinNameLength` set to number greater than 1
30
30
  # def baz(a, b, c)
31
31
  # do_stuff(a, b, c)
32
32
  # end