rubocop 1.35.0 → 1.36.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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +11 -0
  4. data/lib/rubocop/cli/command/{auto_genenerate_config.rb → auto_generate_config.rb} +0 -0
  5. data/lib/rubocop/config.rb +1 -1
  6. data/lib/rubocop/cop/generator/require_file_injector.rb +2 -2
  7. data/lib/rubocop/cop/internal_affairs/single_line_comparison.rb +5 -4
  8. data/lib/rubocop/cop/layout/block_alignment.rb +14 -12
  9. data/lib/rubocop/cop/layout/end_of_line.rb +4 -4
  10. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +2 -2
  11. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +2 -2
  12. data/lib/rubocop/cop/layout/indentation_width.rb +3 -1
  13. data/lib/rubocop/cop/layout/redundant_line_break.rb +1 -1
  14. data/lib/rubocop/cop/layout/space_inside_block_braces.rb +25 -9
  15. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  16. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +4 -4
  17. data/lib/rubocop/cop/lint/duplicate_require.rb +1 -1
  18. data/lib/rubocop/cop/lint/empty_conditional_body.rb +31 -1
  19. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +4 -0
  20. data/lib/rubocop/cop/lint/non_atomic_file_operation.rb +6 -6
  21. data/lib/rubocop/cop/lint/redundant_safe_navigation.rb +9 -3
  22. data/lib/rubocop/cop/lint/shadowed_exception.rb +1 -1
  23. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +14 -2
  24. data/lib/rubocop/cop/lint/unreachable_loop.rb +1 -1
  25. data/lib/rubocop/cop/lint/useless_access_modifier.rb +2 -2
  26. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +1 -1
  27. data/lib/rubocop/cop/mixin/allowed_methods.rb +10 -5
  28. data/lib/rubocop/cop/mixin/allowed_pattern.rb +13 -5
  29. data/lib/rubocop/cop/mixin/check_line_breakable.rb +1 -1
  30. data/lib/rubocop/cop/mixin/hash_transform_method.rb +9 -5
  31. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  32. data/lib/rubocop/cop/naming/constant_name.rb +2 -2
  33. data/lib/rubocop/cop/style/access_modifier_declarations.rb +77 -1
  34. data/lib/rubocop/cop/style/case_equality.rb +40 -10
  35. data/lib/rubocop/cop/style/each_for_simple_loop.rb +40 -5
  36. data/lib/rubocop/cop/style/guard_clause.rb +27 -16
  37. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +2 -2
  38. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  39. data/lib/rubocop/cop/style/next.rb +1 -5
  40. data/lib/rubocop/cop/style/perl_backrefs.rb +22 -1
  41. data/lib/rubocop/cop/style/redundant_parentheses.rb +4 -0
  42. data/lib/rubocop/cop/style/safe_navigation.rb +4 -2
  43. data/lib/rubocop/cop/style/sole_nested_conditional.rb +0 -2
  44. data/lib/rubocop/cop/style/symbol_array.rb +1 -1
  45. data/lib/rubocop/cop/style/symbol_proc.rb +5 -4
  46. data/lib/rubocop/cop/style/word_array.rb +1 -1
  47. data/lib/rubocop/cop/util.rb +1 -1
  48. data/lib/rubocop/feature_loader.rb +3 -1
  49. data/lib/rubocop/formatter/html_formatter.rb +2 -2
  50. data/lib/rubocop/runner.rb +4 -0
  51. data/lib/rubocop/server/cache.rb +9 -8
  52. data/lib/rubocop/version.rb +3 -2
  53. data/lib/rubocop.rb +1 -1
  54. metadata +5 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6533c308e8ecd9193b09cd13fb1f967d1721cbfe4e4cb88bcb453861362b5152
4
- data.tar.gz: a8ebb7e167336289eb9adf7e05cbf8bfe59ccc9669b9177b363a7d54b4d597fc
3
+ metadata.gz: 4bc2d4bd29fd7e81f4d7118fef9f55bcd2f086fd20ce383d85c2a1b7b26ea4e9
4
+ data.tar.gz: 9cb3cef8736b03dd0834b94fefe4415a301d78d842df184a1a1d290973376070
5
5
  SHA512:
6
- metadata.gz: d49c12af4f602e15bf19903272b4ac0e834004f9eb07eecbca829a619559b6326dd95e2e9e10121763c73ff844968853e59dd89f84e9eded8d48bef0149cb379
7
- data.tar.gz: 440d3e163691372ef95aa49847a58e611e669faf0d950f24b0135264d234c4bc4e35ef5c5a6d92394725cf3947295fd7b107dd48bfb7937df9a7fbac7ba70e90
6
+ metadata.gz: abeba580bae46458f6427c3d21c6532e95ff88e7d981d196f5013fee29c8f911146f229daa8e6f92d2f28bb14790edc46373a4366f9881700df18a7f5a1352fa
7
+ data.tar.gz: 4bee5fc42db940e95cd6e3fba83680e6d7fd573a8ed3b7c65136a48d5f3b67ba8d299ecdd30a422afb95961d84c9b0452e3d1b6c1952e0edee1cea97ca704952
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.35', require: false
56
+ gem 'rubocop', '~> 1.36', 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
@@ -2794,6 +2794,7 @@ Naming/MethodParameterName:
2794
2794
  AllowNamesEndingInNumbers: true
2795
2795
  # Allowed names that will not register an offense
2796
2796
  AllowedNames:
2797
+ - as
2797
2798
  - at
2798
2799
  - by
2799
2800
  - db
@@ -2948,6 +2949,7 @@ Style/AccessModifierDeclarations:
2948
2949
  - inline
2949
2950
  - group
2950
2951
  AllowModifiersOnSymbols: true
2952
+ SafeAutoCorrect: false
2951
2953
 
2952
2954
  Style/AccessorGrouping:
2953
2955
  Description: 'Checks for grouping of accessors in `class` and `module` bodies.'
@@ -3186,6 +3188,15 @@ Style/CaseEquality:
3186
3188
  # # good
3187
3189
  # String === "string"
3188
3190
  AllowOnConstant: false
3191
+ # If `AllowOnSelfClass` option is enabled, the cop will ignore violations when the receiver of
3192
+ # the case equality operator is `self.class`.
3193
+ #
3194
+ # # bad
3195
+ # some_class === object
3196
+ #
3197
+ # # good
3198
+ # self.class === object
3199
+ AllowOnSelfClass: false
3189
3200
 
3190
3201
  Style/CaseLikeIf:
3191
3202
  Description: 'Identifies places where `if-elsif` constructions can be replaced with `case-when`.'
@@ -242,7 +242,7 @@ module RuboCop
242
242
  return nil unless loaded_path
243
243
 
244
244
  base_path = base_dir_for_path_parameters
245
- ['gems.locked', 'Gemfile.lock'].each do |file_name|
245
+ ['Gemfile.lock', 'gems.locked'].each do |file_name|
246
246
  path = find_file_upwards(file_name, base_path)
247
247
  return path if path
248
248
  end
@@ -55,8 +55,8 @@ module RuboCop
55
55
  end
56
56
  end
57
57
 
58
- def require_path_fragments(require_directove)
59
- path = require_directove.match(REQUIRE_PATH)
58
+ def require_path_fragments(require_directive)
59
+ path = require_directive.match(REQUIRE_PATH)
60
60
 
61
61
  path ? path.captures.first.split('/') : []
62
62
  end
@@ -29,20 +29,21 @@ module RuboCop
29
29
  extend AutoCorrector
30
30
 
31
31
  MSG = 'Use `%<preferred>s`.'
32
- RESTRICT_ON_SEND = %i[==].freeze
32
+ RESTRICT_ON_SEND = %i[== !=].freeze
33
33
 
34
34
  # @!method single_line_comparison(node)
35
35
  def_node_matcher :single_line_comparison, <<~PATTERN
36
36
  {
37
- (send (send $_receiver {:line :first_line}) :== (send _receiver :last_line))
38
- (send (send $_receiver :last_line) :== (send _receiver {:line :first_line}))
37
+ (send (send $_receiver {:line :first_line}) {:== :!=} (send _receiver :last_line))
38
+ (send (send $_receiver :last_line) {:== :!=} (send _receiver {:line :first_line}))
39
39
  }
40
40
  PATTERN
41
41
 
42
42
  def on_send(node)
43
43
  return unless (receiver = single_line_comparison(node))
44
44
 
45
- preferred = "#{extract_receiver(receiver)}.single_line?"
45
+ bang = node.method?(:!=) ? '!' : ''
46
+ preferred = "#{bang}#{extract_receiver(receiver)}.single_line?"
46
47
 
47
48
  add_offense(node, message: format(MSG, preferred: preferred)) do |corrector|
48
49
  corrector.replace(node, preferred)
@@ -22,23 +22,24 @@ module RuboCop
22
22
  # # bad
23
23
  #
24
24
  # foo.bar
25
- # .each do
26
- # baz
27
- # end
25
+ # .each do
26
+ # baz
27
+ # end
28
28
  #
29
29
  # # good
30
30
  #
31
- # variable = lambda do |i|
32
- # i
31
+ # foo.bar
32
+ # .each do
33
+ # baz
33
34
  # end
34
35
  #
35
36
  # @example EnforcedStyleAlignWith: start_of_block
36
37
  # # bad
37
38
  #
38
39
  # foo.bar
39
- # .each do
40
- # baz
41
- # end
40
+ # .each do
41
+ # baz
42
+ # end
42
43
  #
43
44
  # # good
44
45
  #
@@ -51,16 +52,17 @@ module RuboCop
51
52
  # # bad
52
53
  #
53
54
  # foo.bar
54
- # .each do
55
- # baz
56
- # end
55
+ # .each do
56
+ # baz
57
+ # end
57
58
  #
58
59
  # # good
59
60
  #
60
61
  # foo.bar
61
62
  # .each do
62
- # baz
63
+ # baz
63
64
  # end
65
+ #
64
66
  class BlockAlignment < Base
65
67
  include ConfigurableEnforcedStyle
66
68
  include RangeHelp
@@ -22,20 +22,20 @@ module RuboCop
22
22
  # # all platforms.
23
23
  #
24
24
  # # bad
25
- # puts 'Hello' # Return character is CR+LF on all platfoms.
25
+ # puts 'Hello' # Return character is CR+LF on all platforms.
26
26
  #
27
27
  # # good
28
- # puts 'Hello' # Return character is LF on all platfoms.
28
+ # puts 'Hello' # Return character is LF on all platforms.
29
29
  #
30
30
  # @example EnforcedStyle: crlf
31
31
  # # The `crlf` style means that CR+LF (Carriage Return + Line Feed) is
32
32
  # # enforced on all platforms.
33
33
  #
34
34
  # # bad
35
- # puts 'Hello' # Return character is LF on all platfoms.
35
+ # puts 'Hello' # Return character is LF on all platforms.
36
36
  #
37
37
  # # good
38
- # puts 'Hello' # Return character is CR+LF on all platfoms.
38
+ # puts 'Hello' # Return character is CR+LF on all platforms.
39
39
  #
40
40
  class EndOfLine < Base
41
41
  include ConfigurableEnforcedStyle
@@ -143,7 +143,7 @@ module RuboCop
143
143
  case indent_base_type
144
144
  when :left_brace_or_bracket
145
145
  'the position of the opening bracket'
146
- when :first_colmn_after_left_parenthesis
146
+ when :first_column_after_left_parenthesis
147
147
  'the first position after the preceding left parenthesis'
148
148
  when :parent_hash_key
149
149
  'the parent hash key'
@@ -164,7 +164,7 @@ module RuboCop
164
164
  case indent_base_type
165
165
  when :left_brace_or_bracket
166
166
  'Indent the right bracket the same as the left bracket.'
167
- when :first_colmn_after_left_parenthesis
167
+ when :first_column_after_left_parenthesis
168
168
  'Indent the right bracket the same as the first position ' \
169
169
  'after the preceding left parenthesis.'
170
170
  when :parent_hash_key
@@ -192,7 +192,7 @@ module RuboCop
192
192
  case indent_base_type
193
193
  when :left_brace_or_bracket
194
194
  'the position of the opening brace'
195
- when :first_colmn_after_left_parenthesis
195
+ when :first_column_after_left_parenthesis
196
196
  'the first position after the preceding left parenthesis'
197
197
  when :parent_hash_key
198
198
  'the parent hash key'
@@ -213,7 +213,7 @@ module RuboCop
213
213
  case indent_base_type
214
214
  when :left_brace_or_bracket
215
215
  'Indent the right brace the same as the left brace.'
216
- when :first_colmn_after_left_parenthesis
216
+ when :first_column_after_left_parenthesis
217
217
  'Indent the right brace the same as the first position ' \
218
218
  'after the preceding left parenthesis.'
219
219
  when :parent_hash_key
@@ -148,7 +148,9 @@ module RuboCop
148
148
  check_indentation(in_pattern_node.loc.keyword, in_pattern_node.body)
149
149
  end
150
150
 
151
- check_indentation(case_match.in_pattern_branches.last.loc.keyword, case_match.else_branch)
151
+ else_branch = case_match.else_branch&.empty_else_type? ? nil : case_match.else_branch
152
+
153
+ check_indentation(case_match.in_pattern_branches.last.loc.keyword, else_branch)
152
154
  end
153
155
 
154
156
  def on_if(node, base = node)
@@ -101,7 +101,7 @@ module RuboCop
101
101
  !comment_within?(node) &&
102
102
  node.each_descendant(:if, :case, :kwbegin, :def).none? &&
103
103
  node.each_descendant(:dstr, :str).none?(&:heredoc?) &&
104
- node.each_descendant(:begin).none? { |b| b.first_line != b.last_line }
104
+ node.each_descendant(:begin).none? { |b| !b.single_line? }
105
105
  end
106
106
 
107
107
  def convertible_block?(node)
@@ -131,7 +131,7 @@ module RuboCop
131
131
  args_delimiter = node.arguments.loc.begin if node.block_type? # Can be ( | or nil.
132
132
 
133
133
  check_left_brace(inner, node.loc.begin, args_delimiter)
134
- check_right_brace(inner, node.loc.begin, node.loc.end, node.single_line?)
134
+ check_right_brace(node, inner, node.loc.begin, node.loc.end, node.single_line?)
135
135
  end
136
136
 
137
137
  def check_left_brace(inner, left_brace, args_delimiter)
@@ -142,14 +142,15 @@ module RuboCop
142
142
  end
143
143
  end
144
144
 
145
- def check_right_brace(inner, left_brace, right_brace, single_line)
145
+ def check_right_brace(node, inner, left_brace, right_brace, single_line)
146
146
  if single_line && /\S$/.match?(inner)
147
147
  no_space(right_brace.begin_pos, right_brace.end_pos, 'Space missing inside }.')
148
148
  else
149
+ column = node.loc.expression.column
149
150
  return if multiline_block?(left_brace, right_brace) &&
150
- aligned_braces?(left_brace, right_brace)
151
+ aligned_braces?(inner, right_brace, column)
151
152
 
152
- space_inside_right_brace(right_brace)
153
+ space_inside_right_brace(inner, right_brace, column)
153
154
  end
154
155
  end
155
156
 
@@ -157,8 +158,12 @@ module RuboCop
157
158
  left_brace.first_line != right_brace.first_line
158
159
  end
159
160
 
160
- def aligned_braces?(left_brace, right_brace)
161
- left_brace.first_line == right_brace.last_column
161
+ def aligned_braces?(inner, right_brace, column)
162
+ column == right_brace.column || column == inner_last_space_count(inner)
163
+ end
164
+
165
+ def inner_last_space_count(inner)
166
+ inner.split("\n").last.count(' ')
162
167
  end
163
168
 
164
169
  def no_space_inside_left_brace(left_brace, args_delimiter)
@@ -197,10 +202,21 @@ module RuboCop
197
202
  args_delimiter&.is?('|')
198
203
  end
199
204
 
200
- def space_inside_right_brace(right_brace)
205
+ def space_inside_right_brace(inner, right_brace, column)
201
206
  brace_with_space = range_with_surrounding_space(right_brace, side: :left)
202
- space(brace_with_space.begin_pos, brace_with_space.end_pos - 1,
203
- 'Space inside } detected.')
207
+ begin_pos = brace_with_space.begin_pos
208
+ end_pos = brace_with_space.end_pos - 1
209
+
210
+ if brace_with_space.source.match?(/\R/)
211
+ begin_pos = end_pos - (right_brace.column - column)
212
+ end
213
+
214
+ if inner.end_with?(']')
215
+ end_pos -= 1
216
+ begin_pos = end_pos - (inner_last_space_count(inner) - column)
217
+ end
218
+
219
+ space(begin_pos, end_pos, 'Space inside } detected.')
204
220
  end
205
221
 
206
222
  def no_space(begin_pos, end_pos, msg)
@@ -81,7 +81,7 @@ module RuboCop
81
81
  def allowed_method_pattern?(node)
82
82
  node.assignment? || node.operator_method? || node.method?(:[]) ||
83
83
  allowed_method?(node.last_argument.method_name) ||
84
- matches_allowed_pattern?(node.last_argument.method_name)
84
+ matches_allowed_pattern?(node.last_argument.send_node.source)
85
85
  end
86
86
 
87
87
  def message(send_node)
@@ -66,7 +66,7 @@ module RuboCop
66
66
  private
67
67
 
68
68
  def delimiter
69
- CLASS_METHOD_DELIMETER
69
+ CLASS_METHOD_DELIMITER
70
70
  end
71
71
  end
72
72
 
@@ -89,7 +89,7 @@ module RuboCop
89
89
  private
90
90
 
91
91
  def delimiter
92
- instance_method? ? INSTANCE_METHOD_DELIMETER : CLASS_METHOD_DELIMETER
92
+ instance_method? ? INSTANCE_METHOD_DELIMITER : CLASS_METHOD_DELIMITER
93
93
  end
94
94
 
95
95
  def instance_method?
@@ -126,8 +126,8 @@ module RuboCop
126
126
 
127
127
  RESTRICT_ON_SEND = DEPRECATED_METHODS_OBJECT.keys.map(&:method).freeze
128
128
 
129
- CLASS_METHOD_DELIMETER = '.'
130
- INSTANCE_METHOD_DELIMETER = '#'
129
+ CLASS_METHOD_DELIMITER = '.'
130
+ INSTANCE_METHOD_DELIMITER = '#'
131
131
 
132
132
  def on_send(node)
133
133
  check(node) do |deprecated|
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Lint
6
- # Checks for duplicate `require`s and `require_relative`s.
6
+ # Checks for duplicate ``require``s and ``require_relative``s.
7
7
  #
8
8
  # @safety
9
9
  # This cop's autocorrection is unsafe because it may break the dependency order
@@ -96,7 +96,7 @@ module RuboCop
96
96
  end
97
97
 
98
98
  def correct_other_branches(corrector, node)
99
- return unless (node.if? || node.unless?) && node.else_branch
99
+ return unless require_other_branches_correction?(node)
100
100
 
101
101
  if node.else_branch.if_type?
102
102
  # Replace an orphaned `elsif` with `if`
@@ -107,13 +107,43 @@ module RuboCop
107
107
  end
108
108
  end
109
109
 
110
+ def require_other_branches_correction?(node)
111
+ return false unless node.if_type? && node.else_branch
112
+ return false if !empty_if_branch?(node) && node.elsif?
113
+
114
+ !empty_else_branch?(node)
115
+ end
116
+
117
+ def empty_if_branch?(node)
118
+ return false unless (parent = node.parent)
119
+ return true unless parent.if_type?
120
+ return true unless (if_branch = parent.if_branch)
121
+
122
+ if_branch.if_type? && !if_branch.body
123
+ end
124
+
125
+ def empty_else_branch?(node)
126
+ node.else_branch.if_type? && !node.else_branch.body
127
+ end
128
+
129
+ # rubocop:disable Metrics/AbcSize
110
130
  def branch_range(node)
111
131
  if node.loc.else
112
132
  node.source_range.with(end_pos: node.loc.else.begin_pos - 1)
133
+ elsif all_branches_body_missing?(node)
134
+ if_node = node.ancestors.detect(&:if?)
135
+ node.source_range.with(end_pos: if_node.loc.end.end_pos)
113
136
  else
114
137
  node.source_range
115
138
  end
116
139
  end
140
+ # rubocop:enable Metrics/AbcSize
141
+
142
+ def all_branches_body_missing?(node)
143
+ return false unless node.parent&.if_type?
144
+
145
+ node.parent.branches.compact.empty?
146
+ end
117
147
 
118
148
  def deletion_range(range)
119
149
  # Collect a range between the start of the `if` node and the next relevant node,
@@ -58,6 +58,7 @@ module RuboCop
58
58
  (node.str_type? && !node.loc.respond_to?(:begin)) || node.source_range.is?('__LINE__')
59
59
  end
60
60
 
61
+ # rubocop:disable Metrics/MethodLength
61
62
  def autocorrected_value(node)
62
63
  case node.type
63
64
  when :int
@@ -70,10 +71,13 @@ module RuboCop
70
71
  autocorrected_value_for_symbol(node)
71
72
  when :array
72
73
  autocorrected_value_for_array(node)
74
+ when :nil
75
+ ''
73
76
  else
74
77
  node.source.gsub('"', '\"')
75
78
  end
76
79
  end
80
+ # rubocop:enable Metrics/MethodLength
77
81
 
78
82
  def autocorrected_value_for_string(node)
79
83
  if node.source.start_with?("'", '%q')
@@ -99,19 +99,19 @@ module RuboCop
99
99
  end
100
100
 
101
101
  def register_offense(node, exist_node)
102
- unless force_method?(node)
103
- add_offense(node,
104
- message: format(MSG_CHANGE_FORCE_METHOD,
105
- method_name: replacement_method(node)))
106
- end
102
+ add_offense(node, message: message_change_force_method(node)) unless force_method?(node)
107
103
 
108
104
  range = range_between(node.parent.loc.keyword.begin_pos,
109
105
  exist_node.loc.expression.end_pos)
110
106
  add_offense(range, message: message_remove_file_exist_check(exist_node)) do |corrector|
111
- autocorrect(corrector, node, range)
107
+ autocorrect(corrector, node, range) unless node.parent.elsif?
112
108
  end
113
109
  end
114
110
 
111
+ def message_change_force_method(node)
112
+ format(MSG_CHANGE_FORCE_METHOD, method_name: replacement_method(node))
113
+ end
114
+
115
115
  def message_remove_file_exist_check(node)
116
116
  receiver, method_name = receiver_and_method_name(node)
117
117
  format(MSG_REMOVE_FILE_EXIST_CHECK, receiver: receiver, method_name: method_name)
@@ -7,6 +7,11 @@ module RuboCop
7
7
  # `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, and `equal?` methods
8
8
  # are checked by default. These are customizable with `AllowedMethods` option.
9
9
  #
10
+ # The `AllowedMethods` option specifies nil-safe methods,
11
+ # in other words, it is a method that is allowed to skip safe navigation.
12
+ # Note that the `AllowedMethod` option is not an option that specifies methods
13
+ # for which to suppress (allow) this cop's check.
14
+ #
10
15
  # In the example below, the safe navigation operator (`&.`) is unnecessary
11
16
  # because `NilClass` has methods like `respond_to?` and `is_a?`.
12
17
  #
@@ -35,12 +40,13 @@ module RuboCop
35
40
  # # good - without `&.` this will always return `true`
36
41
  # foo&.respond_to?(:to_a)
37
42
  #
38
- # @example AllowedMethods: [foo?]
43
+ # @example AllowedMethods: [nil_safe_method]
39
44
  # # bad
40
- # do_something if attrs&.foo?(:[])
45
+ # do_something if attrs&.nil_safe_method(:[])
41
46
  #
42
47
  # # good
43
- # do_something if attrs&.bar?(:[])
48
+ # do_something if attrs.nil_safe_method(:[])
49
+ # do_something if attrs&.not_nil_safe_method(:[])
44
50
  #
45
51
  class RedundantSafeNavigation < Base
46
52
  include AllowedMethods
@@ -12,7 +12,7 @@ module RuboCop
12
12
  # same `rescue` statement. In both cases, the more specific rescue is
13
13
  # unnecessary because it is covered by rescuing the less specific
14
14
  # exception. (ie. `rescue Exception, StandardError` has the same behavior
15
- # whether `StandardError` is included or not, because all `StandardError`s
15
+ # whether `StandardError` is included or not, because all ``StandardError``s
16
16
  # are rescued by `rescue Exception`).
17
17
  #
18
18
  # @example
@@ -64,14 +64,26 @@ module RuboCop
64
64
  end
65
65
 
66
66
  def same_conditions_node_different_branch?(variable, outer_local_variable)
67
- variable_node = variable.scope.node.parent
67
+ variable_node = variable_node(variable)
68
68
  return false unless variable_node.conditional?
69
69
 
70
70
  outer_local_variable_node =
71
71
  find_conditional_node_from_ascendant(outer_local_variable.declaration_node)
72
72
  return true unless outer_local_variable_node
73
73
 
74
- outer_local_variable_node.conditional? && variable_node == outer_local_variable_node
74
+ outer_local_variable_node.conditional? &&
75
+ (variable_node == outer_local_variable_node ||
76
+ variable_node == outer_local_variable_node.else_branch)
77
+ end
78
+
79
+ def variable_node(variable)
80
+ parent_node = variable.scope.node.parent
81
+
82
+ if parent_node.when_type?
83
+ parent_node.parent
84
+ else
85
+ parent_node
86
+ end
75
87
  end
76
88
 
77
89
  def find_conditional_node_from_ascendant(node)
@@ -9,7 +9,7 @@ module RuboCop
9
9
  # In rare cases where only one iteration (or at most one iteration) is intended behavior,
10
10
  # the code should be refactored to use `if` conditionals.
11
11
  #
12
- # NOTE: Block methods that are used with `Enumerable`s are considered to be loops.
12
+ # NOTE: Block methods that are used with ``Enumerable``s are considered to be loops.
13
13
  #
14
14
  # `AllowedPatterns` can be used to match against the block receiver in order to allow
15
15
  # code that would otherwise be registered as an offense (eg. `times` used not in an
@@ -31,8 +31,8 @@ module RuboCop
31
31
  # # bad
32
32
  # class Foo
33
33
  # # The following is redundant (methods defined on the class'
34
- # # singleton class are not affected by the public modifier)
35
- # public
34
+ # # singleton class are not affected by the private modifier)
35
+ # private
36
36
  #
37
37
  # def self.method3
38
38
  # end
@@ -6,7 +6,7 @@ module RuboCop
6
6
  # Looks for `ruby2_keywords` calls for methods that do not need it.
7
7
  #
8
8
  # `ruby2_keywords` should only be called on methods that accept an argument splat
9
- # (`*args`) but do not explicit keyword arguments (`k:` or `k: true`) or
9
+ # (`\*args`) but do not explicit keyword arguments (`k:` or `k: true`) or
10
10
  # a keyword splat (`**kwargs`).
11
11
  #
12
12
  # @example
@@ -17,16 +17,21 @@ module RuboCop
17
17
 
18
18
  # @api public
19
19
  def allowed_methods
20
- deprecated_values = cop_config_deprecated_values
21
- if deprecated_values.any?(Regexp)
22
- cop_config.fetch('AllowedMethods', [])
20
+ if cop_config_deprecated_values.any?(Regexp)
21
+ cop_config_allowed_methods
23
22
  else
24
- Array(cop_config['AllowedMethods']).concat(deprecated_values)
23
+ cop_config_allowed_methods + cop_config_deprecated_values
25
24
  end
26
25
  end
27
26
 
27
+ def cop_config_allowed_methods
28
+ @cop_config_allowed_methods ||= Array(cop_config.fetch('AllowedMethods', []))
29
+ end
30
+
28
31
  def cop_config_deprecated_values
29
- Array(cop_config['IgnoredMethods']).concat(Array(cop_config['ExcludedMethods']))
32
+ @cop_config_deprecated_values ||=
33
+ Array(cop_config.fetch('IgnoredMethods', [])) +
34
+ Array(cop_config.fetch('ExcludedMethods', []))
30
35
  end
31
36
  end
32
37
  # @deprecated IgnoredMethods class has been replaced with AllowedMethods.
@@ -30,15 +30,23 @@ module RuboCop
30
30
  def allowed_patterns
31
31
  # Since there could be a pattern specified in the default config, merge the two
32
32
  # arrays together.
33
- patterns = Array(cop_config['AllowedPatterns']).concat(Array(cop_config['IgnoredPatterns']))
34
- deprecated_values = cop_config_deprecated_methods_values
35
- return patterns unless deprecated_values.any?(Regexp)
33
+ if cop_config_deprecated_methods_values.any?(Regexp)
34
+ cop_config_patterns_values + cop_config_deprecated_methods_values
35
+ else
36
+ cop_config_patterns_values
37
+ end
38
+ end
36
39
 
37
- Array(patterns.concat(deprecated_values))
40
+ def cop_config_patterns_values
41
+ @cop_config_patterns_values ||=
42
+ Array(cop_config.fetch('AllowedPatterns', [])) +
43
+ Array(cop_config.fetch('IgnoredPatterns', []))
38
44
  end
39
45
 
40
46
  def cop_config_deprecated_methods_values
41
- Array(cop_config['IgnoredMethods']).concat(Array(cop_config['ExcludedMethods']))
47
+ @cop_config_deprecated_methods_values ||=
48
+ Array(cop_config.fetch('IgnoredMethods', [])) +
49
+ Array(cop_config.fetch('ExcludedMethods', []))
42
50
  end
43
51
  end
44
52
 
@@ -220,7 +220,7 @@ module RuboCop
220
220
  def already_on_multiple_lines?(node)
221
221
  return node.first_line != node.arguments.last.last_line if node.def_type?
222
222
 
223
- node.first_line != node.last_line
223
+ !node.single_line?
224
224
  end
225
225
  end
226
226
  end