rubocop 1.57.2 → 1.58.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/config/default.yml +37 -2
  4. data/lib/rubocop/config_obsoletion.rb +11 -8
  5. data/lib/rubocop/cop/bundler/gem_comment.rb +2 -2
  6. data/lib/rubocop/cop/gemspec/deprecated_attribute_assignment.rb +2 -2
  7. data/lib/rubocop/cop/internal_affairs/method_name_equal.rb +19 -20
  8. data/lib/rubocop/cop/internal_affairs/node_first_or_last_argument.rb +53 -0
  9. data/lib/rubocop/cop/internal_affairs/node_matcher_directive.rb +2 -2
  10. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  11. data/lib/rubocop/cop/layout/argument_alignment.rb +1 -1
  12. data/lib/rubocop/cop/layout/extra_spacing.rb +4 -10
  13. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +6 -6
  14. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  15. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +2 -2
  16. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +4 -4
  17. data/lib/rubocop/cop/layout/single_line_block_chain.rb +4 -0
  18. data/lib/rubocop/cop/layout/space_around_operators.rb +50 -20
  19. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -4
  20. data/lib/rubocop/cop/lint/debugger.rb +2 -1
  21. data/lib/rubocop/cop/lint/duplicate_methods.rb +1 -1
  22. data/lib/rubocop/cop/lint/erb_new_arguments.rb +3 -3
  23. data/lib/rubocop/cop/lint/float_comparison.rb +10 -0
  24. data/lib/rubocop/cop/lint/literal_assignment_in_condition.rb +64 -0
  25. data/lib/rubocop/cop/lint/non_deterministic_require_order.rb +3 -5
  26. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +43 -0
  27. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +3 -4
  28. data/lib/rubocop/cop/lint/self_assignment.rb +37 -0
  29. data/lib/rubocop/cop/lint/symbol_conversion.rb +7 -2
  30. data/lib/rubocop/cop/lint/trailing_comma_in_attribute_declaration.rb +1 -1
  31. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  32. data/lib/rubocop/cop/lint/void.rb +14 -1
  33. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  34. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +1 -1
  35. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  36. data/lib/rubocop/cop/naming/block_forwarding.rb +2 -2
  37. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  38. data/lib/rubocop/cop/style/access_modifier_declarations.rb +2 -2
  39. data/lib/rubocop/cop/style/accessor_grouping.rb +1 -1
  40. data/lib/rubocop/cop/style/arguments_forwarding.rb +68 -6
  41. data/lib/rubocop/cop/style/array_first_last.rb +64 -0
  42. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +21 -14
  43. data/lib/rubocop/cop/style/bisected_attr_accessor.rb +2 -2
  44. data/lib/rubocop/cop/style/case_like_if.rb +4 -4
  45. data/lib/rubocop/cop/style/combinable_loops.rb +2 -7
  46. data/lib/rubocop/cop/style/conditional_assignment.rb +1 -1
  47. data/lib/rubocop/cop/style/empty_literal.rb +1 -1
  48. data/lib/rubocop/cop/style/eval_with_location.rb +3 -3
  49. data/lib/rubocop/cop/style/explicit_block_argument.rb +2 -2
  50. data/lib/rubocop/cop/style/hash_each_methods.rb +58 -10
  51. data/lib/rubocop/cop/style/inverse_methods.rb +6 -5
  52. data/lib/rubocop/cop/style/map_to_hash.rb +9 -4
  53. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +1 -1
  54. data/lib/rubocop/cop/style/method_def_parentheses.rb +1 -1
  55. data/lib/rubocop/cop/style/missing_respond_to_missing.rb +2 -2
  56. data/lib/rubocop/cop/style/redundant_argument.rb +2 -2
  57. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +3 -3
  58. data/lib/rubocop/cop/style/redundant_line_continuation.rb +2 -0
  59. data/lib/rubocop/cop/style/redundant_parentheses.rb +11 -3
  60. data/lib/rubocop/cop/style/redundant_return.rb +1 -1
  61. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  62. data/lib/rubocop/cop/style/redundant_string_escape.rb +1 -1
  63. data/lib/rubocop/cop/style/select_by_regexp.rb +1 -1
  64. data/lib/rubocop/cop/style/self_assignment.rb +1 -1
  65. data/lib/rubocop/cop/style/semicolon.rb +8 -0
  66. data/lib/rubocop/cop/style/slicing_with_range.rb +1 -1
  67. data/lib/rubocop/cop/style/super_with_args_parentheses.rb +35 -0
  68. data/lib/rubocop/formatter/html_formatter.rb +1 -2
  69. data/lib/rubocop/result_cache.rb +0 -1
  70. data/lib/rubocop/runner.rb +1 -1
  71. data/lib/rubocop/version.rb +1 -1
  72. data/lib/rubocop.rb +3 -0
  73. metadata +10 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: adf1db90b03283f492e0e10f234d54d6efc215a8b182965087313e3954d533dd
4
- data.tar.gz: fa84dfd9d61e4834df9287e0ba0619622f4b7eb9e229e8de1172bc1742c04df5
3
+ metadata.gz: b262d82d17790d0993cf662a3ede317cbddfbc38704ae0bbf3108d411fac02d1
4
+ data.tar.gz: e9e7fd1969decd87a3b5e4760331f98bb5b12a48b44b91d9f5a71cb5b79edb89
5
5
  SHA512:
6
- metadata.gz: 44a683eed5e4b9d26caf4d0c775a6f4ba00960b6aaeee29c3f610320d1471326d650e8fc41ee2725af07b4e6a50bf17d442232134522709ebb2a46ec5b80bf40
7
- data.tar.gz: d4f5dda0dbf7689c55b39de3922c2bd1a0c40aa62ac1046f06c98a19e7f2719cfea11babd480ba4e9b9ff2203d20422a51f096165d5919bf564e009c3a91c087
6
+ metadata.gz: 9e6a605d355ff38cdd29726c5e81aeb884757f3fb431beff0dd64f83b05e015f56ec429eccca953142fd85745f3bdbc33b838f1541f7253d422c30ab38b5041d
7
+ data.tar.gz: 2fb1647376fcb6c193fecd74478a3d8913b8efa2ede1bac4c7895d0c42ee94f0f5ec52628e85c3461f930cb9795d18240116f2972d406df136cf4a2fc73f1454
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.57', require: false
56
+ gem 'rubocop', '~> 1.58', require: false
57
57
  ```
58
58
 
59
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
@@ -67,7 +67,7 @@ $ cd my/cool/ruby/project
67
67
  $ rubocop
68
68
  ```
69
69
 
70
- You can also use this magic in your favorite editor with RuboCop's [built-in LSP](https://docs.rubocop.org/rubocop/usage/lsp.html).
70
+ You can also use this magic in your favorite editor with RuboCop's [built-in LSP server](https://docs.rubocop.org/rubocop/usage/lsp.html).
71
71
 
72
72
  ## Documentation
73
73
 
data/config/default.yml CHANGED
@@ -1351,6 +1351,10 @@ Layout/SpaceAroundOperators:
1351
1351
  SupportedStylesForExponentOperator:
1352
1352
  - space
1353
1353
  - no_space
1354
+ EnforcedStyleForRationalLiterals: no_space
1355
+ SupportedStylesForRationalLiterals:
1356
+ - space
1357
+ - no_space
1354
1358
 
1355
1359
  Layout/SpaceBeforeBlockBraces:
1356
1360
  Description: >-
@@ -1969,6 +1973,11 @@ Lint/LiteralAsCondition:
1969
1973
  Enabled: true
1970
1974
  VersionAdded: '0.51'
1971
1975
 
1976
+ Lint/LiteralAssignmentInCondition:
1977
+ Description: 'Checks for literal assignments in the conditions.'
1978
+ Enabled: pending
1979
+ VersionAdded: '1.58'
1980
+
1972
1981
  Lint/LiteralInInterpolation:
1973
1982
  Description: 'Checks for literals used in interpolation.'
1974
1983
  Enabled: true
@@ -3085,7 +3094,19 @@ Style/ArgumentsForwarding:
3085
3094
  Enabled: pending
3086
3095
  AllowOnlyRestArgument: true
3087
3096
  UseAnonymousForwarding: true
3097
+ RedundantRestArgumentNames:
3098
+ - args
3099
+ - arguments
3100
+ RedundantKeywordRestArgumentNames:
3101
+ - kwargs
3102
+ - options
3103
+ - opts
3104
+ RedundantBlockArgumentNames:
3105
+ - blk
3106
+ - block
3107
+ - proc
3088
3108
  VersionAdded: '1.1'
3109
+ VersionChanged: '1.58'
3089
3110
 
3090
3111
  Style/ArrayCoercion:
3091
3112
  Description: >-
@@ -3096,6 +3117,13 @@ Style/ArrayCoercion:
3096
3117
  Enabled: false
3097
3118
  VersionAdded: '0.88'
3098
3119
 
3120
+ Style/ArrayFirstLast:
3121
+ Description: 'Use `arr.first` and `arr.last` instead of `arr[0]` and `arr[-1]`.'
3122
+ Reference: '#first-and-last'
3123
+ Enabled: false
3124
+ VersionAdded: '1.58'
3125
+ Safe: false
3126
+
3099
3127
  Style/ArrayIntersect:
3100
3128
  Description: 'Use `array1.intersect?(array2)` instead of `(array1 & array2).any?`.'
3101
3129
  Enabled: 'pending'
@@ -4902,7 +4930,7 @@ Style/RedundantFetchBlock:
4902
4930
  Description: >-
4903
4931
  Use `fetch(key, value)` instead of `fetch(key) { value }`
4904
4932
  when value has Numeric, Rational, Complex, Symbol or String type, `false`, `true`, `nil` or is a constant.
4905
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#hashfetch-with-argument-vs-hashfetch--block-code'
4933
+ Reference: 'https://github.com/fastruby/fast-ruby#hashfetch-with-argument-vs-hashfetch--block-code'
4906
4934
  Enabled: true
4907
4935
  Safe: false
4908
4936
  # If enabled, this cop will autocorrect usages of
@@ -5123,7 +5151,7 @@ Style/Sample:
5123
5151
  Description: >-
5124
5152
  Use `sample` instead of `shuffle.first`,
5125
5153
  `shuffle.last`, and `shuffle[Integer]`.
5126
- Reference: 'https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code'
5154
+ Reference: 'https://github.com/fastruby/fast-ruby#arrayshufflefirst-vs-arraysample-code'
5127
5155
  Enabled: true
5128
5156
  VersionAdded: '0.30'
5129
5157
 
@@ -5190,6 +5218,7 @@ Style/SingleLineBlockParams:
5190
5218
 
5191
5219
  Style/SingleLineDoEndBlock:
5192
5220
  Description: 'Checks for single-line `do`...`end` blocks.'
5221
+ StyleGuide: '#single-line-do-end-block'
5193
5222
  Enabled: pending
5194
5223
  VersionAdded: '1.57'
5195
5224
 
@@ -5329,6 +5358,12 @@ Style/StructInheritance:
5329
5358
  VersionAdded: '0.29'
5330
5359
  VersionChanged: '1.20'
5331
5360
 
5361
+ Style/SuperWithArgsParentheses:
5362
+ Description: 'Use parentheses for `super` with arguments.'
5363
+ StyleGuide: '#super-with-args'
5364
+ Enabled: pending
5365
+ VersionAdded: '1.58'
5366
+
5332
5367
  Style/SwapValues:
5333
5368
  Description: 'Enforces the use of shorthand-style swapping of 2 variables.'
5334
5369
  StyleGuide: '#values-swapping'
@@ -15,6 +15,8 @@ module RuboCop
15
15
  'changed_parameters' => ChangedParameter,
16
16
  'changed_enforced_styles' => ChangedEnforcedStyles
17
17
  }.freeze
18
+ LOAD_RULES_CACHE = {} # rubocop:disable Style/MutableConstant
19
+ private_constant :LOAD_RULES_CACHE
18
20
 
19
21
  attr_reader :rules, :warnings
20
22
 
@@ -48,16 +50,17 @@ module RuboCop
48
50
  # Default rules for obsoletions are in config/obsoletion.yml
49
51
  # Additional rules files can be added with `RuboCop::ConfigObsoletion.files << filename`
50
52
  def load_rules # rubocop:disable Metrics/AbcSize
51
- rules = self.class.files.each_with_object({}) do |filename, hash|
52
- hash.merge!(YAML.safe_load(File.read(filename))) do |_key, first, second|
53
- case first
54
- when Hash
55
- first.merge(second)
56
- when Array
57
- first.concat(second)
53
+ rules = LOAD_RULES_CACHE[self.class.files] ||=
54
+ self.class.files.each_with_object({}) do |filename, hash|
55
+ hash.merge!(YAML.safe_load(File.read(filename))) do |_key, first, second|
56
+ case first
57
+ when Hash
58
+ first.merge(second)
59
+ when Array
60
+ first.concat(second)
61
+ end
58
62
  end
59
63
  end
60
- end
61
64
 
62
65
  cop_rules = rules.slice(*COP_RULE_CLASSES.keys)
63
66
  parameter_rules = rules.slice(*PARAMETER_RULE_CLASSES.keys)
@@ -161,9 +161,9 @@ module RuboCop
161
161
  end
162
162
 
163
163
  def gem_options(node)
164
- return [] unless node.arguments.last&.type == :hash
164
+ return [] unless node.last_argument&.type == :hash
165
165
 
166
- node.arguments.last.keys.map(&:value)
166
+ node.last_argument.keys.map(&:value)
167
167
  end
168
168
  end
169
169
  end
@@ -43,7 +43,7 @@ module RuboCop
43
43
  def on_block(block_node)
44
44
  return unless gem_specification(block_node)
45
45
 
46
- block_parameter = block_node.arguments.first.source
46
+ block_parameter = block_node.first_argument.source
47
47
 
48
48
  assignment = block_node.descendants.detect do |node|
49
49
  use_deprecated_attributes?(node, block_parameter)
@@ -65,7 +65,7 @@ module RuboCop
65
65
  lhs, _op, _rhs = *node
66
66
  [lhs, attribute]
67
67
  else
68
- [node, "#{attribute}=".to_sym]
68
+ [node, :"#{attribute}="]
69
69
  end
70
70
  end
71
71
 
@@ -12,38 +12,37 @@ module RuboCop
12
12
  # # good
13
13
  # node.method?(:do_something)
14
14
  #
15
+ # # bad
16
+ # node.method_name != :do_something
17
+ #
18
+ # # good
19
+ # !node.method?(:do_something)
20
+ #
15
21
  class MethodNameEqual < Base
16
- include RangeHelp
17
22
  extend AutoCorrector
18
23
 
19
- MSG = 'Use `method?(%<method_name>s)` instead of `method_name == %<method_name>s`.'
20
- RESTRICT_ON_SEND = %i[==].freeze
24
+ MSG = 'Use `%<prefer>s` instead.'
25
+ RESTRICT_ON_SEND = %i[== !=].freeze
21
26
 
22
- # @!method method_name?(node)
23
- def_node_matcher :method_name?, <<~PATTERN
27
+ # @!method method_name(node)
28
+ def_node_matcher :method_name, <<~PATTERN
24
29
  (send
25
- $(send
26
- (...) :method_name) :==
27
- $...)
30
+ (send
31
+ (...) :method_name) {:== :!=}
32
+ $_)
28
33
  PATTERN
29
34
 
30
35
  def on_send(node)
31
- method_name?(node) do |method_name_node, method_name_arg|
32
- message = format(MSG, method_name: method_name_arg.first.source)
36
+ method_name(node) do |method_name_arg|
37
+ bang = node.method?(:!=) ? '!' : ''
38
+ prefer = "#{bang}#{node.receiver.receiver.source}.method?(#{method_name_arg.source})"
39
+ message = format(MSG, prefer: prefer)
33
40
 
34
- range = range(method_name_node, node)
35
-
36
- add_offense(range, message: message) do |corrector|
37
- corrector.replace(range, "method?(#{method_name_arg.first.source})")
41
+ add_offense(node, message: message) do |corrector|
42
+ corrector.replace(node, prefer)
38
43
  end
39
44
  end
40
45
  end
41
-
42
- private
43
-
44
- def range(method_name_node, node)
45
- range_between(method_name_node.loc.selector.begin_pos, node.source_range.end_pos)
46
- end
47
46
  end
48
47
  end
49
48
  end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for the use of `node.arguments.first` or `node.arguments.last` and
7
+ # suggests the use of `node.first_argument` or `node.last_argument` instead.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # node.arguments.first
12
+ # node.arguments[0]
13
+ # node.arguments.last
14
+ # node.arguments[-1]
15
+ #
16
+ # # good
17
+ # node.first_argument
18
+ # node.last_argument
19
+ #
20
+ class NodeFirstOrLastArgument < Base
21
+ extend AutoCorrector
22
+ include RangeHelp
23
+
24
+ MSG = 'Use `#%<correct>s` instead of `#%<incorrect>s`.'
25
+ RESTRICT_ON_SEND = %i[arguments].freeze
26
+
27
+ # @!method arguments_first_or_last?(node)
28
+ def_node_matcher :arguments_first_or_last?, <<~PATTERN
29
+ {
30
+ (send (send !nil? :arguments) ${:first :last})
31
+ (send (send !nil? :arguments) :[] (int ${0 -1}))
32
+ }
33
+ PATTERN
34
+
35
+ def on_send(node)
36
+ arguments_first_or_last?(node.parent) do |end_or_index|
37
+ range = range_between(node.loc.selector.begin_pos, node.parent.source_range.end_pos)
38
+ correct = case end_or_index
39
+ when :first, 0 then 'first_argument'
40
+ when :last, -1 then 'last_argument'
41
+ else raise "Unknown end_or_index: #{end_or_index}"
42
+ end
43
+ message = format(MSG, correct: correct, incorrect: range.source)
44
+
45
+ add_offense(range, message: message) do |corrector|
46
+ corrector.replace(range, correct)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -40,7 +40,7 @@ module RuboCop
40
40
  return if node.arguments.none?
41
41
  return unless valid_method_name?(node)
42
42
 
43
- actual_name = node.arguments.first.value
43
+ actual_name = node.first_argument.value
44
44
  directives = method_directives(node)
45
45
  return too_many_directives(node) if directives.size > 1
46
46
 
@@ -53,7 +53,7 @@ module RuboCop
53
53
  private
54
54
 
55
55
  def valid_method_name?(node)
56
- node.arguments.first.str_type? || node.arguments.first.sym_type?
56
+ node.first_argument.str_type? || node.first_argument.sym_type?
57
57
  end
58
58
 
59
59
  def method_directives(node)
@@ -12,6 +12,7 @@ require_relative 'internal_affairs/location_line_equality_comparison'
12
12
  require_relative 'internal_affairs/method_name_end_with'
13
13
  require_relative 'internal_affairs/method_name_equal'
14
14
  require_relative 'internal_affairs/node_destructuring'
15
+ require_relative 'internal_affairs/node_first_or_last_argument'
15
16
  require_relative 'internal_affairs/node_matcher_directive'
16
17
  require_relative 'internal_affairs/node_type_predicate'
17
18
  require_relative 'internal_affairs/numblock_handler'
@@ -79,7 +79,7 @@ module RuboCop
79
79
 
80
80
  def arguments_with_last_arg_pairs(node)
81
81
  items = node.arguments[0..-2]
82
- last_arg = node.arguments.last
82
+ last_arg = node.last_argument
83
83
 
84
84
  if last_arg.hash_type? && !last_arg.braces?
85
85
  items += last_arg.pairs
@@ -49,19 +49,13 @@ module RuboCop
49
49
 
50
50
  private
51
51
 
52
- def aligned_locations(locs) # rubocop:disable Metrics/AbcSize
52
+ def aligned_locations(locs)
53
53
  return [] if locs.empty?
54
54
 
55
- aligned = Set[locs.first.line, locs.last.line]
56
- locs.each_cons(3) do |before, loc, after|
57
- col = loc.column
58
- aligned << loc.line if col == before.column || col == after.column
55
+ aligned = Set.new
56
+ locs.each_cons(2) do |loc1, loc2|
57
+ aligned << loc1.line << loc2.line if loc1.column == loc2.column
59
58
  end
60
-
61
- # if locs.size > 2 and the size of variable `aligned`
62
- # has not increased from its initial value, there are not aligned lines.
63
- return [] if locs.size > 2 && aligned.size == 2
64
-
65
59
  aligned
66
60
  end
67
61
 
@@ -25,7 +25,7 @@ module RuboCop
25
25
  # # element are on separate lines is indented one step (two spaces) more
26
26
  # # than the position inside the opening parenthesis.
27
27
  #
28
- # #bad
28
+ # # bad
29
29
  # array = [
30
30
  # :value
31
31
  # ]
@@ -33,7 +33,7 @@ module RuboCop
33
33
  # :no_difference
34
34
  # ])
35
35
  #
36
- # #good
36
+ # # good
37
37
  # array = [
38
38
  # :value
39
39
  # ]
@@ -47,7 +47,7 @@ module RuboCop
47
47
  # # separate lines is indented the same as an array literal which is not
48
48
  # # defined inside a method call.
49
49
  #
50
- # #bad
50
+ # # bad
51
51
  # # consistent
52
52
  # array = [
53
53
  # :value
@@ -56,7 +56,7 @@ module RuboCop
56
56
  # :its_like_this
57
57
  # ])
58
58
  #
59
- # #good
59
+ # # good
60
60
  # array = [
61
61
  # :value
62
62
  # ]
@@ -68,13 +68,13 @@ module RuboCop
68
68
  # # The `align_brackets` style enforces that the opening and closing
69
69
  # # brackets are indented to the same position.
70
70
  #
71
- # #bad
71
+ # # bad
72
72
  # # align_brackets
73
73
  # and_now_for_something = [
74
74
  # :completely_different
75
75
  # ]
76
76
  #
77
- # #good
77
+ # # good
78
78
  # # align_brackets
79
79
  # and_now_for_something = [
80
80
  # :completely_different
@@ -72,7 +72,7 @@ module RuboCop
72
72
  return if ignored_node?(def_node)
73
73
 
74
74
  left_parenthesis = def_node.arguments.loc.begin
75
- first_elem = def_node.arguments.first
75
+ first_elem = def_node.first_argument
76
76
  return unless first_elem
77
77
  return if same_line?(first_elem, left_parenthesis)
78
78
 
@@ -182,7 +182,7 @@ module RuboCop
182
182
  end
183
183
 
184
184
  def add_correct_closing_paren(node, corrector)
185
- corrector.insert_after(node.arguments.last, ')')
185
+ corrector.insert_after(node.last_argument, ')')
186
186
  end
187
187
 
188
188
  def remove_incorrect_closing_paren(node, corrector)
@@ -271,7 +271,7 @@ module RuboCop
271
271
  def add_correct_external_trailing_comma(node, corrector)
272
272
  return unless external_trailing_comma?(node)
273
273
 
274
- corrector.insert_after(node.arguments.last, ',')
274
+ corrector.insert_after(node.last_argument, ',')
275
275
  end
276
276
 
277
277
  def remove_incorrect_external_trailing_comma(node, corrector)
@@ -29,7 +29,7 @@ module RuboCop
29
29
  MSG = '`%<kw_loc>s` at %<kw_loc_line>d, %<kw_loc_column>d is not ' \
30
30
  'aligned with `%<beginning>s` at ' \
31
31
  '%<begin_loc_line>d, %<begin_loc_column>d.'
32
- ANCESTOR_TYPES = %i[kwbegin def defs class module block].freeze
32
+ ANCESTOR_TYPES = %i[kwbegin def defs class module block numblock].freeze
33
33
  ANCESTOR_TYPES_WITH_ACCESS_MODIFIERS = %i[def defs].freeze
34
34
  ALTERNATIVE_ACCESS_MODIFIERS = %i[public_class_method private_class_method].freeze
35
35
 
@@ -95,7 +95,7 @@ module RuboCop
95
95
  def alignment_source(node, starting_loc)
96
96
  ending_loc =
97
97
  case node.type
98
- when :block, :kwbegin
98
+ when :block, :numblock, :kwbegin
99
99
  node.loc.begin
100
100
  when :def, :defs, :class, :module,
101
101
  :lvasgn, :ivasgn, :cvasgn, :gvasgn, :casgn
@@ -104,8 +104,8 @@ module RuboCop
104
104
  mlhs_node, = *node
105
105
  mlhs_node.source_range
106
106
  else
107
- # It is a wrapper with access modifier.
108
- node.child_nodes.first.loc.name
107
+ # It is a wrapper with receiver of object attribute or access modifier.
108
+ node.receiver&.source_range || node.child_nodes.first.loc.name
109
109
  end
110
110
 
111
111
  range_between(starting_loc.begin_pos, ending_loc.end_pos).source
@@ -25,6 +25,10 @@ module RuboCop
25
25
 
26
26
  MSG = 'Put method call on a separate line if chained to a single line block.'
27
27
 
28
+ def self.autocorrect_incompatible_with
29
+ [Style::MapToHash]
30
+ end
31
+
28
32
  def on_send(node)
29
33
  range = offending_range(node)
30
34
  add_offense(range) { |corrector| corrector.insert_before(range, "\n") } if range
@@ -50,6 +50,20 @@ module RuboCop
50
50
  #
51
51
  # # good
52
52
  # a ** b
53
+ #
54
+ # @example EnforcedStyleForRationalLiterals: no_space (default)
55
+ # # bad
56
+ # 1 / 48r
57
+ #
58
+ # # good
59
+ # 1/48r
60
+ #
61
+ # @example EnforcedStyleForRationalLiterals: space
62
+ # # bad
63
+ # 1/48r
64
+ #
65
+ # # good
66
+ # 1 / 48r
53
67
  class SpaceAroundOperators < Base
54
68
  include PrecedingFollowingAlignment
55
69
  include RangeHelp
@@ -64,7 +78,7 @@ module RuboCop
64
78
  end
65
79
 
66
80
  def on_sclass(node)
67
- check_operator(:sclass, node.loc.operator, node.source_range)
81
+ check_operator(:sclass, node.loc.operator, node)
68
82
  end
69
83
 
70
84
  def on_pair(node)
@@ -72,14 +86,14 @@ module RuboCop
72
86
 
73
87
  return if hash_table_style? && !node.parent.pairs_on_same_line?
74
88
 
75
- check_operator(:pair, node.loc.operator, node.source_range)
89
+ check_operator(:pair, node.loc.operator, node)
76
90
  end
77
91
 
78
92
  def on_if(node)
79
93
  return unless node.ternary?
80
94
 
81
- check_operator(:if, node.loc.question, node.if_branch.source_range)
82
- check_operator(:if, node.loc.colon, node.else_branch.source_range)
95
+ check_operator(:if, node.loc.question, node.if_branch)
96
+ check_operator(:if, node.loc.colon, node.else_branch)
83
97
  end
84
98
 
85
99
  def on_resbody(node)
@@ -87,7 +101,7 @@ module RuboCop
87
101
 
88
102
  _, variable, = *node
89
103
 
90
- check_operator(:resbody, node.loc.assoc, variable.source_range)
104
+ check_operator(:resbody, node.loc.assoc, variable)
91
105
  end
92
106
 
93
107
  def on_send(node)
@@ -96,7 +110,7 @@ module RuboCop
96
110
  if node.setter_method?
97
111
  on_special_asgn(node)
98
112
  elsif regular_operator?(node)
99
- check_operator(:send, node.loc.selector, node.first_argument.source_range)
113
+ check_operator(:send, node.loc.selector, node.first_argument)
100
114
  end
101
115
  end
102
116
 
@@ -105,7 +119,7 @@ module RuboCop
105
119
 
106
120
  return unless rhs
107
121
 
108
- check_operator(:assignment, node.loc.operator, rhs.source_range)
122
+ check_operator(:assignment, node.loc.operator, rhs)
109
123
  end
110
124
 
111
125
  def on_casgn(node)
@@ -113,7 +127,7 @@ module RuboCop
113
127
 
114
128
  return unless right
115
129
 
116
- check_operator(:assignment, node.loc.operator, right.source_range)
130
+ check_operator(:assignment, node.loc.operator, right)
117
131
  end
118
132
 
119
133
  def on_binary(node)
@@ -121,7 +135,7 @@ module RuboCop
121
135
 
122
136
  return unless rhs
123
137
 
124
- check_operator(:binary, node.loc.operator, rhs.source_range)
138
+ check_operator(:binary, node.loc.operator, rhs)
125
139
  end
126
140
 
127
141
  def on_special_asgn(node)
@@ -129,13 +143,13 @@ module RuboCop
129
143
 
130
144
  return unless right
131
145
 
132
- check_operator(:special_asgn, node.loc.operator, right.source_range)
146
+ check_operator(:special_asgn, node.loc.operator, right)
133
147
  end
134
148
 
135
149
  def on_match_pattern(node)
136
150
  return if target_ruby_version < 3.0
137
151
 
138
- check_operator(:match_pattern, node.loc.operator, node.source_range)
152
+ check_operator(:match_pattern, node.loc.operator, node)
139
153
  end
140
154
 
141
155
  alias on_or on_binary
@@ -168,7 +182,7 @@ module RuboCop
168
182
 
169
183
  offense(type, operator, with_space, right_operand) do |msg|
170
184
  add_offense(operator, message: msg) do |corrector|
171
- autocorrect(corrector, with_space)
185
+ autocorrect(corrector, with_space, right_operand)
172
186
  end
173
187
  end
174
188
  end
@@ -178,11 +192,15 @@ module RuboCop
178
192
  yield msg if msg
179
193
  end
180
194
 
181
- def autocorrect(corrector, range)
182
- if range.source.include?('**') && !space_around_exponent_operator?
195
+ def autocorrect(corrector, range, right_operand)
196
+ range_source = range.source
197
+
198
+ if range_source.include?('**') && !space_around_exponent_operator?
183
199
  corrector.replace(range, '**')
184
- elsif range.source.end_with?("\n")
185
- corrector.replace(range, " #{range.source.strip}\n")
200
+ elsif range_source.include?('/') && !space_around_slash_operator?(right_operand)
201
+ corrector.replace(range, '/')
202
+ elsif range_source.end_with?("\n")
203
+ corrector.replace(range, " #{range_source.strip}\n")
186
204
  else
187
205
  enclose_operator_with_space(corrector, range)
188
206
  end
@@ -202,14 +220,14 @@ module RuboCop
202
220
  end
203
221
 
204
222
  def offense_message(type, operator, with_space, right_operand)
205
- if should_not_have_surrounding_space?(operator)
223
+ if should_not_have_surrounding_space?(operator, right_operand)
206
224
  return if with_space.is?(operator.source)
207
225
 
208
226
  "Space around operator `#{operator.source}` detected."
209
227
  elsif !/^\s.*\s$/.match?(with_space.source)
210
228
  "Surrounding space missing for operator `#{operator.source}`."
211
229
  elsif excess_leading_space?(type, operator, with_space) ||
212
- excess_trailing_space?(right_operand, with_space)
230
+ excess_trailing_space?(right_operand.source_range, with_space)
213
231
  "Operator `#{operator.source}` should be surrounded " \
214
232
  'by a single space.'
215
233
  end
@@ -247,12 +265,24 @@ module RuboCop
247
265
  cop_config['EnforcedStyleForExponentOperator'] == 'space'
248
266
  end
249
267
 
268
+ def space_around_slash_operator?(right_operand)
269
+ return true unless right_operand.rational_type?
270
+
271
+ cop_config['EnforcedStyleForRationalLiterals'] == 'space'
272
+ end
273
+
250
274
  def force_equal_sign_alignment?
251
275
  config.for_cop('Layout/ExtraSpacing')['ForceEqualSignAlignment']
252
276
  end
253
277
 
254
- def should_not_have_surrounding_space?(operator)
255
- operator.is?('**') ? !space_around_exponent_operator? : false
278
+ def should_not_have_surrounding_space?(operator, right_operand)
279
+ if operator.is?('**')
280
+ !space_around_exponent_operator?
281
+ elsif operator.is?('/')
282
+ !space_around_slash_operator?(right_operand)
283
+ else
284
+ false
285
+ end
256
286
  end
257
287
  end
258
288
  end