rubocop 1.47.0 → 1.48.0

Sign up to get free protection for your applications and to get access to all the features.
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: