rubocop 1.38.0 → 1.40.0

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