rubocop 1.47.0 → 1.48.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3790198ce32105233a07bc15c82a62ec188e7430910b16a7ff10eefbfa89c0a2
4
- data.tar.gz: aa440d2b6a863b774d63731cbf779cd204491f675b5ad0d4b708a1b8708dcd3b
3
+ metadata.gz: fb25d50ecbd2f942993d245b3302d53cf3605fa362e0addf1ee088caaa22bfff
4
+ data.tar.gz: 62df82b33ce3ae669b7fd23ca69f1a53f9dbbcd480d44cfff763df3c84c39585
5
5
  SHA512:
6
- metadata.gz: 2adcafe5b28f4c2a440d3cee024b3e2462a4b60d6ddf5136f63972255e484059780281f2be264c82bd21a8c5ebe83433c010b53b8d893f01de9d9e58de586b7f
7
- data.tar.gz: 66eab3f5f70f3c93ee3263a982b6e7795fec658dd91462d6c5d5bc9f87f1ae99de17fb0fcd04afb060985ad1085505ff7c98d5df6d11a33b40432260ef5e91fc
6
+ metadata.gz: 563e301ae73973fd6ccb3679ce82fe15a02d6634c7993bfab9f0c15ae29687982ac63ec07f656be22273e6b5c63cd2686b678cdc3319536b51d086103ec60fcd
7
+ data.tar.gz: eb24bb4636f91c76715a81896852d6620306ac45e52755cc5c2148ff0f85d1012ebe7b043076a802259bf1d130fc4296d55b70f4d99816aba39056fa05205b16
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.47', require: false
56
+ gem 'rubocop', '~> 1.48', 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
@@ -3261,6 +3261,9 @@ Style/CaseLikeIf:
3261
3261
  Enabled: true
3262
3262
  Safe: false
3263
3263
  VersionAdded: '0.88'
3264
+ VersionChanged: '1.48'
3265
+ # `MinBranchesCount` defines the number of branches `if` needs to have to trigger this cop.
3266
+ MinBranchesCount: 3
3264
3267
 
3265
3268
  Style/CharacterLiteral:
3266
3269
  Description: 'Checks for uses of character literals.'
@@ -3527,6 +3530,12 @@ Style/Dir:
3527
3530
  Enabled: true
3528
3531
  VersionAdded: '0.50'
3529
3532
 
3533
+ Style/DirEmpty:
3534
+ Description: >-
3535
+ Prefer to use `Dir.empty?('path/to/dir')` when checking if a directory is empty.
3536
+ Enabled: pending
3537
+ VersionAdded: '1.48'
3538
+
3530
3539
  Style/DisableCopsWithinSourceCodeDirective:
3531
3540
  Description: >-
3532
3541
  Forbids disabling/enabling cops within source code.
@@ -3722,6 +3731,14 @@ Style/FetchEnvVar:
3722
3731
  # Environment variables to be excluded from the inspection.
3723
3732
  AllowedVars: []
3724
3733
 
3734
+ Style/FileEmpty:
3735
+ Description: >-
3736
+ Prefer to use `File.empty?('path/to/file')` when checking if a file is empty.
3737
+ Enabled: pending
3738
+ Safe: false
3739
+ SafeAutoCorrect: false
3740
+ VersionAdded: '1.48'
3741
+
3725
3742
  Style/FileRead:
3726
3743
  Description: 'Favor `File.(bin)read` convenience methods.'
3727
3744
  StyleGuide: '#file-read'
@@ -110,12 +110,12 @@ module RuboCop
110
110
  end
111
111
 
112
112
  def inside_class_with_stateful_parent?(node)
113
- if (class_node = node.parent) && class_node.class_type?
114
- class_node.parent_class && !stateless_class?(class_node.parent_class)
115
- elsif (block_node = node.each_ancestor(:block, :numblock).first)
113
+ if (block_node = node.each_ancestor(:block, :numblock).first)
116
114
  return false unless (super_class = class_new_block(block_node))
117
115
 
118
116
  !stateless_class?(super_class)
117
+ elsif (class_node = node.each_ancestor(:class).first)
118
+ class_node.parent_class && !stateless_class?(class_node.parent_class)
119
119
  else
120
120
  false
121
121
  end
@@ -31,6 +31,8 @@ module RuboCop
31
31
  return unless lhs&.casgn_type?
32
32
 
33
33
  add_offense(node.loc.operator) do |corrector|
34
+ next if node.each_ancestor(:def, :defs).any?
35
+
34
36
  corrector.replace(node.loc.operator, '=')
35
37
  end
36
38
  end
@@ -137,7 +137,7 @@ module RuboCop
137
137
  alias on_sclass on_class
138
138
 
139
139
  def on_block(node)
140
- return unless eval_call?(node)
140
+ return unless eval_call?(node) || included_block?(node)
141
141
 
142
142
  check_node(node.body)
143
143
  end
@@ -192,10 +192,13 @@ module RuboCop
192
192
  end
193
193
  end
194
194
 
195
+ # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
195
196
  def check_child_nodes(node, unused, cur_vis)
196
197
  node.child_nodes.each do |child|
197
198
  if child.send_type? && access_modifier?(child)
198
199
  cur_vis, unused = check_send_node(child, cur_vis, unused)
200
+ elsif child.block_type? && included_block?(child)
201
+ next
199
202
  elsif method_definition?(child)
200
203
  unused = nil
201
204
  elsif start_of_new_scope?(child)
@@ -207,6 +210,7 @@ module RuboCop
207
210
 
208
211
  [cur_vis, unused]
209
212
  end
213
+ # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
210
214
 
211
215
  def check_send_node(node, cur_vis, unused)
212
216
  if node.bare_access_modifier?
@@ -240,6 +244,10 @@ module RuboCop
240
244
  [new_vis, unused]
241
245
  end
242
246
 
247
+ def included_block?(block_node)
248
+ active_support_extensions_enabled? && block_node.method?(:included)
249
+ end
250
+
243
251
  def method_definition?(child)
244
252
  static_method_definition?(child) ||
245
253
  dynamic_method_definition?(child) ||
@@ -95,19 +95,20 @@ module RuboCop
95
95
  use_modifier_form_without_parenthesized_method_call?(method_dispatch_node)
96
96
  end
97
97
 
98
- # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
98
+ # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
99
99
  def def_node_that_require_parentheses(node)
100
100
  last_pair = node.parent.pairs.last
101
101
  return unless last_pair.key.source == last_pair.value.source
102
102
  return unless (dispatch_node = find_ancestor_method_dispatch_node(node))
103
103
  return if dispatch_node.parenthesized?
104
+ return if dispatch_node.parent && parentheses?(dispatch_node.parent)
104
105
  return if last_expression?(dispatch_node) && !method_dispatch_as_argument?(dispatch_node)
105
106
 
106
107
  def_node = node.each_ancestor(:send, :csend, :super, :yield).first
107
108
 
108
109
  DefNode.new(def_node) unless def_node && def_node.arguments.empty?
109
110
  end
110
- # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity
111
+ # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
111
112
 
112
113
  def find_ancestor_method_dispatch_node(node)
113
114
  return unless (ancestor = node.parent.parent)
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # Common functionality for checking minimum branches count.
6
+ module MinBranchesCount
7
+ private
8
+
9
+ def min_branches_count?(node)
10
+ branches =
11
+ if node.case_type?
12
+ node.when_branches
13
+ elsif node.if_type?
14
+ if_conditional_branches(node)
15
+ else
16
+ raise ArgumentError, "Unsupported #{node.type.inspect} node type"
17
+ end
18
+
19
+ branches.size >= min_branches_count
20
+ end
21
+
22
+ def min_branches_count
23
+ length = cop_config['MinBranchesCount'] || 3
24
+ return length if length.is_a?(Integer) && length.positive?
25
+
26
+ raise 'MinBranchesCount needs to be a positive integer!'
27
+ end
28
+
29
+ def if_conditional_branches(node, branches = [])
30
+ return [] if node.nil? || !node.if_type?
31
+
32
+ branches << node.if_branch
33
+
34
+ else_branch = node.else_branch
35
+ if_conditional_branches(else_branch, branches) if else_branch&.if_type?
36
+ branches
37
+ end
38
+ end
39
+ end
40
+ end
@@ -197,7 +197,9 @@ module RuboCop
197
197
  def enabled?(cop, config)
198
198
  return true if options[:only]&.include?(cop.cop_name)
199
199
 
200
- cfg = config.for_cop(cop)
200
+ # We need to use `cop_name` in this case, because `for_cop` uses caching
201
+ # which expects cop names or cop classes as keys.
202
+ cfg = config.for_cop(cop.cop_name)
201
203
 
202
204
  cop_enabled = cfg.fetch('Enabled') == true || enabled_pending_cop?(cfg, config)
203
205
 
@@ -14,12 +14,13 @@ module RuboCop
14
14
  # # bad
15
15
  # class Foo
16
16
  # attr_reader :bar
17
+ # attr_reader :bax
17
18
  # attr_reader :baz
18
19
  # end
19
20
  #
20
21
  # # good
21
22
  # class Foo
22
- # attr_reader :bar, :baz
23
+ # attr_reader :bar, :bax, :baz
23
24
  # end
24
25
  #
25
26
  # # good
@@ -27,6 +28,9 @@ module RuboCop
27
28
  # # may be intended comment for bar.
28
29
  # attr_reader :bar
29
30
  #
31
+ # sig { returns(String) }
32
+ # attr_reader :bax
33
+ #
30
34
  # may_be_intended_annotation :baz
31
35
  # attr_reader :baz
32
36
  # end
@@ -90,6 +94,14 @@ module RuboCop
90
94
 
91
95
  def groupable_accessor?(node)
92
96
  return true unless (previous_expression = node.left_siblings.last)
97
+
98
+ # Accessors with Sorbet `sig { ... }` blocks shouldn't be groupable.
99
+ if previous_expression.block_type?
100
+ previous_expression.child_nodes.each do |child_node|
101
+ break previous_expression = child_node if child_node.send_type?
102
+ end
103
+ end
104
+
93
105
  return true unless previous_expression.send_type?
94
106
 
95
107
  previous_expression.attribute_accessor? || previous_expression.access_modifier?
@@ -342,6 +342,7 @@ module RuboCop
342
342
  end
343
343
 
344
344
  def proper_block_style?(node)
345
+ return true if require_braces?(node)
345
346
  return special_method_proper_block_style?(node) if special_method?(node.method_name)
346
347
 
347
348
  case style
@@ -352,6 +353,14 @@ module RuboCop
352
353
  end
353
354
  end
354
355
 
356
+ def require_braces?(node)
357
+ return false unless node.braces?
358
+
359
+ node.each_ancestor(:send).any? do |send|
360
+ send.arithmetic_operation? && node.source_range.end_pos < send.loc.selector.begin_pos
361
+ end
362
+ end
363
+
355
364
  def special_method?(method_name)
356
365
  allowed_method?(method_name) ||
357
366
  matches_allowed_pattern?(method_name) ||
@@ -11,12 +11,14 @@ module RuboCop
11
11
  # so if the original conditional used a different equality operator, the
12
12
  # behavior may be different.
13
13
  #
14
- # @example
14
+ # @example MinBranchesCount: 3 (default)
15
15
  # # bad
16
16
  # if status == :active
17
17
  # perform_action
18
18
  # elsif status == :inactive || status == :hibernating
19
19
  # check_timeout
20
+ # elsif status == :invalid
21
+ # report_invalid
20
22
  # else
21
23
  # final_action
22
24
  # end
@@ -27,12 +29,27 @@ module RuboCop
27
29
  # perform_action
28
30
  # when :inactive, :hibernating
29
31
  # check_timeout
32
+ # when :invalid
33
+ # report_invalid
34
+ # else
35
+ # final_action
36
+ # end
37
+ #
38
+ # @example MinBranchesCount: 4
39
+ # # good
40
+ # if status == :active
41
+ # perform_action
42
+ # elsif status == :inactive || status == :hibernating
43
+ # check_timeout
44
+ # elsif status == :invalid
45
+ # report_invalid
30
46
  # else
31
47
  # final_action
32
48
  # end
33
49
  #
34
50
  class CaseLikeIf < Base
35
51
  include RangeHelp
52
+ include MinBranchesCount
36
53
  extend AutoCorrector
37
54
 
38
55
  MSG = 'Convert `if-elsif` to `case-when`.'
@@ -78,7 +95,7 @@ module RuboCop
78
95
 
79
96
  def should_check?(node)
80
97
  !node.unless? && !node.elsif? && !node.modifier_form? && !node.ternary? &&
81
- node.elsif_conditional?
98
+ node.elsif_conditional? && min_branches_count?(node)
82
99
  end
83
100
 
84
101
  # rubocop:disable Metrics/MethodLength
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Prefer to use `Dir.empty?('path/to/dir')` when checking if a directory is empty.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # Dir.entries('path/to/dir').size == 2
11
+ # Dir.children('path/to/dir').empty?
12
+ # Dir.children('path/to/dir').size == 0
13
+ # Dir.each_child('path/to/dir').none?
14
+ #
15
+ # # good
16
+ # Dir.empty?('path/to/dir')
17
+ #
18
+ class DirEmpty < Base
19
+ extend AutoCorrector
20
+ extend TargetRubyVersion
21
+
22
+ MSG = 'Use `Dir.empty?(%<arg>s)` instead.'
23
+ RESTRICT_ON_SEND = %i[== > empty? none?].freeze
24
+
25
+ minimum_target_ruby_version 2.4
26
+
27
+ # @!method offensive?(node)
28
+ def_node_matcher :offensive?, <<~PATTERN
29
+ {
30
+ (send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) {:== :>} (int 2))
31
+ (send (send (send $(const {nil? cbase} :Dir) :children $_) :size) {:== :>} (int 0))
32
+ (send (send (send (send $(const {nil? cbase} :Dir) :entries $_) :size) :!) {:== :>} (int 2))
33
+ (send (send (send (send $(const {nil? cbase} :Dir) :children $_) :size) :!) {:== :>} (int 0))
34
+ (send (send $(const {nil? cbase} :Dir) :children $_) :empty?)
35
+ (send (send $(const {nil? cbase} :Dir) :each_child $_) :none?)
36
+ }
37
+ PATTERN
38
+
39
+ def on_send(node)
40
+ offensive?(node) do |const_node, arg_node|
41
+ add_offense(node, message: format(MSG, arg: arg_node.source)) do |corrector|
42
+ bang(node)
43
+ corrector.replace(node,
44
+ "#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})")
45
+ end
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def bang(node)
52
+ if (node.method?(:==) && node.child_nodes.first.method?(:!)) ||
53
+ (node.method?(:>) && !node.child_nodes.first.method?(:!))
54
+ '!'
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -178,13 +178,19 @@ module RuboCop
178
178
  def identifier(node)
179
179
  # Get the fully qualified identifier for a class/module
180
180
  nodes = [node, *node.each_ancestor(:class, :module)]
181
- nodes.reverse_each.flat_map { |n| qualify_const(n.identifier) }.join('::')
181
+ identifier = nodes.reverse_each.flat_map { |n| qualify_const(n.identifier) }.join('::')
182
+
183
+ identifier.sub('::::', '::')
182
184
  end
183
185
 
184
186
  def qualify_const(node)
185
- return if node.nil? || node.cbase_type? || node.self_type? || node.send_type?
187
+ return if node.nil?
186
188
 
187
- [qualify_const(node.namespace), node.short_name].compact
189
+ if node.cbase_type? || node.self_type? || node.call_type? || node.variable?
190
+ node.source
191
+ else
192
+ [qualify_const(node.namespace), node.short_name].compact
193
+ end
188
194
  end
189
195
  end
190
196
  end
@@ -0,0 +1,71 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # Prefer to use `File.empty?('path/to/file')` when checking if a file is empty.
7
+ #
8
+ # @safety
9
+ # This cop's autocorrection is unsafe it because `File.size`, `File.read`,
10
+ # and `File.binread` raise `ENOENT` exception when there is no file
11
+ # corresponding to the path, while `File.empty?` does not raise an exception.
12
+ #
13
+ # @example
14
+ # # bad
15
+ # File.zero?('path/to/file')
16
+ # File.size('path/to/file') == 0
17
+ # File.size('path/to/file') >= 0
18
+ # File.size('path/to/file').zero?
19
+ # File.read('path/to/file').empty?
20
+ # File.binread('path/to/file') == ''
21
+ # FileTest.zero?('path/to/file')
22
+ #
23
+ # # good
24
+ # File.empty?('path/to/file')
25
+ # FileTest.empty?('path/to/file')
26
+ #
27
+ class FileEmpty < Base
28
+ extend AutoCorrector
29
+ extend TargetRubyVersion
30
+
31
+ MSG = 'Use `%<file_class>s.empty?(%<arg>s)` instead.'
32
+ RESTRICT_ON_SEND = %i[>= != == zero? empty?].freeze
33
+
34
+ minimum_target_ruby_version 2.4
35
+
36
+ # @!method offensive?(node)
37
+ def_node_matcher :offensive?, <<~PATTERN
38
+ {
39
+ (send $(const {nil? cbase} {:File :FileTest}) :zero? $_)
40
+ (send (send $(const {nil? cbase} {:File :FileTest}) :size $_) {:== :>=} (int 0))
41
+ (send (send (send $(const {nil? cbase} {:File :FileTest}) :size $_) :!) {:== :>=} (int 0))
42
+ (send (send $(const {nil? cbase} {:File :FileTest}) :size $_) :zero?)
43
+ (send (send $(const {nil? cbase} {:File :FileTest}) {:read :binread} $_) {:!= :==} (str empty?))
44
+ (send (send (send $(const {nil? cbase} {:File :FileTest}) {:read :binread} $_) :!) {:!= :==} (str empty?))
45
+ (send (send $(const {nil? cbase} {:File :FileTest}) {:read :binread} $_) :empty?)
46
+ }
47
+ PATTERN
48
+
49
+ def on_send(node)
50
+ offensive?(node) do |const_node, arg_node|
51
+ add_offense(node,
52
+ message: format(MSG, file_class: const_node.source,
53
+ arg: arg_node.source)) do |corrector|
54
+ corrector.replace(node,
55
+ "#{bang(node)}#{const_node.source}.empty?(#{arg_node.source})")
56
+ end
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def bang(node)
63
+ if (node.method?(:==) && node.child_nodes.first.method?(:!)) ||
64
+ (%i[>= !=].include?(node.method_name) && !node.child_nodes.first.method?(:!))
65
+ '!'
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -37,6 +37,8 @@ module RuboCop
37
37
  # end
38
38
  #
39
39
  class HashLikeCase < Base
40
+ include MinBranchesCount
41
+
40
42
  MSG = 'Consider replacing `case-when` with a hash lookup.'
41
43
 
42
44
  # @!method hash_like_case?(node)
@@ -49,7 +51,7 @@ module RuboCop
49
51
  PATTERN
50
52
 
51
53
  def on_case(node)
52
- return if node.when_branches.size < min_branches_count
54
+ return unless min_branches_count?(node)
53
55
 
54
56
  hash_like_case?(node) do |condition_nodes, body_nodes|
55
57
  if nodes_of_same_type?(condition_nodes) && nodes_of_same_type?(body_nodes)
@@ -63,14 +65,6 @@ module RuboCop
63
65
  def nodes_of_same_type?(nodes)
64
66
  nodes.all? { |node| node.type == nodes.first.type }
65
67
  end
66
-
67
- def min_branches_count
68
- length = cop_config['MinBranchesCount'] || 3
69
- return length if length.is_a?(Integer) && length.positive?
70
-
71
- warn Rainbow('`MinBranchesCount` needs to be a positive integer!').red
72
- exit!
73
- end
74
68
  end
75
69
  end
76
70
  end
@@ -53,6 +53,7 @@ module RuboCop
53
53
  include LineLengthHelp
54
54
  include AllowedPattern
55
55
  include RangeHelp
56
+ include CommentsHelp
56
57
  extend AutoCorrector
57
58
 
58
59
  MSG_USE_MODIFIER = 'Favor modifier `%<keyword>s` usage when having a ' \
@@ -101,26 +102,43 @@ module RuboCop
101
102
 
102
103
  def autocorrect(corrector, node)
103
104
  replacement = if node.modifier_form?
104
- last_argument = node.if_branch.last_argument if node.if_branch.send_type?
105
-
106
- if last_argument.respond_to?(:heredoc?) && last_argument.heredoc?
107
- heredoc = extract_heredoc_from(last_argument)
108
- remove_heredoc(corrector, heredoc)
109
- to_normal_form_with_heredoc(node, indent(node), heredoc)
110
- else
111
- to_normal_form(node, indent(node))
112
- end
105
+ replacement_for_modifier_form(corrector, node)
113
106
  else
114
107
  to_modifier_form(node)
115
108
  end
116
109
  corrector.replace(node, replacement)
117
110
  end
118
111
 
112
+ def replacement_for_modifier_form(corrector, node) # rubocop:disable Metrics/AbcSize
113
+ comment = comment_on_node_line(node)
114
+ if comment && too_long_due_to_comment_after_modifier?(node, comment)
115
+ remove_comment(corrector, node, comment)
116
+
117
+ return to_modifier_form_with_move_comment(node, indent(node), comment)
118
+ end
119
+
120
+ last_argument = node.if_branch.last_argument if node.if_branch.send_type?
121
+ if last_argument.respond_to?(:heredoc?) && last_argument.heredoc?
122
+ heredoc = extract_heredoc_from(last_argument)
123
+ remove_heredoc(corrector, heredoc)
124
+
125
+ return to_normal_form_with_heredoc(node, indent(node), heredoc)
126
+ end
127
+
128
+ to_normal_form(node, indent(node))
129
+ end
130
+
119
131
  def too_long_due_to_modifier?(node)
120
132
  node.modifier_form? && too_long_single_line?(node) &&
121
133
  !another_statement_on_same_line?(node)
122
134
  end
123
135
 
136
+ def too_long_due_to_comment_after_modifier?(node, comment)
137
+ source_length = processed_source.lines[node.first_line - 1].length
138
+ source_length >= max_line_length &&
139
+ source_length - comment.source_range.length <= max_line_length
140
+ end
141
+
124
142
  def allowed_patterns
125
143
  line_length_config = config.for_cop('Layout/LineLength')
126
144
  line_length_config['AllowedPatterns'] || line_length_config['IgnoredPatterns'] || []
@@ -215,6 +233,13 @@ module RuboCop
215
233
  RUBY
216
234
  end
217
235
 
236
+ def to_modifier_form_with_move_comment(node, indentation, comment)
237
+ <<~RUBY.chomp
238
+ #{comment.source}
239
+ #{indentation}#{node.body.source} #{node.keyword} #{node.condition.source}
240
+ RUBY
241
+ end
242
+
218
243
  def extract_heredoc_from(last_argument)
219
244
  heredoc_body = last_argument.loc.heredoc_body
220
245
  heredoc_end = last_argument.loc.heredoc_end
@@ -227,6 +252,14 @@ module RuboCop
227
252
  corrector.remove(range_by_whole_lines(range, include_final_newline: true))
228
253
  end
229
254
  end
255
+
256
+ def comment_on_node_line(node)
257
+ processed_source.comments.find { |c| same_line?(c, node) }
258
+ end
259
+
260
+ def remove_comment(corrector, _node, comment)
261
+ corrector.remove(range_with_surrounding_space(range: comment.source_range, side: :left))
262
+ end
230
263
  end
231
264
  end
232
265
  end
@@ -118,6 +118,8 @@ module RuboCop
118
118
  end
119
119
 
120
120
  def return_boolean_value?(condition)
121
+ return false unless condition
122
+
121
123
  if condition.begin_type?
122
124
  return_boolean_value?(condition.children.first)
123
125
  elsif condition.or_type?
@@ -48,13 +48,11 @@ module RuboCop
48
48
 
49
49
  def on_if(node)
50
50
  return unless if_else?(node)
51
-
52
- condition = unwrap_begin_nodes(node.condition)
53
-
51
+ return unless (condition = unwrap_begin_nodes(node.condition))
54
52
  return if double_negation?(condition) || !negated_condition?(condition)
55
53
 
56
- type = node.ternary? ? 'ternary' : 'if-else'
57
- add_offense(node, message: format(MSG, type: type)) do |corrector|
54
+ message = message(node)
55
+ add_offense(node, message: message) do |corrector|
58
56
  unless corrected_ancestor?(node)
59
57
  correct_negated_condition(corrector, condition)
60
58
  swap_branches(corrector, node)
@@ -73,7 +71,8 @@ module RuboCop
73
71
  end
74
72
 
75
73
  def unwrap_begin_nodes(node)
76
- node = node.children.first while node.begin_type? || node.kwbegin_type?
74
+ node = node.children.first while node && (node.begin_type? || node.kwbegin_type?)
75
+
77
76
  node
78
77
  end
79
78
 
@@ -82,6 +81,12 @@ module RuboCop
82
81
  (node.negation_method? || NEGATED_EQUALITY_METHODS.include?(node.method_name))
83
82
  end
84
83
 
84
+ def message(node)
85
+ type = node.ternary? ? 'ternary' : 'if-else'
86
+
87
+ format(MSG, type: type)
88
+ end
89
+
85
90
  def corrected_ancestor?(node)
86
91
  node.each_ancestor(:if).any? { |ancestor| @corrected_nodes&.include?(ancestor) }
87
92
  end
@@ -160,8 +160,8 @@ module RuboCop
160
160
  def roundup_relevant_cops(processed_source)
161
161
  cops.select do |cop|
162
162
  next true if processed_source.comment_config.cop_opted_in?(cop)
163
- next false unless @registry.enabled?(cop, @config)
164
163
  next false if cop.excluded_file?(processed_source.file_path)
164
+ next false unless @registry.enabled?(cop, @config)
165
165
 
166
166
  support_target_ruby_version?(cop) && support_target_rails_version?(cop)
167
167
  end
@@ -62,7 +62,10 @@ module RuboCop
62
62
  end
63
63
 
64
64
  def classname_attribute_value(file)
65
- file.gsub(/\.rb\Z/, '').gsub("#{Dir.pwd}/", '').tr('/', '.')
65
+ @classname_attribute_value_cache ||= Hash.new do |hash, key|
66
+ hash[key] = key.gsub(/\.rb\Z/, '').gsub("#{Dir.pwd}/", '').tr('/', '.')
67
+ end
68
+ @classname_attribute_value_cache[file]
66
69
  end
67
70
 
68
71
  def finished(_inspected_files)
@@ -100,7 +100,7 @@ module RuboCop
100
100
 
101
101
  def use_json_format?
102
102
  return true if ARGV.include?('--format=json') || ARGV.include?('--format=j')
103
- return false unless (index = ARGV.index('--format'))
103
+ return false unless (index = ARGV.index('--format') || ARGV.index('-f'))
104
104
 
105
105
  format = ARGV[index + 1]
106
106
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '1.47.0'
6
+ STRING = '1.48.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
@@ -102,6 +102,7 @@ require_relative 'rubocop/cop/mixin/hash_shorthand_syntax'
102
102
  require_relative 'rubocop/cop/mixin/method_complexity'
103
103
  require_relative 'rubocop/cop/mixin/method_preference'
104
104
  require_relative 'rubocop/cop/mixin/min_body_length'
105
+ require_relative 'rubocop/cop/mixin/min_branches_count'
105
106
  require_relative 'rubocop/cop/mixin/multiline_element_indentation'
106
107
  require_relative 'rubocop/cop/mixin/multiline_element_line_breaks'
107
108
  require_relative 'rubocop/cop/mixin/multiline_expression_indentation'
@@ -482,6 +483,7 @@ require_relative 'rubocop/cop/style/copyright'
482
483
  require_relative 'rubocop/cop/style/date_time'
483
484
  require_relative 'rubocop/cop/style/def_with_parentheses'
484
485
  require_relative 'rubocop/cop/style/dir'
486
+ require_relative 'rubocop/cop/style/dir_empty'
485
487
  require_relative 'rubocop/cop/style/disable_cops_within_source_code_directive'
486
488
  require_relative 'rubocop/cop/style/documentation_method'
487
489
  require_relative 'rubocop/cop/style/documentation'
@@ -507,6 +509,7 @@ require_relative 'rubocop/cop/style/expand_path_arguments'
507
509
  require_relative 'rubocop/cop/style/explicit_block_argument'
508
510
  require_relative 'rubocop/cop/style/exponential_notation'
509
511
  require_relative 'rubocop/cop/style/fetch_env_var'
512
+ require_relative 'rubocop/cop/style/file_empty'
510
513
  require_relative 'rubocop/cop/style/file_read'
511
514
  require_relative 'rubocop/cop/style/file_write'
512
515
  require_relative 'rubocop/cop/style/float_division'
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.47.0
4
+ version: 1.48.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: 2023-03-01 00:00:00.000000000 Z
13
+ date: 2023-03-06 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: json
@@ -584,6 +584,7 @@ files:
584
584
  - lib/rubocop/cop/mixin/method_complexity.rb
585
585
  - lib/rubocop/cop/mixin/method_preference.rb
586
586
  - lib/rubocop/cop/mixin/min_body_length.rb
587
+ - lib/rubocop/cop/mixin/min_branches_count.rb
587
588
  - lib/rubocop/cop/mixin/multiline_element_indentation.rb
588
589
  - lib/rubocop/cop/mixin/multiline_element_line_breaks.rb
589
590
  - lib/rubocop/cop/mixin/multiline_expression_indentation.rb
@@ -685,6 +686,7 @@ files:
685
686
  - lib/rubocop/cop/style/date_time.rb
686
687
  - lib/rubocop/cop/style/def_with_parentheses.rb
687
688
  - lib/rubocop/cop/style/dir.rb
689
+ - lib/rubocop/cop/style/dir_empty.rb
688
690
  - lib/rubocop/cop/style/disable_cops_within_source_code_directive.rb
689
691
  - lib/rubocop/cop/style/document_dynamic_eval_definition.rb
690
692
  - lib/rubocop/cop/style/documentation.rb
@@ -710,6 +712,7 @@ files:
710
712
  - lib/rubocop/cop/style/explicit_block_argument.rb
711
713
  - lib/rubocop/cop/style/exponential_notation.rb
712
714
  - lib/rubocop/cop/style/fetch_env_var.rb
715
+ - lib/rubocop/cop/style/file_empty.rb
713
716
  - lib/rubocop/cop/style/file_read.rb
714
717
  - lib/rubocop/cop/style/file_write.rb
715
718
  - lib/rubocop/cop/style/float_division.rb
@@ -985,7 +988,7 @@ metadata:
985
988
  homepage_uri: https://rubocop.org/
986
989
  changelog_uri: https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md
987
990
  source_code_uri: https://github.com/rubocop/rubocop/
988
- documentation_uri: https://docs.rubocop.org/rubocop/1.47/
991
+ documentation_uri: https://docs.rubocop.org/rubocop/1.48/
989
992
  bug_tracker_uri: https://github.com/rubocop/rubocop/issues
990
993
  rubygems_mfa_required: 'true'
991
994
  post_install_message: