rubocop 1.23.0 → 1.25.1

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 (84) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +2 -3
  4. data/config/default.yml +60 -12
  5. data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
  6. data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
  7. data/lib/rubocop/cli/command/show_docs_url.rb +48 -0
  8. data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
  9. data/lib/rubocop/cli.rb +1 -0
  10. data/lib/rubocop/config_loader_resolver.rb +1 -1
  11. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  12. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +1 -1
  13. data/lib/rubocop/cop/correctors/if_then_corrector.rb +55 -0
  14. data/lib/rubocop/cop/documentation.rb +19 -2
  15. data/lib/rubocop/cop/gemspec/require_mfa.rb +8 -10
  16. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +10 -3
  17. data/lib/rubocop/cop/generator.rb +4 -3
  18. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +47 -0
  19. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +3 -1
  20. data/lib/rubocop/cop/internal_affairs.rb +1 -0
  21. data/lib/rubocop/cop/layout/argument_alignment.rb +36 -9
  22. data/lib/rubocop/cop/layout/comment_indentation.rb +31 -2
  23. data/lib/rubocop/cop/layout/dot_position.rb +4 -0
  24. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +5 -1
  25. data/lib/rubocop/cop/layout/hash_alignment.rb +7 -2
  26. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  27. data/lib/rubocop/cop/layout/space_after_colon.rb +1 -1
  28. data/lib/rubocop/cop/layout/space_before_first_arg.rb +4 -0
  29. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +5 -1
  30. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +1 -1
  31. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +16 -4
  32. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +6 -0
  33. data/lib/rubocop/cop/lint/each_with_object_argument.rb +1 -1
  34. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +10 -5
  35. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +7 -4
  36. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  37. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -9
  38. data/lib/rubocop/cop/metrics/method_length.rb +1 -0
  39. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  40. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  41. data/lib/rubocop/cop/metrics/utils/repeated_attribute_discount.rb +1 -1
  42. data/lib/rubocop/cop/mixin/enforce_superclass.rb +5 -0
  43. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +4 -3
  44. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +82 -0
  45. data/lib/rubocop/cop/naming/block_forwarding.rb +121 -0
  46. data/lib/rubocop/cop/naming/method_parameter_name.rb +1 -1
  47. data/lib/rubocop/cop/security/open.rb +11 -1
  48. data/lib/rubocop/cop/style/character_literal.rb +8 -1
  49. data/lib/rubocop/cop/style/collection_compact.rb +31 -13
  50. data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
  51. data/lib/rubocop/cop/style/empty_case_condition.rb +10 -0
  52. data/lib/rubocop/cop/style/file_read.rb +112 -0
  53. data/lib/rubocop/cop/style/file_write.rb +124 -0
  54. data/lib/rubocop/cop/style/hash_conversion.rb +2 -1
  55. data/lib/rubocop/cop/style/hash_syntax.rb +36 -0
  56. data/lib/rubocop/cop/style/hash_transform_keys.rb +6 -6
  57. data/lib/rubocop/cop/style/hash_transform_values.rb +6 -6
  58. data/lib/rubocop/cop/style/if_inside_else.rb +15 -0
  59. data/lib/rubocop/cop/style/if_with_boolean_literal_branches.rb +1 -1
  60. data/lib/rubocop/cop/style/map_to_hash.rb +68 -0
  61. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +20 -0
  62. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +3 -1
  63. data/lib/rubocop/cop/style/method_def_parentheses.rb +17 -13
  64. data/lib/rubocop/cop/style/numeric_literals.rb +10 -1
  65. data/lib/rubocop/cop/style/one_line_conditional.rb +18 -39
  66. data/lib/rubocop/cop/style/redundant_begin.rb +2 -6
  67. data/lib/rubocop/cop/style/redundant_interpolation.rb +17 -3
  68. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +5 -1
  69. data/lib/rubocop/cop/style/redundant_self.rb +1 -1
  70. data/lib/rubocop/cop/style/safe_navigation.rb +1 -5
  71. data/lib/rubocop/cop/style/sample.rb +5 -3
  72. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  73. data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
  74. data/lib/rubocop/cop/style/swap_values.rb +2 -0
  75. data/lib/rubocop/cop/style/ternary_parentheses.rb +16 -2
  76. data/lib/rubocop/cop/team.rb +1 -1
  77. data/lib/rubocop/cop/util.rb +9 -1
  78. data/lib/rubocop/formatter/disabled_config_formatter.rb +16 -2
  79. data/lib/rubocop/options.rb +6 -1
  80. data/lib/rubocop/remote_config.rb +1 -3
  81. data/lib/rubocop/result_cache.rb +1 -1
  82. data/lib/rubocop/version.rb +1 -1
  83. data/lib/rubocop.rb +7 -0
  84. metadata +15 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cf11fe2d8f8be8879d6afc63d6f3be50b970c7910c83f1d22847d1fc9654d4aa
4
- data.tar.gz: fd4c7ef3838a286efe3d1729672cc7a0e72f47cfb4c8d815699d53d2a974a372
3
+ metadata.gz: 54b88752efa8bb84dc034391460b9071f31179dcb279550a209d31829e7b8c93
4
+ data.tar.gz: 31115cff5fdbf562dee62cf7e07033205d150b61ac5fd11476708f21e67000cf
5
5
  SHA512:
6
- metadata.gz: 4014183525b58378a0e628ae5136d17c148a41c6c25dd51eddc810ca08fbd89d652f6c715b58eef149005af1145469936416864869b6e63a4c9e521627ab1cb4
7
- data.tar.gz: 6e0e2a9a9d6fae829b73bd49814965a28d447207aaf7d1dda073f34130343557df965c77cc998d6ddb0d59eca09f1307d6ca56cbd3fcade575ca52950d1a56d3
6
+ metadata.gz: acdaf069659a775853b20e05734e85cd65c0c8734b09e568d4360dc9a7440a49ec8e47928b0da78866e1326a588638d18f2564e6e94023bb17b2f39493555027
7
+ data.tar.gz: 2765d9c9c10966c485be6cd70190b69a25aa99800c8d483bd67c1fdfe3dc5d13bb97cb1ca7f9f663776869acda5a426bc797f3b40adda17e0241ff8b62a374f1
data/LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012-21 Bozhidar Batsov
1
+ Copyright (c) 2012-22 Bozhidar Batsov
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -9,7 +9,6 @@
9
9
  [![Actions Status](https://github.com/rubocop/rubocop/workflows/CI/badge.svg?branch=master)](https://github.com/rubocop/rubocop/actions?query=workflow%3ACI)
10
10
  [![Test Coverage](https://api.codeclimate.com/v1/badges/d2d67f728e88ea84ac69/test_coverage)](https://codeclimate.com/github/rubocop/rubocop/test_coverage)
11
11
  [![Maintainability](https://api.codeclimate.com/v1/badges/d2d67f728e88ea84ac69/maintainability)](https://codeclimate.com/github/rubocop/rubocop/maintainability)
12
- [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=rubocop&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=rubocop&package-manager=bundler&version-scheme=semver)
13
12
  [![Discord](https://img.shields.io/badge/chat-on%20discord-7289da.svg?sanitize=true)](https://discord.gg/wJjWvGRDmm)
14
13
 
15
14
  > Role models are important. <br/>
@@ -54,7 +53,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
54
53
  in your `Gemfile`:
55
54
 
56
55
  ```rb
57
- gem 'rubocop', '~> 1.23', require: false
56
+ gem 'rubocop', '~> 1.25', require: false
58
57
  ```
59
58
 
60
59
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details.
@@ -245,5 +244,5 @@ RuboCop's changelog is available [here](CHANGELOG.md).
245
244
 
246
245
  ## Copyright
247
246
 
248
- Copyright (c) 2012-2021 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for
247
+ Copyright (c) 2012-2022 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for
249
248
  further details.
data/config/default.yml CHANGED
@@ -78,6 +78,8 @@ AllCops:
78
78
  # When specifying style guide URLs, any paths and/or fragments will be
79
79
  # evaluated relative to the base URL.
80
80
  StyleGuideBaseURL: https://rubystyle.guide
81
+ # Documentation URLs will be constructed using the base URL.
82
+ DocumentationBaseURL: https://docs.rubocop.org/rubocop
81
83
  # Extra details are not displayed in offense messages by default. Change
82
84
  # behavior by overriding ExtraDetails, or by giving the
83
85
  # `-E/--extra-details` option.
@@ -428,13 +430,13 @@ Layout/ClassStructure:
428
430
  - prepend
429
431
  - extend
430
432
  ExpectedOrder:
431
- - module_inclusion
432
- - constants
433
- - public_class_methods
434
- - initializer
435
- - public_methods
436
- - protected_methods
437
- - private_methods
433
+ - module_inclusion
434
+ - constants
435
+ - public_class_methods
436
+ - initializer
437
+ - public_methods
438
+ - protected_methods
439
+ - private_methods
438
440
 
439
441
  Layout/ClosingHeredocIndentation:
440
442
  Description: 'Checks the indentation of here document closings.'
@@ -449,7 +451,11 @@ Layout/ClosingParenthesisIndentation:
449
451
  Layout/CommentIndentation:
450
452
  Description: 'Indentation of comments.'
451
453
  Enabled: true
454
+ # When true, allows comments to have extra indentation if that aligns them
455
+ # with a comment on the preceding line.
456
+ AllowForAlignment: false
452
457
  VersionAdded: '0.49'
458
+ VersionChanged: '1.24'
453
459
 
454
460
  Layout/ConditionPosition:
455
461
  Description: >-
@@ -1796,7 +1802,9 @@ Lint/ImplicitStringConcatenation:
1796
1802
  Lint/IncompatibleIoSelectWithFiberScheduler:
1797
1803
  Description: 'Checks for `IO.select` that is incompatible with Fiber Scheduler.'
1798
1804
  Enabled: pending
1805
+ SafeAutoCorrect: false
1799
1806
  VersionAdded: '1.21'
1807
+ VersionChanged: '1.24'
1800
1808
 
1801
1809
  Lint/IneffectiveAccessModifier:
1802
1810
  Description: >-
@@ -1892,7 +1900,7 @@ Lint/NestedPercentLiteral:
1892
1900
  VersionAdded: '0.52'
1893
1901
 
1894
1902
  Lint/NextWithoutAccumulator:
1895
- Description: >-
1903
+ Description: >-
1896
1904
  Do not omit the accumulator when calling `next`
1897
1905
  in a `reduce`/`inject` block.
1898
1906
  Enabled: true
@@ -2479,6 +2487,17 @@ Naming/BinaryOperatorParameterName:
2479
2487
  VersionAdded: '0.50'
2480
2488
  VersionChanged: '1.2'
2481
2489
 
2490
+ Naming/BlockForwarding:
2491
+ Description: 'Use anonymous block forwarding.'
2492
+ StyleGuide: '#block-forwarding'
2493
+ Enabled: pending
2494
+ VersionAdded: '1.24'
2495
+ EnforcedStyle: anonymous
2496
+ SupportedStyles:
2497
+ - anonymous
2498
+ - explicit
2499
+ BlockForwardingName: block
2500
+
2482
2501
  Naming/BlockParameterName:
2483
2502
  Description: >-
2484
2503
  Checks for block parameter names that contain capital letters,
@@ -3134,7 +3153,7 @@ Style/ClassMethodsDefinitions:
3134
3153
  StyleGuide: '#def-self-class-methods'
3135
3154
  Enabled: false
3136
3155
  VersionAdded: '0.89'
3137
- EnforcedStyle: def_self
3156
+ EnforcedStyle: def_self
3138
3157
  SupportedStyles:
3139
3158
  - def_self
3140
3159
  - self_class
@@ -3492,6 +3511,18 @@ Style/ExponentialNotation:
3492
3511
  - engineering
3493
3512
  - integral
3494
3513
 
3514
+ Style/FileRead:
3515
+ Description: 'Favor `File.(bin)read` convenience methods.'
3516
+ StyleGuide: '#file-read'
3517
+ Enabled: pending
3518
+ VersionAdded: '1.24'
3519
+
3520
+ Style/FileWrite:
3521
+ Description: 'Favor `File.(bin)write` convenience methods.'
3522
+ StyleGuide: '#file-write'
3523
+ Enabled: pending
3524
+ VersionAdded: '1.24'
3525
+
3495
3526
  Style/FloatDivision:
3496
3527
  Description: 'For performing float division, coerce one side only.'
3497
3528
  StyleGuide: '#float-division'
@@ -3650,7 +3681,7 @@ Style/HashSyntax:
3650
3681
  StyleGuide: '#hash-literals'
3651
3682
  Enabled: true
3652
3683
  VersionAdded: '0.9'
3653
- VersionChanged: '0.43'
3684
+ VersionChanged: '1.24'
3654
3685
  EnforcedStyle: ruby19
3655
3686
  SupportedStyles:
3656
3687
  # checks for 1.9 syntax (e.g. {a: 1}) for all symbol keys
@@ -3661,6 +3692,15 @@ Style/HashSyntax:
3661
3692
  - no_mixed_keys
3662
3693
  # enforces both ruby19 and no_mixed_keys styles
3663
3694
  - ruby19_no_mixed_keys
3695
+ # Force hashes that have a hash value omission
3696
+ EnforcedShorthandSyntax: always
3697
+ SupportedShorthandSyntax:
3698
+ # forces use of the 3.1 syntax (e.g. {foo:}) when the hash key and value are the same.
3699
+ - always
3700
+ # forces use of explicit hash literal value.
3701
+ - never
3702
+ # accepts both shorthand and explicit use of hash literal value.
3703
+ - either
3664
3704
  # Force hashes that have a symbol value to use hash rockets
3665
3705
  UseHashRocketsWithSymbolValues: false
3666
3706
  # Do not suggest { a?: 1 } over { :a? => 1 } in ruby19 style
@@ -3775,8 +3815,8 @@ Style/InverseMethods:
3775
3815
  :>: :<=
3776
3816
  # `ActiveSupport` defines some common inverse methods. They are listed below,
3777
3817
  # and not enabled by default.
3778
- #:present?: :blank?,
3779
- #:include?: :exclude?
3818
+ # :present?: :blank?,
3819
+ # :include?: :exclude?
3780
3820
  # `InverseBlocks` are methods that are inverted by inverting the return
3781
3821
  # of the block that is passed to the method
3782
3822
  InverseBlocks:
@@ -3837,6 +3877,12 @@ Style/LineEndConcatenation:
3837
3877
  VersionAdded: '0.18'
3838
3878
  VersionChanged: '0.64'
3839
3879
 
3880
+ Style/MapToHash:
3881
+ Description: 'Prefer `to_h` with a block over `map.to_h`.'
3882
+ Enabled: pending
3883
+ VersionAdded: '1.24'
3884
+ Safe: false
3885
+
3840
3886
  Style/MethodCallWithArgsParentheses:
3841
3887
  Description: 'Use parentheses for method calls with arguments.'
3842
3888
  StyleGuide: '#method-invocation-parens'
@@ -4205,6 +4251,8 @@ Style/NumericLiterals:
4205
4251
  VersionChanged: '0.48'
4206
4252
  MinDigits: 5
4207
4253
  Strict: false
4254
+ # You can specify allowed numbers. (e.g. port number 3000, 8080, and etc)
4255
+ AllowedNumbers: []
4208
4256
 
4209
4257
  Style/NumericPredicate:
4210
4258
  Description: >-
@@ -124,7 +124,7 @@ module RuboCop
124
124
  lines = /\S/.match?(rubocop_yml_contents) ? rubocop_yml_contents.split("\n", -1) : []
125
125
  doc_start_index = lines.index { |line| YAML_OPTIONAL_DOC_START.match?(line) } || -1
126
126
  lines.insert(doc_start_index + 1, "inherit_from:#{file_string}\n")
127
- File.open(file_name, 'w') { |f| f.write lines.join("\n") }
127
+ File.write(file_name, lines.join("\n"))
128
128
  end
129
129
  end
130
130
  end
@@ -31,7 +31,7 @@ module RuboCop
31
31
  # See https://docs.rubocop.org/rubocop/configuration
32
32
  DESC
33
33
 
34
- File.open(DOTFILE, 'w') { |f| f.write(description) }
34
+ File.write(DOTFILE, description)
35
35
 
36
36
  puts "Writing new #{DOTFILE} to #{path}"
37
37
 
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ class CLI
5
+ module Command
6
+ # Prints out url to documentation of provided cops
7
+ # or documentation base url by default.
8
+ # @api private
9
+ class ShowDocsUrl < Base
10
+ self.command_name = :show_docs_url
11
+
12
+ def initialize(env)
13
+ super
14
+
15
+ @config = @config_store.for(Dir.pwd)
16
+ end
17
+
18
+ def run
19
+ print_documentation_url
20
+ end
21
+
22
+ private
23
+
24
+ def print_documentation_url
25
+ puts Cop::Documentation.default_base_url if cops_array.empty?
26
+
27
+ cops_array.each do |cop_name|
28
+ cop = registry_hash[cop_name]
29
+
30
+ next if cop.empty?
31
+
32
+ puts Cop::Documentation.url_for(cop.first, @config)
33
+ end
34
+
35
+ puts
36
+ end
37
+
38
+ def cops_array
39
+ @cops_array ||= @options[:show_docs_url]
40
+ end
41
+
42
+ def registry_hash
43
+ @registry_hash ||= Cop::Registry.global.to_h
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -22,7 +22,7 @@ module RuboCop
22
22
  'RuboCop extension libraries might be helpful:'
23
23
 
24
24
  extensions.sort.each do |extension|
25
- puts " * #{extension} (https://github.com/rubocop/#{extension})"
25
+ puts " * #{extension} (https://rubygems.org/gems/#{extension})"
26
26
  end
27
27
 
28
28
  puts
data/lib/rubocop/cli.rb CHANGED
@@ -131,6 +131,7 @@ module RuboCop
131
131
 
132
132
  run_command(:version) if @options[:version] || @options[:verbose_version]
133
133
  run_command(:show_cops) if @options[:show_cops]
134
+ run_command(:show_docs_url) if @options[:show_docs_url]
134
135
  raise Finished
135
136
  end
136
137
 
@@ -74,7 +74,7 @@ module RuboCop
74
74
  # Merges the given configuration with the default one. If
75
75
  # AllCops:DisabledByDefault is true, it changes the Enabled params so that
76
76
  # only cops from user configuration are enabled. If
77
- # AllCops::EnabledByDefault is true, it changes the Enabled params so that
77
+ # AllCops:EnabledByDefault is true, it changes the Enabled params so that
78
78
  # only cops explicitly disabled in user configuration are disabled.
79
79
  def merge_with_default(config, config_file, unset_nil:)
80
80
  default_configuration = ConfigLoader.default_configuration
@@ -68,7 +68,7 @@ module RuboCop
68
68
  end
69
69
 
70
70
  def conditional_declaration?(nodes)
71
- parent = nodes[0].parent
71
+ parent = nodes[0].each_ancestor.find { |ancestor| !ancestor.begin_type? }
72
72
  return false unless parent&.if_type? || parent&.when_type?
73
73
 
74
74
  root_conditional_node = parent.if_type? ? parent : parent.parent
@@ -11,7 +11,7 @@ module RuboCop
11
11
 
12
12
  def initialize(block_node)
13
13
  @block_node = block_node
14
- @collection_node = block_node.send_node.receiver
14
+ @collection_node = block_node.receiver
15
15
  @argument_node = block_node.arguments
16
16
  end
17
17
 
@@ -0,0 +1,55 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This class auto-corrects `if...then` structures to a multiline `if` statement
6
+ class IfThenCorrector
7
+ DEFAULT_INDENTATION_WIDTH = 2
8
+
9
+ def initialize(if_node, indentation: nil)
10
+ @if_node = if_node
11
+ @indentation = indentation || DEFAULT_INDENTATION_WIDTH
12
+ end
13
+
14
+ def call(corrector)
15
+ corrector.replace(if_node, replacement)
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :if_node, :indentation
21
+
22
+ def replacement(node = if_node, indentation = nil)
23
+ indentation = ' ' * node.source_range.column if indentation.nil?
24
+ if_branch_source = node.if_branch&.source || 'nil'
25
+ elsif_indentation = indentation if node.respond_to?(:elsif?) && node.elsif?
26
+
27
+ if_branch = <<~RUBY
28
+ #{elsif_indentation}#{node.keyword} #{node.condition.source}
29
+ #{indentation}#{branch_body_indentation}#{if_branch_source}
30
+ RUBY
31
+
32
+ else_branch = rewrite_else_branch(node.else_branch, indentation)
33
+ if_branch + else_branch
34
+ end
35
+
36
+ def rewrite_else_branch(else_branch, indentation)
37
+ if else_branch.nil?
38
+ 'end'
39
+ elsif else_branch.if_type? && else_branch.elsif?
40
+ replacement(else_branch, indentation)
41
+ else
42
+ <<~RUBY.chomp
43
+ #{indentation}else
44
+ #{indentation}#{branch_body_indentation}#{else_branch.source}
45
+ #{indentation}end
46
+ RUBY
47
+ end
48
+ end
49
+
50
+ def branch_body_indentation
51
+ @branch_body_indentation ||= (' ' * indentation).freeze
52
+ end
53
+ end
54
+ end
55
+ end
@@ -12,10 +12,27 @@ module RuboCop
12
12
  end
13
13
 
14
14
  # @api private
15
- def url_for(cop_class)
15
+ def url_for(cop_class, config = nil)
16
16
  base = department_to_basename(cop_class.department)
17
17
  fragment = cop_class.cop_name.downcase.gsub(/[^a-z]/, '')
18
- "https://docs.rubocop.org/rubocop/#{base}.html##{fragment}"
18
+ base_url = base_url_for(cop_class, config)
19
+
20
+ "#{base_url}/#{base}.html##{fragment}"
21
+ end
22
+
23
+ # @api private
24
+ def base_url_for(cop_class, config)
25
+ return default_base_url unless config
26
+
27
+ department_name = cop_class.department.to_s
28
+
29
+ config.for_department(department_name)['DocumentationBaseURL'] ||
30
+ config.for_all_cops['DocumentationBaseURL']
31
+ end
32
+
33
+ # @api private
34
+ def default_base_url
35
+ 'https://docs.rubocop.org/rubocop'
19
36
  end
20
37
  end
21
38
  end
@@ -6,18 +6,18 @@ module RuboCop
6
6
  # Requires a gemspec to have `rubygems_mfa_required` metadata set.
7
7
  #
8
8
  # This setting tells RubyGems that MFA is required for accounts to
9
- # be able perform any of these privileged operations:
9
+ # be able perform privileged operations, such as (see
10
+ # RubyGems' documentation for the full list of privileged operations):
10
11
  #
11
- # * gem push
12
- # * gem yank
13
- # * gem owner --add/remove
12
+ # * `gem push`
13
+ # * `gem yank`
14
+ # * `gem owner --add/remove`
14
15
  # * adding or removing owners using gem ownership page
15
16
  #
16
17
  # This helps make your gem more secure, as users can be more
17
18
  # confident that gem updates were pushed by maintainers.
18
19
  #
19
20
  # @example
20
- #
21
21
  # # bad
22
22
  # Gem::Specification.new do |spec|
23
23
  # # no `rubygems_mfa_required` metadata specified
@@ -117,7 +117,7 @@ module RuboCop
117
117
 
118
118
  correct_metadata(corrector, metadata)
119
119
  else
120
- correct_missing_metadata(corrector, node, block_var)
120
+ insert_mfa_required(corrector, node, block_var)
121
121
  end
122
122
  end
123
123
 
@@ -129,11 +129,9 @@ module RuboCop
129
129
  end
130
130
  end
131
131
 
132
- def correct_missing_metadata(corrector, node, block_var)
132
+ def insert_mfa_required(corrector, node, block_var)
133
133
  corrector.insert_before(node.loc.end, <<~RUBY)
134
- #{block_var}.metadata = {
135
- 'rubygems_mfa_required' => 'true'
136
- }
134
+ #{block_var}.metadata['rubygems_mfa_required'] = 'true'
137
135
  RUBY
138
136
  end
139
137
 
@@ -68,8 +68,11 @@ module RuboCop
68
68
 
69
69
  # @!method defined_ruby_version(node)
70
70
  def_node_matcher :defined_ruby_version, <<~PATTERN
71
- {$(str _) $(array (str _) (str _))
72
- (send (const (const nil? :Gem) :Requirement) :new $(str _))}
71
+ {
72
+ $(str _)
73
+ $(array (str _) (str _))
74
+ (send (const (const nil? :Gem) :Requirement) :new $str+)
75
+ }
73
76
  PATTERN
74
77
 
75
78
  def on_new_investigation
@@ -97,7 +100,11 @@ module RuboCop
97
100
  def extract_ruby_version(required_ruby_version)
98
101
  return unless required_ruby_version
99
102
 
100
- if required_ruby_version.array_type?
103
+ if required_ruby_version.is_a?(Array)
104
+ required_ruby_version = required_ruby_version.detect do |v|
105
+ /[>=]/.match?(v.str_content)
106
+ end
107
+ elsif required_ruby_version.array_type?
101
108
  required_ruby_version = required_ruby_version.children.detect do |v|
102
109
  /[>=]/.match?(v.str_content)
103
110
  end
@@ -182,7 +182,8 @@ module RuboCop
182
182
  end
183
183
 
184
184
  def generate(template)
185
- format(template, department: badge.department, cop_name: badge.cop_name)
185
+ format(template, department: badge.department.to_s.gsub('/', '::'),
186
+ cop_name: badge.cop_name)
186
187
  end
187
188
 
188
189
  def spec_path
@@ -209,8 +210,8 @@ module RuboCop
209
210
  return 'rspec' if camel_case_string == 'RSpec'
210
211
 
211
212
  camel_case_string
212
- .gsub(/([^A-Z])([A-Z]+)/, '\1_\2')
213
- .gsub(/([A-Z])([A-Z][^A-Z\d]+)/, '\1_\2')
213
+ .gsub(%r{([^A-Z/])([A-Z]+)}, '\1_\2')
214
+ .gsub(%r{([A-Z])([A-Z][^A-Z\d/]+)}, '\1_\2')
214
215
  .downcase
215
216
  end
216
217
  end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module InternalAffairs
6
+ # Checks for redundant `send_node` method dispatch node.
7
+ #
8
+ # @example
9
+ #
10
+ # # bad
11
+ # node.send_node.method_name
12
+ #
13
+ # # good
14
+ # node.method_name
15
+ #
16
+ # # bad
17
+ # node.send_node.receiver
18
+ #
19
+ # # good
20
+ # node.receiver
21
+ #
22
+ class RedundantMethodDispatchNode < Base
23
+ include RangeHelp
24
+ extend AutoCorrector
25
+
26
+ MSG = 'Remove the redundant `send_node`.'
27
+ RESTRICT_ON_SEND = %i[method_name receiver].freeze
28
+
29
+ # @!method dispatch_method(node)
30
+ def_node_matcher :dispatch_method, <<~PATTERN
31
+ (send $(send _ :send_node) _)
32
+ PATTERN
33
+
34
+ def on_send(node)
35
+ return unless (dispatch_node = dispatch_method(node))
36
+ return unless (dot = dispatch_node.loc.dot)
37
+
38
+ range = range_between(dot.begin_pos, dispatch_node.loc.selector.end_pos)
39
+
40
+ add_offense(range) do |corrector|
41
+ corrector.remove(range)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -14,7 +14,9 @@ module RuboCop
14
14
 
15
15
  # @!method cop_class_def(node)
16
16
  def_node_search :cop_class_def, <<~PATTERN
17
- (class _ (const _ {:Base :Cop}) ...)
17
+ (class _
18
+ (const {nil? (const nil? :Cop) (const (const {cbase nil?} :RuboCop) :Cop)}
19
+ {:Base :Cop}) ...)
18
20
  PATTERN
19
21
 
20
22
  # @!method cop_config_accessor?(node)
@@ -13,6 +13,7 @@ require_relative 'internal_affairs/redundant_described_class_as_subject'
13
13
  require_relative 'internal_affairs/redundant_let_rubocop_config_new'
14
14
  require_relative 'internal_affairs/redundant_location_argument'
15
15
  require_relative 'internal_affairs/redundant_message_argument'
16
+ require_relative 'internal_affairs/redundant_method_dispatch_node'
16
17
  require_relative 'internal_affairs/style_detected_api_use'
17
18
  require_relative 'internal_affairs/undefined_config'
18
19
  require_relative 'internal_affairs/useless_message_assertion'
@@ -53,23 +53,50 @@ module RuboCop
53
53
  'following the first line of a multi-line method call.'
54
54
 
55
55
  def on_send(node)
56
- first_arg = node.first_argument
57
- return if !multiple_arguments?(node, first_arg) || (node.send_type? && node.method?(:[]=))
56
+ return if !multiple_arguments?(node) || (node.send_type? && node.method?(:[]=))
58
57
 
59
- if first_arg.hash_type? && !first_arg.braces?
60
- pairs = first_arg.pairs
61
- check_alignment(pairs, base_column(node, pairs.first))
62
- else
63
- check_alignment(node.arguments, base_column(node, first_arg))
64
- end
58
+ items = flattened_arguments(node)
59
+
60
+ check_alignment(items, base_column(node, items.first))
65
61
  end
62
+
66
63
  alias on_csend on_send
67
64
 
68
65
  private
69
66
 
70
- def multiple_arguments?(node, first_argument)
67
+ def flattened_arguments(node)
68
+ if fixed_indentation?
69
+ arguments_with_last_arg_pairs(node)
70
+ else
71
+ arguments_or_first_arg_pairs(node)
72
+ end
73
+ end
74
+
75
+ def arguments_with_last_arg_pairs(node)
76
+ items = node.arguments[0..-2]
77
+ last_arg = node.arguments.last
78
+
79
+ if last_arg.hash_type? && !last_arg.braces?
80
+ items += last_arg.pairs
81
+ else
82
+ items << last_arg
83
+ end
84
+ items
85
+ end
86
+
87
+ def arguments_or_first_arg_pairs(node)
88
+ first_arg = node.first_argument
89
+ if first_arg.hash_type? && !first_arg.braces?
90
+ first_arg.pairs
91
+ else
92
+ node.arguments
93
+ end
94
+ end
95
+
96
+ def multiple_arguments?(node)
71
97
  return true if node.arguments.size >= 2
72
98
 
99
+ first_argument = node.first_argument
73
100
  first_argument&.hash_type? && first_argument.pairs.count >= 2
74
101
  end
75
102