rubocop 1.38.0 → 1.40.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 (83) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +51 -11
  4. data/exe/rubocop +1 -1
  5. data/lib/rubocop/comment_config.rb +5 -0
  6. data/lib/rubocop/config.rb +5 -4
  7. data/lib/rubocop/config_loader.rb +5 -5
  8. data/lib/rubocop/config_loader_resolver.rb +1 -1
  9. data/lib/rubocop/cop/base.rb +2 -9
  10. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +22 -6
  11. data/lib/rubocop/cop/internal_affairs/lambda_or_proc.rb +46 -0
  12. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  13. data/lib/rubocop/cop/layout/line_continuation_leading_space.rb +29 -8
  14. data/lib/rubocop/cop/layout/space_inside_array_percent_literal.rb +3 -0
  15. data/lib/rubocop/cop/layout/space_inside_percent_literal_delimiters.rb +34 -0
  16. data/lib/rubocop/cop/lint/ambiguous_block_association.rb +1 -1
  17. data/lib/rubocop/cop/lint/assignment_in_condition.rb +11 -1
  18. data/lib/rubocop/cop/lint/deprecated_constants.rb +8 -1
  19. data/lib/rubocop/cop/lint/duplicate_methods.rb +17 -8
  20. data/lib/rubocop/cop/lint/empty_block.rb +1 -5
  21. data/lib/rubocop/cop/lint/empty_conditional_body.rb +1 -1
  22. data/lib/rubocop/cop/lint/interpolation_check.rb +4 -3
  23. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +5 -0
  24. data/lib/rubocop/cop/lint/redundant_cop_disable_directive.rb +13 -3
  25. data/lib/rubocop/cop/lint/safe_navigation_chain.rb +15 -6
  26. data/lib/rubocop/cop/lint/send_with_mixin_argument.rb +5 -4
  27. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +4 -3
  28. data/lib/rubocop/cop/lint/suppressed_exception.rb +1 -1
  29. data/lib/rubocop/cop/lint/void.rb +6 -6
  30. data/lib/rubocop/cop/metrics/abc_size.rb +1 -1
  31. data/lib/rubocop/cop/metrics/block_length.rb +9 -4
  32. data/lib/rubocop/cop/metrics/class_length.rb +9 -4
  33. data/lib/rubocop/cop/metrics/method_length.rb +9 -4
  34. data/lib/rubocop/cop/metrics/module_length.rb +9 -4
  35. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +5 -2
  36. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +24 -5
  37. data/lib/rubocop/cop/mixin/range_help.rb +23 -0
  38. data/lib/rubocop/cop/mixin/statement_modifier.rb +15 -1
  39. data/lib/rubocop/cop/mixin/visibility_help.rb +40 -5
  40. data/lib/rubocop/cop/registry.rb +23 -11
  41. data/lib/rubocop/cop/style/access_modifier_declarations.rb +1 -25
  42. data/lib/rubocop/cop/style/array_intersect.rb +111 -0
  43. data/lib/rubocop/cop/style/class_equality_comparison.rb +7 -5
  44. data/lib/rubocop/cop/style/collection_compact.rb +1 -1
  45. data/lib/rubocop/cop/style/guard_clause.rb +32 -5
  46. data/lib/rubocop/cop/style/hash_as_last_array_item.rb +1 -0
  47. data/lib/rubocop/cop/style/hash_each_methods.rb +32 -10
  48. data/lib/rubocop/cop/style/hash_except.rb +4 -0
  49. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -1
  50. data/lib/rubocop/cop/style/nil_lambda.rb +1 -1
  51. data/lib/rubocop/cop/style/object_then.rb +3 -0
  52. data/lib/rubocop/cop/style/operator_method_call.rb +13 -0
  53. data/lib/rubocop/cop/style/quoted_symbols.rb +1 -1
  54. data/lib/rubocop/cop/style/redundant_argument.rb +3 -0
  55. data/lib/rubocop/cop/style/redundant_constant_base.rb +72 -0
  56. data/lib/rubocop/cop/style/redundant_each.rb +13 -8
  57. data/lib/rubocop/cop/style/redundant_regexp_escape.rb +12 -3
  58. data/lib/rubocop/cop/style/redundant_return.rb +7 -0
  59. data/lib/rubocop/cop/style/redundant_sort.rb +1 -1
  60. data/lib/rubocop/cop/style/require_order.rb +88 -0
  61. data/lib/rubocop/cop/style/safe_navigation.rb +35 -6
  62. data/lib/rubocop/cop/style/select_by_regexp.rb +8 -4
  63. data/lib/rubocop/cop/style/string_literals.rb +1 -5
  64. data/lib/rubocop/cop/style/symbol_proc.rb +2 -4
  65. data/lib/rubocop/cop/team.rb +1 -1
  66. data/lib/rubocop/cop/util.rb +2 -2
  67. data/lib/rubocop/cop/variable_force/assignment.rb +1 -1
  68. data/lib/rubocop/cop/variable_force.rb +20 -29
  69. data/lib/rubocop/cops_documentation_generator.rb +3 -4
  70. data/lib/rubocop/formatter/disabled_config_formatter.rb +17 -6
  71. data/lib/rubocop/formatter/html_formatter.rb +1 -1
  72. data/lib/rubocop/formatter.rb +3 -1
  73. data/lib/rubocop/optimized_patterns.rb +38 -0
  74. data/lib/rubocop/options.rb +9 -1
  75. data/lib/rubocop/path_util.rb +14 -2
  76. data/lib/rubocop/result_cache.rb +1 -1
  77. data/lib/rubocop/rspec/cop_helper.rb +4 -1
  78. data/lib/rubocop/rspec/support.rb +2 -2
  79. data/lib/rubocop/server/core.rb +16 -1
  80. data/lib/rubocop/target_ruby.rb +1 -1
  81. data/lib/rubocop/version.rb +1 -1
  82. data/lib/rubocop.rb +14 -6
  83. metadata +8 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ed47ef39bb205db15249a399d0502f730c2656f712293357651cc0ddd328715
4
- data.tar.gz: 5e6411a2b459e0ac426e0ef0d8b8508b9b1693fea0c5b8cb5d82ed23f71d39b9
3
+ metadata.gz: bb2b7b02733dca8e7577cd5ccd776044179cd762685152d9c7d5a739dd7cf9e1
4
+ data.tar.gz: 47b6ef2704e65f30af91def68b22331aca13d629d954cc860288738dccd4f14d
5
5
  SHA512:
6
- metadata.gz: 5cfd13ac3c283e77e300f87ee923be282740f2763e26c73d21d27b5ae176629d15d8d580d9d326349acf5b71c74e6335689c2192050a818577b9f2e0a6a4484f
7
- data.tar.gz: 27f36547ccdf6cc1336e1c44c5e164410f65344cba77fda76ad2db463054adaa93c96a406939b3826412280463a1d6a2940708f4080bc3170999bcc81594ba9d
6
+ metadata.gz: c65cd2840052b36832dec3218f2994b0dbaae5e482328c767b0f82ac3d882ce1a29a02ddd53e960c199514ff241d17d0c5f33b139b50634fce4c7fa246018a1c
7
+ data.tar.gz: 51442c821afd72669bb0845386c1c05495618736b46978e1d2fae12f3f69f30ff914025209f6efc2c673692e585e4e2968fe76467f2433ba98f2209d435b46bd
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.38', require: false
56
+ gem 'rubocop', '~> 1.40', 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
@@ -161,7 +161,9 @@ AllCops:
161
161
  Bundler/DuplicatedGem:
162
162
  Description: 'Checks for duplicate gem entries in Gemfile.'
163
163
  Enabled: true
164
+ Severity: warning
164
165
  VersionAdded: '0.46'
166
+ VersionChanged: '1.40'
165
167
  Include:
166
168
  - '**/*.gemfile'
167
169
  - '**/Gemfile'
@@ -213,7 +215,9 @@ Bundler/InsecureProtocolSource:
213
215
  because HTTP requests are insecure. Please change your source to
214
216
  'https://rubygems.org' if possible, or 'http://rubygems.org' if not.
215
217
  Enabled: true
218
+ Severity: warning
216
219
  VersionAdded: '0.50'
220
+ VersionChanged: '1.40'
217
221
  AllowHttpProtocol: true
218
222
  Include:
219
223
  - '**/*.gemfile'
@@ -252,14 +256,18 @@ Gemspec/DependencyVersion:
252
256
  Gemspec/DeprecatedAttributeAssignment:
253
257
  Description: Checks that deprecated attribute assignments are not set in a gemspec file.
254
258
  Enabled: pending
259
+ Severity: warning
255
260
  VersionAdded: '1.30'
261
+ VersionChanged: '1.40'
256
262
  Include:
257
263
  - '**/*.gemspec'
258
264
 
259
265
  Gemspec/DuplicatedAssignment:
260
266
  Description: 'An attribute assignment method calls should be listed only once in a gemspec.'
261
267
  Enabled: true
268
+ Severity: warning
262
269
  VersionAdded: '0.52'
270
+ VersionChanged: '1.40'
263
271
  Include:
264
272
  - '**/*.gemspec'
265
273
 
@@ -278,7 +286,9 @@ Gemspec/OrderedDependencies:
278
286
  Gemspec/RequireMFA:
279
287
  Description: 'Checks that the gemspec has metadata to require Multi-Factor Authentication from RubyGems.'
280
288
  Enabled: pending
289
+ Severity: warning
281
290
  VersionAdded: '1.23'
291
+ VersionChanged: '1.40'
282
292
  Reference:
283
293
  - https://guides.rubygems.org/mfa-requirement-opt-in/
284
294
  Include:
@@ -287,8 +297,9 @@ Gemspec/RequireMFA:
287
297
  Gemspec/RequiredRubyVersion:
288
298
  Description: 'Checks that `required_ruby_version` of gemspec is specified and equal to `TargetRubyVersion` of .rubocop.yml.'
289
299
  Enabled: true
300
+ Severity: warning
290
301
  VersionAdded: '0.52'
291
- VersionChanged: '1.22'
302
+ VersionChanged: '1.40'
292
303
  Include:
293
304
  - '**/*.gemspec'
294
305
 
@@ -296,7 +307,9 @@ Gemspec/RubyVersionGlobalsUsage:
296
307
  Description: Checks usage of RUBY_VERSION in gemspec.
297
308
  StyleGuide: '#no-ruby-version-in-the-gemspec'
298
309
  Enabled: true
310
+ Severity: warning
299
311
  VersionAdded: '0.72'
312
+ VersionChanged: '1.40'
300
313
  Include:
301
314
  - '**/*.gemspec'
302
315
 
@@ -378,8 +391,9 @@ Layout/AssignmentIndentation:
378
391
  Checks the indentation of the first line of the
379
392
  right-hand-side of a multi-line assignment.
380
393
  Enabled: true
394
+ SafeAutoCorrect: false
381
395
  VersionAdded: '0.49'
382
- VersionChanged: '0.77'
396
+ VersionChanged: '1.40'
383
397
  # By default the indentation width from `Layout/IndentationWidth` is used,
384
398
  # but it can be overridden by setting this parameter.
385
399
  IndentationWidth: ~
@@ -1643,7 +1657,7 @@ Lint/DeprecatedConstants:
1643
1657
  Description: 'Checks for deprecated constants.'
1644
1658
  Enabled: pending
1645
1659
  VersionAdded: '1.8'
1646
- VersionChanged: '1.22'
1660
+ VersionChanged: '1.40'
1647
1661
  # You can configure deprecated constants.
1648
1662
  # If there is an alternative method, you can set alternative value as `Alternative`.
1649
1663
  # And you can set the deprecated version as `DeprecatedVersion`.
@@ -1670,6 +1684,12 @@ Lint/DeprecatedConstants:
1670
1684
  'Random::DEFAULT':
1671
1685
  Alternative: 'Random.new'
1672
1686
  DeprecatedVersion: '3.0'
1687
+ 'Struct::Group':
1688
+ Alternative: 'Etc::Group'
1689
+ DeprecatedVersion: '3.0'
1690
+ 'Struct::Passwd':
1691
+ Alternative: 'Etc::Passwd'
1692
+ DeprecatedVersion: '3.0'
1673
1693
 
1674
1694
  Lint/DeprecatedOpenSSLConstant:
1675
1695
  Description: "Don't use algorithm constants for `OpenSSL::Cipher` and `OpenSSL::Digest`."
@@ -1894,11 +1914,11 @@ Lint/InheritException:
1894
1914
  - runtime_error
1895
1915
 
1896
1916
  Lint/InterpolationCheck:
1897
- Description: 'Raise warning for interpolation in single q strs.'
1917
+ Description: 'Checks for interpolation in a single quoted string.'
1898
1918
  Enabled: true
1899
- Safe: false
1919
+ SafeAutoCorrect: false
1900
1920
  VersionAdded: '0.50'
1901
- VersionChanged: '0.87'
1921
+ VersionChanged: '1.40'
1902
1922
 
1903
1923
  Lint/LambdaWithoutLiteralBlock:
1904
1924
  Description: 'Checks uses of lambda without a literal block.'
@@ -2806,8 +2826,10 @@ Naming/MethodParameterName:
2806
2826
  - as
2807
2827
  - at
2808
2828
  - by
2829
+ - cc
2809
2830
  - db
2810
2831
  - id
2832
+ - if
2811
2833
  - in
2812
2834
  - io
2813
2835
  - ip
@@ -3012,6 +3034,11 @@ Style/ArrayCoercion:
3012
3034
  Enabled: false
3013
3035
  VersionAdded: '0.88'
3014
3036
 
3037
+ Style/ArrayIntersect:
3038
+ Description: 'Use `array1.intersect?(array2)` instead of `(array1 & array2).any?`.'
3039
+ Enabled: 'pending'
3040
+ VersionAdded: '1.40'
3041
+
3015
3042
  Style/ArrayJoin:
3016
3043
  Description: 'Use Array#join instead of Array#*.'
3017
3044
  StyleGuide: '#array-join'
@@ -3448,7 +3475,7 @@ Style/Copyright:
3448
3475
 
3449
3476
  Style/DateTime:
3450
3477
  Description: 'Use Time over DateTime.'
3451
- StyleGuide: '#date--time'
3478
+ StyleGuide: '#date-time'
3452
3479
  Enabled: false
3453
3480
  VersionAdded: '0.51'
3454
3481
  VersionChanged: '0.92'
@@ -3819,8 +3846,9 @@ Style/HashExcept:
3819
3846
  Checks for usages of `Hash#reject`, `Hash#select`, and `Hash#filter` methods
3820
3847
  that can be replaced with `Hash#except` method.
3821
3848
  Enabled: pending
3849
+ Safe: false
3822
3850
  VersionAdded: '1.7'
3823
- VersionChanged: '1.31'
3851
+ VersionChanged: '1.39'
3824
3852
 
3825
3853
  Style/HashLikeCase:
3826
3854
  Description: >-
@@ -4658,10 +4686,12 @@ Style/RedundantArgument:
4658
4686
  Enabled: pending
4659
4687
  Safe: false
4660
4688
  VersionAdded: '1.4'
4661
- VersionChanged: '1.7'
4689
+ VersionChanged: '1.40'
4662
4690
  Methods:
4663
4691
  # Array#join
4664
4692
  join: ''
4693
+ # Array#sum
4694
+ sum: 0
4665
4695
  # String#split
4666
4696
  split: ' '
4667
4697
  # String#chomp
@@ -4696,6 +4726,11 @@ Style/RedundantConditional:
4696
4726
  Enabled: true
4697
4727
  VersionAdded: '0.50'
4698
4728
 
4729
+ Style/RedundantConstantBase:
4730
+ Description: Avoid redundant `::` prefix on constant.
4731
+ Enabled: pending
4732
+ VersionAdded: '1.40'
4733
+
4699
4734
  Style/RedundantEach:
4700
4735
  Description: 'Checks for redundant `each`.'
4701
4736
  Enabled: pending
@@ -4836,6 +4871,12 @@ Style/RegexpLiteral:
4836
4871
  # are found in the regexp string.
4837
4872
  AllowInnerSlashes: false
4838
4873
 
4874
+ Style/RequireOrder:
4875
+ Description: Sort `require` and `require_relative` in alphabetical order.
4876
+ Enabled: false
4877
+ SafeAutoCorrect: false
4878
+ VersionAdded: '1.40'
4879
+
4839
4880
  Style/RescueModifier:
4840
4881
  Description: 'Avoid using rescue in its modifier form.'
4841
4882
  StyleGuide: '#no-rescue-modifiers'
@@ -5120,12 +5161,11 @@ Style/SymbolProc:
5120
5161
  Enabled: true
5121
5162
  Safe: false
5122
5163
  VersionAdded: '0.26'
5123
- VersionChanged: '1.28'
5164
+ VersionChanged: '1.40'
5124
5165
  AllowMethodsWithArguments: false
5125
5166
  # A list of method names to be always allowed by the check.
5126
5167
  # The names should be fairly unique, otherwise you'll end up ignoring lots of code.
5127
5168
  AllowedMethods:
5128
- - respond_to
5129
5169
  - define_method
5130
5170
  AllowedPatterns: []
5131
5171
  IgnoredMethods: [] # deprecated
data/exe/rubocop CHANGED
@@ -11,8 +11,8 @@ exit exit_status if server_cli.exit?
11
11
  if RuboCop::Server.running?
12
12
  exit_status = RuboCop::Server::ClientCommand::Exec.new.run
13
13
  else
14
- require 'rubocop'
15
14
  require 'benchmark'
15
+ require 'rubocop'
16
16
 
17
17
  cli = RuboCop::CLI.new
18
18
 
@@ -31,6 +31,7 @@ module RuboCop
31
31
 
32
32
  def initialize(processed_source)
33
33
  @processed_source = processed_source
34
+ @no_directives = !processed_source.raw_source.include?('rubocop')
34
35
  end
35
36
 
36
37
  def cop_enabled_at_line?(cop, line_number)
@@ -74,6 +75,8 @@ module RuboCop
74
75
  end
75
76
 
76
77
  def analyze # rubocop:todo Metrics/AbcSize
78
+ return {} if @no_directives
79
+
77
80
  analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) }
78
81
  inject_disabled_cops_directives(analyses)
79
82
 
@@ -146,6 +149,8 @@ module RuboCop
146
149
  end
147
150
 
148
151
  def each_directive
152
+ return if @no_directives
153
+
149
154
  processed_source.comments.each do |comment|
150
155
  directive = DirectiveComment.new(comment)
151
156
  yield directive if directive.cop_names
@@ -24,10 +24,11 @@ module RuboCop
24
24
  def initialize(hash = {}, loaded_path = nil)
25
25
  @loaded_path = loaded_path
26
26
  @for_cop = Hash.new do |h, cop|
27
- qualified_cop_name = Cop::Registry.qualified_cop_name(cop, loaded_path)
27
+ cop_name = cop.respond_to?(:cop_name) ? cop.cop_name : cop
28
+ qualified_cop_name = Cop::Registry.qualified_cop_name(cop_name, loaded_path)
28
29
  cop_options = self[qualified_cop_name].dup || {}
29
30
  cop_options['Enabled'] = enable_cop?(qualified_cop_name, cop_options)
30
- h[cop] = cop_options
31
+ h[cop] = h[cop_name] = cop_options
31
32
  end
32
33
  @hash = hash
33
34
  @validator = ConfigValidator.new(self)
@@ -116,7 +117,7 @@ module RuboCop
116
117
  # Note: the 'Enabled' attribute is calculated according to the department's
117
118
  # and 'AllCops' configuration; other attributes are not inherited.
118
119
  def for_cop(cop)
119
- @for_cop[cop.respond_to?(:cop_name) ? cop.cop_name : cop]
120
+ @for_cop[cop]
120
121
  end
121
122
 
122
123
  # @return [Config] for the given cop merged with that of its department (if any)
@@ -215,7 +216,7 @@ module RuboCop
215
216
  # directory since that wouldn't work.
216
217
  def base_dir_for_path_parameters
217
218
  @base_dir_for_path_parameters ||=
218
- if File.basename(loaded_path).start_with?('.rubocop') &&
219
+ if loaded_path && File.basename(loaded_path).start_with?('.rubocop') &&
219
220
  loaded_path != File.join(Dir.home, ConfigLoader::DOTFILE)
220
221
  File.expand_path(File.dirname(loaded_path))
221
222
  else
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'erb'
4
- require 'yaml'
5
4
  require 'pathname'
5
+ require 'yaml'
6
6
  require_relative 'config_finder'
7
7
 
8
8
  module RuboCop
@@ -42,18 +42,18 @@ module RuboCop
42
42
 
43
43
  hash = load_yaml_configuration(path)
44
44
 
45
- # Resolve requires first in case they define additional cops
46
45
  loaded_features = resolver.resolve_requires(path, hash)
47
46
  add_loaded_features(loaded_features)
48
47
 
49
- add_missing_namespaces(path, hash)
50
-
51
48
  resolver.override_department_setting_for_cops({}, hash)
52
49
  resolver.resolve_inheritance_from_gems(hash)
53
50
  resolver.resolve_inheritance(path, hash, file, debug?)
54
-
55
51
  hash.delete('inherit_from')
56
52
 
53
+ # Adding missing namespaces only after resolving requires & inheritance,
54
+ # since both can introduce new cops that need to be considered here.
55
+ add_missing_namespaces(path, hash)
56
+
57
57
  Config.create(hash, path, check: check)
58
58
  end
59
59
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
3
  require 'pathname'
4
+ require 'yaml'
5
5
 
6
6
  module RuboCop
7
7
  # A help class for ConfigLoader that handles configuration resolution.
@@ -412,15 +412,8 @@ module RuboCop
412
412
  patterns = cop_config[parameter]
413
413
  return default_result unless patterns
414
414
 
415
- path = nil
416
- patterns.any? do |pattern|
417
- # Try to match the absolute path, as Exclude properties are absolute.
418
- next true if match_path?(pattern, file)
419
-
420
- # Try with relative path.
421
- path ||= config.path_relative_to_config(file)
422
- match_path?(pattern, path)
423
- end
415
+ patterns = OptimizedPatterns.from(patterns)
416
+ patterns.match?(config.path_relative_to_config(file)) || patterns.match?(file)
424
417
  end
425
418
 
426
419
  def enabled_line?(line_number)
@@ -28,7 +28,10 @@ module RuboCop
28
28
  # put the comment.
29
29
  return if new_line_needed_before_closing_brace?(node)
30
30
 
31
- correct_next_line_brace(corrector)
31
+ end_range = last_element_range_with_trailing_comma(node).end
32
+
33
+ correct_next_line_brace(corrector, end_range)
34
+ correct_heredoc_argument_method_chain(corrector, end_range)
32
35
  end
33
36
  end
34
37
 
@@ -40,13 +43,19 @@ module RuboCop
40
43
  corrector.insert_before(node.loc.end, "\n")
41
44
  end
42
45
 
43
- def correct_next_line_brace(corrector)
46
+ def correct_next_line_brace(corrector, end_range)
44
47
  corrector.remove(range_with_surrounding_space(node.loc.end, side: :left))
48
+ corrector.insert_before(end_range, content_if_comment_present(corrector, node))
49
+ end
45
50
 
46
- corrector.insert_before(
47
- last_element_range_with_trailing_comma(node).end,
48
- content_if_comment_present(corrector, node)
49
- )
51
+ def correct_heredoc_argument_method_chain(corrector, end_range)
52
+ return unless (parent = node.parent)
53
+ return unless use_heredoc_argument_method_chain?(parent)
54
+
55
+ chained_method = range_between(parent.loc.dot.begin_pos, parent.loc.expression.end_pos)
56
+
57
+ corrector.remove(chained_method)
58
+ corrector.insert_after(end_range, chained_method.source)
50
59
  end
51
60
 
52
61
  def content_if_comment_present(corrector, node)
@@ -61,6 +70,13 @@ module RuboCop
61
70
  end
62
71
  end
63
72
 
73
+ def use_heredoc_argument_method_chain?(parent)
74
+ return false unless node.respond_to?(:first_argument)
75
+ return false unless (first_argument = node.first_argument)
76
+
77
+ parent.call_type? && first_argument.str_type? && first_argument.heredoc?
78
+ end
79
+
64
80
  def select_content_to_be_inserted_after_last_element(corrector, node)
65
81
  range = range_between(
66
82
  node.loc.end.begin_pos,
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Enforces the use of `node.lambda_or_proc?` instead of `node.lambda? || node.proc?`.
7
+ #
8
+ # @example
9
+ # # bad
10
+ # node.lambda? || node.proc?
11
+ # node.proc? || node.lambda?
12
+ #
13
+ # # good
14
+ # node.lambda_or_proc?
15
+ #
16
+ class LambdaOrProc < Base
17
+ extend AutoCorrector
18
+
19
+ MSG = 'Use `%<prefer>s`.'
20
+
21
+ # @!method lambda_or_proc(node)
22
+ def_node_matcher :lambda_or_proc, <<~PATTERN
23
+ {
24
+ (or $(send _node :lambda?) $(send _node :proc?))
25
+ (or $(send _node :proc?) $(send _node :lambda?))
26
+ (or
27
+ (or _ $(send _node :lambda?)) $(send _node :proc?))
28
+ (or
29
+ (or _ $(send _node :proc?)) $(send _node :lambda?))
30
+ }
31
+ PATTERN
32
+
33
+ def on_or(node)
34
+ return unless (lhs, rhs = lambda_or_proc(node))
35
+
36
+ offense = lhs.receiver.source_range.join(rhs.source_range.end)
37
+ prefer = "#{lhs.receiver.source}.lambda_or_proc?"
38
+
39
+ add_offense(offense, message: format(MSG, prefer: prefer)) do |corrector|
40
+ corrector.replace(offense, prefer)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -6,6 +6,7 @@ require_relative 'internal_affairs/empty_line_between_expect_offense_and_correct
6
6
  require_relative 'internal_affairs/example_description'
7
7
  require_relative 'internal_affairs/example_heredoc_delimiter'
8
8
  require_relative 'internal_affairs/inherit_deprecated_cop_class'
9
+ require_relative 'internal_affairs/lambda_or_proc'
9
10
  require_relative 'internal_affairs/location_line_equality_comparison'
10
11
  require_relative 'internal_affairs/method_name_end_with'
11
12
  require_relative 'internal_affairs/method_name_equal'
@@ -42,6 +42,14 @@ module RuboCop
42
42
  # ' long'
43
43
  class LineContinuationLeadingSpace < Base
44
44
  include RangeHelp
45
+ extend AutoCorrector
46
+
47
+ LINE_1_ENDING = /['"]\s*\\\n/.freeze
48
+ LINE_2_BEGINNING = /\A\s*['"]/.freeze
49
+ LEADING_STYLE_OFFENSE = /(?<trailing_spaces>\s+)(?<ending>#{LINE_1_ENDING})/.freeze
50
+ TRAILING_STYLE_OFFENSE = /(?<beginning>#{LINE_2_BEGINNING})(?<leading_spaces>\s+)/.freeze
51
+ private_constant :LINE_1_ENDING, :LINE_2_BEGINNING,
52
+ :LEADING_STYLE_OFFENSE, :TRAILING_STYLE_OFFENSE
45
53
 
46
54
  def on_dstr(node)
47
55
  end_of_first_line = node.loc.expression.begin_pos - node.loc.expression.column
@@ -52,9 +60,9 @@ module RuboCop
52
60
  next unless continuation?(raw_line_one)
53
61
 
54
62
  if enforced_style_leading?
55
- investigate_leading_style(raw_line_one, end_of_first_line)
63
+ investigate_leading_style(raw_line_one, raw_line_two, end_of_first_line)
56
64
  else
57
- investigate_trailing_style(raw_line_two, end_of_first_line)
65
+ investigate_trailing_style(raw_line_one, raw_line_two, end_of_first_line)
58
66
  end
59
67
  end
60
68
  end
@@ -65,24 +73,37 @@ module RuboCop
65
73
  processed_source.raw_source.lines[node.first_line - 1, line_range(node).size]
66
74
  end
67
75
 
68
- def investigate_leading_style(first_line, end_of_first_line)
69
- matches = first_line.match(/(?<trailing_spaces>\s+)(?<ending>['"]\s*\\\n)/)
76
+ def investigate_leading_style(first_line, second_line, end_of_first_line)
77
+ matches = first_line.match(LEADING_STYLE_OFFENSE)
70
78
  return if matches.nil?
71
79
 
72
- add_offense(leading_offense_range(end_of_first_line, matches))
80
+ offense_range = leading_offense_range(end_of_first_line, matches)
81
+ add_offense(offense_range) do |corrector|
82
+ insert_pos = end_of_first_line + second_line[LINE_2_BEGINNING].length
83
+ autocorrect(corrector, offense_range, insert_pos, matches[:trailing_spaces])
84
+ end
73
85
  end
74
86
 
75
- def investigate_trailing_style(second_line, end_of_first_line)
76
- matches = second_line.match(/\A(?<beginning>\s*['"])(?<leading_spaces>\s+)/)
87
+ def investigate_trailing_style(first_line, second_line, end_of_first_line)
88
+ matches = second_line.match(TRAILING_STYLE_OFFENSE)
77
89
  return if matches.nil?
78
90
 
79
- add_offense(trailing_offense_range(end_of_first_line, matches))
91
+ offense_range = trailing_offense_range(end_of_first_line, matches)
92
+ add_offense(offense_range) do |corrector|
93
+ insert_pos = end_of_first_line - first_line[LINE_1_ENDING].length
94
+ autocorrect(corrector, offense_range, insert_pos, matches[:leading_spaces])
95
+ end
80
96
  end
81
97
 
82
98
  def continuation?(line)
83
99
  line.end_with?("\\\n")
84
100
  end
85
101
 
102
+ def autocorrect(corrector, offense_range, insert_pos, spaces)
103
+ corrector.remove(offense_range)
104
+ corrector.replace(range_between(insert_pos, insert_pos), spaces)
105
+ end
106
+
86
107
  def leading_offense_range(end_of_first_line, matches)
87
108
  end_pos = end_of_first_line - matches[:ending].length
88
109
  begin_pos = end_pos - matches[:trailing_spaces].length
@@ -6,6 +6,9 @@ module RuboCop
6
6
  # Checks for unnecessary additional spaces inside array percent literals
7
7
  # (i.e. %i/%w).
8
8
  #
9
+ # Note that blank percent literals (e.g. `%i( )`) are checked by
10
+ # `Layout/SpaceInsidePercentLiteralDelimiters`.
11
+ #
9
12
  # @example
10
13
  #
11
14
  # # bad
@@ -8,14 +8,31 @@ module RuboCop
8
8
  #
9
9
  # @example
10
10
  #
11
+ # # bad
12
+ # %i( foo bar baz )
13
+ #
11
14
  # # good
12
15
  # %i(foo bar baz)
13
16
  #
14
17
  # # bad
15
18
  # %w( foo bar baz )
16
19
  #
20
+ # # good
21
+ # %w(foo bar baz)
22
+ #
17
23
  # # bad
18
24
  # %x( ls -l )
25
+ #
26
+ # # good
27
+ # %x(ls -l)
28
+ #
29
+ # # bad
30
+ # %w( )
31
+ # %w(
32
+ # )
33
+ #
34
+ # # good
35
+ # %w()
19
36
  class SpaceInsidePercentLiteralDelimiters < Base
20
37
  include MatchRange
21
38
  include PercentLiteral
@@ -34,11 +51,21 @@ module RuboCop
34
51
  end
35
52
 
36
53
  def on_percent_literal(node)
54
+ add_offenses_for_blank_spaces(node)
37
55
  add_offenses_for_unnecessary_spaces(node)
38
56
  end
39
57
 
40
58
  private
41
59
 
60
+ def add_offenses_for_blank_spaces(node)
61
+ range = body_range(node)
62
+ return if range.source.empty? || !range.source.strip.empty?
63
+
64
+ add_offense(range) do |corrector|
65
+ corrector.remove(range)
66
+ end
67
+ end
68
+
42
69
  def add_offenses_for_unnecessary_spaces(node)
43
70
  return unless node.single_line?
44
71
 
@@ -54,6 +81,13 @@ module RuboCop
54
81
  each_match_range(contents_range(node), regex, &blk)
55
82
  end
56
83
  end
84
+
85
+ def body_range(node)
86
+ node.location.expression.with(
87
+ begin_pos: node.location.begin.end_pos,
88
+ end_pos: node.location.end.begin_pos
89
+ )
90
+ end
57
91
  end
58
92
  end
59
93
  end
@@ -63,7 +63,7 @@ module RuboCop
63
63
  return unless node.arguments?
64
64
 
65
65
  return unless ambiguous_block_association?(node)
66
- return if node.parenthesized? || node.last_argument.lambda? || node.last_argument.proc? ||
66
+ return if node.parenthesized? || node.last_argument.lambda_or_proc? ||
67
67
  allowed_method_pattern?(node)
68
68
 
69
69
  message = message(node)
@@ -11,6 +11,10 @@ module RuboCop
11
11
  # an assignment to indicate "I know I'm using an assignment
12
12
  # as a condition. It's not a mistake."
13
13
  #
14
+ # @safety
15
+ # This cop's autocorrection is unsafe because it assumes that
16
+ # the author meant to use an assignment result as a condition.
17
+ #
14
18
  # @example
15
19
  # # bad
16
20
  # if some_var = true
@@ -35,6 +39,8 @@ module RuboCop
35
39
  # end
36
40
  #
37
41
  class AssignmentInCondition < Base
42
+ extend AutoCorrector
43
+
38
44
  include SafeAssignment
39
45
 
40
46
  MSG_WITH_SAFE_ASSIGNMENT_ALLOWED =
@@ -53,7 +59,11 @@ module RuboCop
53
59
  next :skip_children if skip_children?(asgn_node)
54
60
  next if allowed_construct?(asgn_node)
55
61
 
56
- add_offense(asgn_node.loc.operator)
62
+ add_offense(asgn_node.loc.operator) do |corrector|
63
+ next unless safe_assignment_allowed?
64
+
65
+ corrector.wrap(asgn_node, '(', ')')
66
+ end
57
67
  end
58
68
  end
59
69
  alias on_while on_if