rubocop 1.43.0 → 1.44.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +50 -0
  4. data/lib/rubocop/config_loader.rb +12 -15
  5. data/lib/rubocop/cop/corrector.rb +10 -2
  6. data/lib/rubocop/cop/correctors/ordered_gem_corrector.rb +1 -6
  7. data/lib/rubocop/cop/gemspec/development_dependencies.rb +107 -0
  8. data/lib/rubocop/cop/internal_affairs/redundant_let_rubocop_config_new.rb +11 -3
  9. data/lib/rubocop/cop/layout/block_end_newline.rb +7 -1
  10. data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +1 -5
  11. data/lib/rubocop/cop/layout/heredoc_indentation.rb +6 -9
  12. data/lib/rubocop/cop/layout/space_inside_array_literal_brackets.rb +0 -2
  13. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +62 -112
  14. data/lib/rubocop/cop/lint/else_layout.rb +2 -6
  15. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +10 -7
  16. data/lib/rubocop/cop/lint/redundant_require_statement.rb +11 -1
  17. data/lib/rubocop/cop/lint/useless_method_definition.rb +3 -3
  18. data/lib/rubocop/cop/lint/useless_rescue.rb +15 -1
  19. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +9 -1
  20. data/lib/rubocop/cop/lint/void.rb +17 -10
  21. data/lib/rubocop/cop/metrics/block_nesting.rb +1 -1
  22. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +1 -1
  23. data/lib/rubocop/cop/metrics/utils/abc_size_calculator.rb +2 -5
  24. data/lib/rubocop/cop/mixin/alignment.rb +1 -1
  25. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +40 -18
  26. data/lib/rubocop/cop/mixin/line_length_help.rb +3 -1
  27. data/lib/rubocop/cop/registry.rb +12 -7
  28. data/lib/rubocop/cop/style/access_modifier_declarations.rb +18 -10
  29. data/lib/rubocop/cop/style/block_delimiters.rb +8 -2
  30. data/lib/rubocop/cop/style/class_and_module_children.rb +2 -9
  31. data/lib/rubocop/cop/style/comparable_clamp.rb +125 -0
  32. data/lib/rubocop/cop/style/conditional_assignment.rb +0 -6
  33. data/lib/rubocop/cop/style/infinite_loop.rb +2 -5
  34. data/lib/rubocop/cop/style/invertible_unless_condition.rb +114 -0
  35. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +11 -5
  36. data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +2 -0
  37. data/lib/rubocop/cop/style/min_max_comparison.rb +11 -1
  38. data/lib/rubocop/cop/style/multiline_if_modifier.rb +0 -4
  39. data/lib/rubocop/cop/style/multiline_memoization.rb +2 -2
  40. data/lib/rubocop/cop/style/negated_if_else_condition.rb +1 -5
  41. data/lib/rubocop/cop/style/one_line_conditional.rb +2 -5
  42. data/lib/rubocop/cop/style/operator_method_call.rb +1 -1
  43. data/lib/rubocop/cop/style/redundant_conditional.rb +0 -4
  44. data/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb +16 -10
  45. data/lib/rubocop/cop/style/require_order.rb +2 -9
  46. data/lib/rubocop/cop/style/semicolon.rb +24 -2
  47. data/lib/rubocop/cop/variable_force.rb +1 -1
  48. data/lib/rubocop/formatter.rb +0 -1
  49. data/lib/rubocop/rspec/expect_offense.rb +5 -3
  50. data/lib/rubocop/server/cache.rb +3 -1
  51. data/lib/rubocop/version.rb +1 -1
  52. data/lib/rubocop.rb +3 -0
  53. metadata +6 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: adbae8e6d8a8ad828f302b9d3bba545a8b7fe54727480077a1878d4c2109dbf3
4
- data.tar.gz: fb30d554306879712c48bec3d389b4232ee8f8dde6d410dd139b73796a076d3d
3
+ metadata.gz: ad37375bb32d669c2c9ac877f9a8522829c76495e41bffb9796663807dfbcf2d
4
+ data.tar.gz: 8efe81401a312e4e7f438509aa1dfa7929d505d8797863dc55c97212573fbfda
5
5
  SHA512:
6
- metadata.gz: 7aa85cf4d34b4994422b5aa921d746b68bc282c97f7563affa2b2574a9b1102eefce4e10bed58801bb6ef9fb2ee2d3d563a63f5b114d754a69c872f6830a793e
7
- data.tar.gz: 1e088db8ccb3cdcf2ab7b9e624b68bfc4513681e4cc8ee6bd69084dfa91fda775fc28483a4764962829230d6d2fd5726855299ba1ae622bf85cc66f55451c8c9
6
+ metadata.gz: 7ece75066f9a765556559a906b11feef8d68bd6fe72a160c378bd10f59c5aab66d2e1b034a0932a7cc6aeab09275e1758e3680fbb0e05e79567deefd975e94bf
7
+ data.tar.gz: b1ed9f275eb702308fb17406da11b13ae79ed7453ba4145c857e5192004469c0c6ec07bab8030f6de0831bcebfb19dda4a9a484ea830d237de6c2154f571b03b
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.43', require: false
56
+ gem 'rubocop', '~> 1.44', require: false
57
57
  ```
58
58
 
59
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
data/config/default.yml CHANGED
@@ -262,6 +262,22 @@ Gemspec/DeprecatedAttributeAssignment:
262
262
  Include:
263
263
  - '**/*.gemspec'
264
264
 
265
+ Gemspec/DevelopmentDependencies:
266
+ Description: Checks that development dependencies are specified in Gemfile rather than gemspec.
267
+ Enabled: pending
268
+ VersionAdded: '1.44'
269
+ EnforcedStyle: Gemfile
270
+ SupportedStyles:
271
+ - Gemfile
272
+ - gems.rb
273
+ - gemspec
274
+ AllowedGems:
275
+ - bundler
276
+ Include:
277
+ - '**/*.gemspec'
278
+ - '**/Gemfile'
279
+ - '**/gems.rb'
280
+
265
281
  Gemspec/DuplicatedAssignment:
266
282
  Description: 'An attribute assignment method calls should be listed only once in a gemspec.'
267
283
  Enabled: true
@@ -3431,6 +3447,11 @@ Style/CommentedKeyword:
3431
3447
  VersionAdded: '0.51'
3432
3448
  VersionChanged: '1.19'
3433
3449
 
3450
+ Style/ComparableClamp:
3451
+ Description: 'Enforces the use of `Comparable#clamp` instead of comparison by minimum and maximum.'
3452
+ Enabled: pending
3453
+ VersionAdded: '1.44'
3454
+
3434
3455
  Style/ConcatArrayLiterals:
3435
3456
  Description: 'Enforces the use of `Array#push(item)` instead of `Array#concat([item])` to avoid redundant array literals.'
3436
3457
  Enabled: pending
@@ -4031,6 +4052,35 @@ Style/InverseMethods:
4031
4052
  :select: :reject
4032
4053
  :select!: :reject!
4033
4054
 
4055
+ Style/InvertibleUnlessCondition:
4056
+ Description: 'Favor `if` with inverted condition over `unless`.'
4057
+ Enabled: false
4058
+ VersionAdded: '1.44'
4059
+ # `InverseMethods` are methods that can be inverted in a `unless` condition.
4060
+ # The relationship of inverse methods needs to be defined in both directions.
4061
+ # Keys and values both need to be defined as symbols.
4062
+ InverseMethods:
4063
+ :!=: :==
4064
+ :>: :<=
4065
+ :<=: :>
4066
+ :<: :>=
4067
+ :>=: :<
4068
+ :!~: :=~
4069
+ :zero?: :nonzero?
4070
+ :nonzero?: :zero?
4071
+ :any?: :none?
4072
+ :none?: :any?
4073
+ :even?: :odd?
4074
+ :odd?: :even?
4075
+ # `ActiveSupport` defines some common inverse methods. They are listed below,
4076
+ # and not enabled by default.
4077
+ # :present?: :blank?
4078
+ # :blank?: :present?
4079
+ # :include?: :exclude?
4080
+ # :exclude?: :include?
4081
+ # :one?: :many?
4082
+ # :many?: :one?
4083
+
4034
4084
  Style/IpAddresses:
4035
4085
  Description: "Don't include literal IP addresses in code."
4036
4086
  Enabled: false
@@ -111,10 +111,17 @@ module RuboCop
111
111
  end
112
112
 
113
113
  merge_with_default(config, config_file).tap do |merged_config|
114
- warn_on_pending_cops(merged_config.pending_cops) unless possible_new_cops?(merged_config)
114
+ unless possible_new_cops?(merged_config)
115
+ pending_cops = pending_cops_only_qualified(merged_config.pending_cops)
116
+ warn_on_pending_cops(pending_cops) unless pending_cops.empty?
117
+ end
115
118
  end
116
119
  end
117
120
 
121
+ def pending_cops_only_qualified(pending_cops)
122
+ pending_cops.select { |cop| Cop::Registry.qualified_cop?(cop.name) }
123
+ end
124
+
118
125
  def possible_new_cops?(config)
119
126
  disable_pending_cops || enable_pending_cops ||
120
127
  config.disabled_new_cops? || config.enabled_new_cops?
@@ -167,8 +174,6 @@ module RuboCop
167
174
  BANNER
168
175
 
169
176
  def warn_on_pending_cops(pending_cops)
170
- return if pending_cops.empty?
171
-
172
177
  warn Rainbow(PENDING_BANNER).yellow
173
178
 
174
179
  pending_cops.each { |cop| warn_pending_cop cop }
@@ -241,18 +246,10 @@ module RuboCop
241
246
  raise
242
247
  end
243
248
 
244
- if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0')
245
- def yaml_safe_load!(yaml_code, filename)
246
- YAML.safe_load(yaml_code,
247
- permitted_classes: [Regexp, Symbol],
248
- permitted_symbols: [],
249
- aliases: true,
250
- filename: filename)
251
- end
252
- else # Ruby < 2.6
253
- def yaml_safe_load!(yaml_code, filename)
254
- YAML.safe_load(yaml_code, [Regexp, Symbol], [], true, filename)
255
- end
249
+ def yaml_safe_load!(yaml_code, filename)
250
+ YAML.safe_load(
251
+ yaml_code, permitted_classes: [Regexp, Symbol], aliases: true, filename: filename
252
+ )
256
253
  end
257
254
  end
258
255
 
@@ -86,8 +86,16 @@ module RuboCop
86
86
  range1 = to_range(node_or_range1)
87
87
  range2 = to_range(node_or_range2)
88
88
 
89
- replace(range1, range2.source)
90
- replace(range2, range1.source)
89
+ if range1.end_pos == range2.begin_pos
90
+ insert_before(range1, range2.source)
91
+ remove(range2)
92
+ elsif range2.end_pos == range1.begin_pos
93
+ insert_before(range2, range1.source)
94
+ remove(range1)
95
+ else
96
+ replace(range1, range2.source)
97
+ replace(range2, range1.source)
98
+ end
91
99
  end
92
100
 
93
101
  private
@@ -18,7 +18,7 @@ module RuboCop
18
18
  current_range = declaration_with_comment(node)
19
19
  previous_range = declaration_with_comment(previous_declaration)
20
20
 
21
- ->(corrector) { swap_range(corrector, current_range, previous_range) }
21
+ ->(corrector) { corrector.swap(current_range, previous_range) }
22
22
  end
23
23
 
24
24
  private
@@ -32,11 +32,6 @@ module RuboCop
32
32
 
33
33
  range_between(begin_pos, end_pos)
34
34
  end
35
-
36
- def swap_range(corrector, range1, range2)
37
- corrector.insert_before(range2, range1.source)
38
- corrector.remove(range1)
39
- end
40
35
  end
41
36
  end
42
37
  end
@@ -0,0 +1,107 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Gemspec
6
+ # Enforce that development dependencies for a gem are specified in
7
+ # `Gemfile`, rather than in the `gemspec` using
8
+ # `add_development_dependency`. Alternatively, using `EnforcedStyle:
9
+ # gemspec`, enforce that all dependencies are specified in `gemspec`,
10
+ # rather than in `Gemfile`.
11
+ #
12
+ # @example EnforcedStyle: Gemfile (default)
13
+ # # Specify runtime dependencies in your gemspec,
14
+ # # but all other dependencies in your Gemfile.
15
+ #
16
+ # # bad
17
+ # # example.gemspec
18
+ # s.add_development_dependency "foo"
19
+ #
20
+ # # good
21
+ # # Gemfile
22
+ # gem "foo"
23
+ #
24
+ # # good
25
+ # # gems.rb
26
+ # gem "foo"
27
+ #
28
+ # # good (with AllowedGems: ["bar"])
29
+ # # example.gemspec
30
+ # s.add_development_dependency "bar"
31
+ #
32
+ # @example EnforcedStyle: gems.rb
33
+ # # Specify runtime dependencies in your gemspec,
34
+ # # but all other dependencies in your Gemfile.
35
+ # #
36
+ # # Identical to `EnforcedStyle: Gemfile`, but with a different error message.
37
+ # # Rely on Bundler/GemFilename to enforce the use of `Gemfile` vs `gems.rb`.
38
+ #
39
+ # # bad
40
+ # # example.gemspec
41
+ # s.add_development_dependency "foo"
42
+ #
43
+ # # good
44
+ # # Gemfile
45
+ # gem "foo"
46
+ #
47
+ # # good
48
+ # # gems.rb
49
+ # gem "foo"
50
+ #
51
+ # # good (with AllowedGems: ["bar"])
52
+ # # example.gemspec
53
+ # s.add_development_dependency "bar"
54
+ #
55
+ # @example EnforcedStyle: gemspec
56
+ # # Specify all dependencies in your gemspec.
57
+ #
58
+ # # bad
59
+ # # Gemfile
60
+ # gem "foo"
61
+ #
62
+ # # good
63
+ # # example.gemspec
64
+ # s.add_development_dependency "foo"
65
+ #
66
+ # # good (with AllowedGems: ["bar"])
67
+ # # Gemfile
68
+ # gem "bar"
69
+ #
70
+ class DevelopmentDependencies < Base
71
+ include ConfigurableEnforcedStyle
72
+
73
+ MSG = 'Specify development dependencies in %<preferred>s.'
74
+ RESTRICT_ON_SEND = %i[add_development_dependency gem].freeze
75
+
76
+ # @!method add_development_dependency?(node)
77
+ def_node_matcher :add_development_dependency?, <<~PATTERN
78
+ (send _ :add_development_dependency (str #forbidden_gem? ...))
79
+ PATTERN
80
+
81
+ # @!method gem?(node)
82
+ def_node_matcher :gem?, <<~PATTERN
83
+ (send _ :gem (str #forbidden_gem? ...))
84
+ PATTERN
85
+
86
+ def on_send(node)
87
+ case style
88
+ when :Gemfile, :'gems.rb'
89
+ add_offense(node) if add_development_dependency?(node)
90
+ when :gemspec
91
+ add_offense(node) if gem?(node)
92
+ end
93
+ end
94
+
95
+ private
96
+
97
+ def forbidden_gem?(gem_name)
98
+ !cop_config['AllowedGems'].include?(gem_name)
99
+ end
100
+
101
+ def message(_range)
102
+ format(MSG, preferred: style)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -31,9 +31,17 @@ module RuboCop
31
31
  (send nil? :let
32
32
  (sym :config))
33
33
  (args)
34
- (send
35
- (const
36
- (const nil? :RuboCop) :Config) :new))
34
+ {
35
+ (send
36
+ (const
37
+ (const nil? :RuboCop) :Config) :new)
38
+ (send
39
+ (const
40
+ (const nil? :RuboCop) :Config) :new
41
+ (hash (pair (send (send (send nil? :described_class) :badge) :to_s)
42
+ (send nil? :cop_config))))
43
+ }
44
+ )
37
45
  PATTERN
38
46
 
39
47
  def on_block(node)
@@ -46,7 +46,7 @@ module RuboCop
46
46
  def register_offense(node)
47
47
  add_offense(node.loc.end, message: message(node)) do |corrector|
48
48
  offense_range = offense_range(node)
49
- replacement = "\n#{offense_range.source.strip}"
49
+ replacement = replacement(node)
50
50
 
51
51
  if (heredoc = last_heredoc_argument(node.body))
52
52
  corrector.remove(offense_range)
@@ -79,6 +79,12 @@ module RuboCop
79
79
  )
80
80
  end
81
81
 
82
+ def replacement(node)
83
+ end_with_method_chain = node.loc.end.join(end_of_method_chain(node).loc.expression.end)
84
+
85
+ "\n#{end_with_method_chain.source.strip}"
86
+ end
87
+
82
88
  def end_of_method_chain(node)
83
89
  return node unless node.parent&.call_type?
84
90
 
@@ -144,7 +144,7 @@ module RuboCop
144
144
  def expected_column(left_paren, elements)
145
145
  if line_break_after_left_paren?(left_paren, elements)
146
146
  source_indent = processed_source.line_indentation(first_argument_line(elements))
147
- new_indent = source_indent - indentation_width
147
+ new_indent = source_indent - configured_indentation_width
148
148
 
149
149
  new_indent.negative? ? 0 : new_indent
150
150
  elsif all_elements_aligned?(elements)
@@ -184,10 +184,6 @@ module RuboCop
184
184
  end
185
185
  end
186
186
 
187
- def indentation_width
188
- @config.for_cop('Layout/IndentationWidth')['Width'] || 2
189
- end
190
-
191
187
  def line_break_after_left_paren?(left_paren, elements)
192
188
  elements.first && elements.first.loc.line > left_paren.line
193
189
  end
@@ -22,6 +22,7 @@ module RuboCop
22
22
  # RUBY
23
23
  #
24
24
  class HeredocIndentation < Base
25
+ include Alignment
25
26
  include Heredoc
26
27
  extend AutoCorrector
27
28
 
@@ -37,7 +38,7 @@ module RuboCop
37
38
  heredoc_indent_type = heredoc_indent_type(node)
38
39
 
39
40
  if heredoc_indent_type == '~'
40
- expected_indent_level = base_indent_level(node) + indentation_width
41
+ expected_indent_level = base_indent_level(node) + configured_indentation_width
41
42
  return if expected_indent_level == body_indent_level
42
43
  else
43
44
  return unless body_indent_level.zero?
@@ -66,9 +67,9 @@ module RuboCop
66
67
  current_indent_type = "<<#{heredoc_indent_type}"
67
68
 
68
69
  if current_indent_type == '<<~'
69
- width_message(indentation_width)
70
+ width_message(configured_indentation_width)
70
71
  else
71
- type_message(indentation_width, current_indent_type)
72
+ type_message(configured_indentation_width, current_indent_type)
72
73
  end
73
74
  end
74
75
 
@@ -89,7 +90,7 @@ module RuboCop
89
90
 
90
91
  body = heredoc_body(node)
91
92
 
92
- expected_indent = base_indent_level(node) + indentation_width
93
+ expected_indent = base_indent_level(node) + configured_indentation_width
93
94
  actual_indent = indent_level(body)
94
95
  increase_indent_level = expected_indent - actual_indent
95
96
 
@@ -122,7 +123,7 @@ module RuboCop
122
123
  def indented_body(node)
123
124
  body = heredoc_body(node)
124
125
  body_indent_level = indent_level(body)
125
- correct_indent_level = base_indent_level(node) + indentation_width
126
+ correct_indent_level = base_indent_level(node) + configured_indentation_width
126
127
  body.gsub(/^[^\S\r\n]{#{body_indent_level}}/, ' ' * correct_indent_level)
127
128
  end
128
129
 
@@ -148,10 +149,6 @@ module RuboCop
148
149
  node.source[/^<<([~-])/, 1]
149
150
  end
150
151
 
151
- def indentation_width
152
- @config.for_cop('Layout/IndentationWidth')['Width'] || 2
153
- end
154
-
155
152
  def heredoc_body(node)
156
153
  node.loc.heredoc_body.source
157
154
  end
@@ -178,8 +178,6 @@ module RuboCop
178
178
  def multi_dimensional_array?(node, token, side: :right)
179
179
  offset = side == :right ? -1 : +1
180
180
  i = index_for(node, token) + offset
181
- # TODO: change this type check once
182
- # https://github.com/rubocop/rubocop-ast/pull/240 is merged
183
181
  i += offset while processed_source.tokens_within(node)[i].new_line?
184
182
  if side == :right
185
183
  processed_source.tokens_within(node)[i].right_bracket?
@@ -11,6 +11,8 @@ module RuboCop
11
11
  # File.exists?(some_path)
12
12
  # Dir.exists?(some_path)
13
13
  # iterator?
14
+ # attr :name, true
15
+ # attr :name, false
14
16
  # ENV.freeze # Calling `Env.freeze` raises `TypeError` since Ruby 2.7.
15
17
  # ENV.clone
16
18
  # ENV.dup # Calling `Env.dup` raises `TypeError` since Ruby 3.1.
@@ -21,6 +23,8 @@ module RuboCop
21
23
  # File.exist?(some_path)
22
24
  # Dir.exist?(some_path)
23
25
  # block_given?
26
+ # attr_accessor :name
27
+ # attr_reader :name
24
28
  # ENV # `ENV.freeze` cannot prohibit changes to environment variables.
25
29
  # ENV.to_h
26
30
  # ENV.to_h # `ENV.dup` cannot dup `ENV`, use `ENV.to_h` to get a copy of `ENV` as a hash.
@@ -29,138 +33,84 @@ module RuboCop
29
33
  class DeprecatedClassMethods < Base
30
34
  extend AutoCorrector
31
35
 
32
- # Inner class to DeprecatedClassMethods.
33
- # This class exists to add abstraction and clean naming
34
- # to the deprecated objects
35
- class DeprecatedClassMethod
36
- include RuboCop::AST::Sexp
36
+ MSG = '`%<current>s` is deprecated in favor of `%<prefer>s`.'
37
+ RESTRICT_ON_SEND = %i[
38
+ attr clone dup exists? freeze gethostbyaddr gethostbyname iterator?
39
+ ].freeze
40
+
41
+ PREFERRED_METHDOS = {
42
+ clone: 'to_h',
43
+ dup: 'to_h',
44
+ exists?: 'exist?',
45
+ gethostbyaddr: 'Addrinfo#getnameinfo',
46
+ gethostbyname: 'Addrinfo#getaddrinfo',
47
+ iterator?: 'block_given?'
48
+ }.freeze
37
49
 
38
- attr_reader :method, :class_constant
50
+ DIR_ENV_FILE_CONSTANTS = %i[Dir ENV File].freeze
39
51
 
40
- def initialize(method, class_constant: nil, correctable: true)
41
- @method = method
42
- @class_constant = class_constant
43
- @correctable = correctable
44
- end
45
-
46
- def class_nodes
47
- @class_nodes ||=
48
- if class_constant
49
- [
50
- s(:const, nil, class_constant),
51
- s(:const, s(:cbase), class_constant)
52
- ]
53
- else
54
- [nil]
55
- end
56
- end
52
+ # @!method deprecated_class_method?(node)
53
+ def_node_matcher :deprecated_class_method?, <<~PATTERN
54
+ {
55
+ (send (const {cbase nil?} {:ENV}) {:clone :dup :freeze})
56
+ (send (const {cbase nil?} {:File :Dir}) :exists? _)
57
+ (send (const {cbase nil?} :Socket) {:gethostbyaddr :gethostbyname} ...)
58
+ (send nil? :attr _ boolean)
59
+ (send nil? :iterator?)
60
+ }
61
+ PATTERN
57
62
 
58
- def correctable?
59
- @correctable
60
- end
63
+ def on_send(node)
64
+ return unless deprecated_class_method?(node)
61
65
 
62
- def to_s
63
- [class_constant, method].compact.join(delimiter)
64
- end
66
+ offense_range = offense_range(node)
67
+ prefer = preferred_method(node)
68
+ message = format(MSG, current: offense_range.source, prefer: prefer)
65
69
 
66
- private
70
+ add_offense(offense_range, message: message) do |corrector|
71
+ next if socket_const?(node.receiver)
67
72
 
68
- def delimiter
69
- CLASS_METHOD_DELIMITER
73
+ if node.method?(:freeze)
74
+ corrector.replace(node, 'ENV')
75
+ else
76
+ corrector.replace(offense_range, prefer)
77
+ end
70
78
  end
71
79
  end
72
80
 
73
- # Inner class to DeprecatedClassMethods.
74
- # This class exists to add abstraction and clean naming
75
- # to the replacements for deprecated objects
76
- class Replacement
77
- attr_reader :method, :class_constant
78
-
79
- def initialize(method, class_constant: nil, instance_method: false)
80
- @method = method
81
- @class_constant = class_constant
82
- @instance_method = instance_method
83
- end
84
-
85
- def to_s
86
- [class_constant, method].compact.join(delimiter)
87
- end
88
-
89
- private
90
-
91
- def delimiter
92
- instance_method? ? INSTANCE_METHOD_DELIMITER : CLASS_METHOD_DELIMITER
93
- end
81
+ private
94
82
 
95
- def instance_method?
96
- @instance_method
83
+ def offense_range(node)
84
+ if socket_const?(node.receiver) || dir_env_file_const?(node.receiver)
85
+ node.loc.expression.begin.join(node.loc.selector.end)
86
+ elsif node.method?(:attr)
87
+ node
88
+ else
89
+ node.loc.selector
97
90
  end
98
91
  end
99
92
 
100
- MSG = '`%<current>s` is deprecated in favor of `%<prefer>s`.'
101
-
102
- DEPRECATED_METHODS_OBJECT = {
103
- DeprecatedClassMethod.new(:exists?, class_constant: :File) =>
104
- Replacement.new(:exist?, class_constant: :File),
105
-
106
- DeprecatedClassMethod.new(:exists?, class_constant: :Dir) =>
107
- Replacement.new(:exist?, class_constant: :Dir),
108
-
109
- DeprecatedClassMethod.new(:iterator?) => Replacement.new(:block_given?),
110
-
111
- DeprecatedClassMethod.new(:freeze, class_constant: :ENV) =>
112
- Replacement.new(nil, class_constant: :ENV),
93
+ def preferred_method(node)
94
+ if node.method?(:attr)
95
+ boolean_argument = node.arguments[1].source
96
+ preferred_attr_method = boolean_argument == 'true' ? 'attr_accessor' : 'attr_reader'
113
97
 
114
- DeprecatedClassMethod.new(:clone, class_constant: :ENV) =>
115
- Replacement.new(:to_h, class_constant: :ENV),
116
-
117
- DeprecatedClassMethod.new(:dup, class_constant: :ENV) =>
118
- Replacement.new(:to_h, class_constant: :ENV),
119
-
120
- DeprecatedClassMethod.new(:gethostbyaddr, class_constant: :Socket, correctable: false) =>
121
- Replacement.new(:getnameinfo, class_constant: :Addrinfo, instance_method: true),
122
-
123
- DeprecatedClassMethod.new(:gethostbyname, class_constant: :Socket, correctable: false) =>
124
- Replacement.new(:getaddrinfo, class_constant: :Addrinfo, instance_method: true)
125
- }.freeze
98
+ "#{preferred_attr_method} #{node.first_argument.source}"
99
+ elsif dir_env_file_const?(node.receiver)
100
+ prefer = PREFERRED_METHDOS[node.method_name]
126
101
 
127
- RESTRICT_ON_SEND = DEPRECATED_METHODS_OBJECT.keys.map(&:method).freeze
128
-
129
- CLASS_METHOD_DELIMITER = '.'
130
- INSTANCE_METHOD_DELIMITER = '#'
131
-
132
- def on_send(node)
133
- check(node) do |deprecated|
134
- prefer = replacement(deprecated)
135
- message = format(MSG, current: deprecated, prefer: prefer)
136
- current_method = node.loc.selector
137
-
138
- add_offense(current_method, message: message) do |corrector|
139
- next unless deprecated.correctable?
140
-
141
- if (preferred_method = prefer.method)
142
- corrector.replace(current_method, preferred_method)
143
- else
144
- corrector.remove(node.loc.dot)
145
- corrector.remove(current_method)
146
- end
147
- end
102
+ prefer ? "#{node.receiver.source}.#{prefer}" : 'ENV'
103
+ else
104
+ PREFERRED_METHDOS[node.method_name]
148
105
  end
149
106
  end
150
107
 
151
- private
152
-
153
- def check(node)
154
- DEPRECATED_METHODS_OBJECT.each_key do |deprecated|
155
- next unless deprecated.class_nodes.include?(node.receiver)
156
- next unless node.method?(deprecated.method)
157
-
158
- yield deprecated
159
- end
108
+ def socket_const?(node)
109
+ node&.short_name == :Socket
160
110
  end
161
111
 
162
- def replacement(deprecated)
163
- DEPRECATED_METHODS_OBJECT[deprecated]
112
+ def dir_env_file_const?(node)
113
+ DIR_ENV_FILE_CONSTANTS.include?(node&.short_name)
164
114
  end
165
115
  end
166
116
  end
@@ -41,6 +41,7 @@ module RuboCop
41
41
  # do_that
42
42
  # end
43
43
  class ElseLayout < Base
44
+ include Alignment
44
45
  include RangeHelp
45
46
  extend AutoCorrector
46
47
 
@@ -81,12 +82,7 @@ module RuboCop
81
82
  corrector.insert_after(node.loc.else, "\n")
82
83
 
83
84
  blank_range = range_between(node.loc.else.end_pos, first_else.loc.expression.begin_pos)
84
- indentation = indent(node, offset: indentation_width)
85
- corrector.replace(blank_range, indentation)
86
- end
87
-
88
- def indentation_width
89
- @config.for_cop('Layout/IndentationWidth')['Width'] || 2
85
+ corrector.replace(blank_range, indentation(node))
90
86
  end
91
87
  end
92
88
  end