rubocop 1.22.1 → 1.24.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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/default.yml +88 -8
  4. data/lib/rubocop/cli/command/auto_genenerate_config.rb +1 -1
  5. data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
  6. data/lib/rubocop/cli/command/show_docs_url.rb +48 -0
  7. data/lib/rubocop/cli/command/suggest_extensions.rb +1 -1
  8. data/lib/rubocop/cli.rb +1 -0
  9. data/lib/rubocop/config_loader_resolver.rb +1 -1
  10. data/lib/rubocop/cop/bundler/duplicated_gem.rb +1 -1
  11. data/lib/rubocop/cop/bundler/gem_comment.rb +3 -3
  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/date_assignment.rb +2 -10
  16. data/lib/rubocop/cop/gemspec/duplicated_assignment.rb +1 -10
  17. data/lib/rubocop/cop/gemspec/require_mfa.rb +146 -0
  18. data/lib/rubocop/cop/gemspec/required_ruby_version.rb +30 -23
  19. data/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb +3 -10
  20. data/lib/rubocop/cop/generator.rb +1 -1
  21. data/lib/rubocop/cop/internal_affairs/location_line_equality_comparison.rb +60 -0
  22. data/lib/rubocop/cop/internal_affairs/redundant_method_dispatch_node.rb +46 -0
  23. data/lib/rubocop/cop/internal_affairs/undefined_config.rb +3 -1
  24. data/lib/rubocop/cop/internal_affairs.rb +2 -0
  25. data/lib/rubocop/cop/layout/assignment_indentation.rb +1 -1
  26. data/lib/rubocop/cop/layout/block_alignment.rb +3 -3
  27. data/lib/rubocop/cop/layout/comment_indentation.rb +31 -2
  28. data/lib/rubocop/cop/layout/dot_position.rb +13 -7
  29. data/lib/rubocop/cop/layout/empty_comment.rb +1 -1
  30. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +22 -1
  31. data/lib/rubocop/cop/layout/empty_lines_around_exception_handling_keywords.rb +7 -4
  32. data/lib/rubocop/cop/layout/end_alignment.rb +1 -2
  33. data/lib/rubocop/cop/layout/first_array_element_indentation.rb +1 -1
  34. data/lib/rubocop/cop/layout/first_hash_element_indentation.rb +1 -1
  35. data/lib/rubocop/cop/layout/first_parameter_indentation.rb +1 -1
  36. data/lib/rubocop/cop/layout/hash_alignment.rb +2 -2
  37. data/lib/rubocop/cop/layout/heredoc_argument_closing_parenthesis.rb +1 -1
  38. data/lib/rubocop/cop/layout/indentation_width.rb +1 -1
  39. data/lib/rubocop/cop/layout/line_length.rb +1 -1
  40. data/lib/rubocop/cop/layout/multiline_assignment_layout.rb +1 -1
  41. data/lib/rubocop/cop/layout/multiline_block_layout.rb +2 -2
  42. data/lib/rubocop/cop/layout/multiline_method_call_indentation.rb +1 -1
  43. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +1 -1
  44. data/lib/rubocop/cop/layout/space_after_colon.rb +1 -1
  45. data/lib/rubocop/cop/layout/space_before_comment.rb +1 -1
  46. data/lib/rubocop/cop/layout/space_before_first_arg.rb +4 -0
  47. data/lib/rubocop/cop/layout/space_in_lambda_literal.rb +11 -5
  48. data/lib/rubocop/cop/layout/space_inside_parens.rb +0 -4
  49. data/lib/rubocop/cop/lint/ambiguous_range.rb +3 -3
  50. data/lib/rubocop/cop/lint/constant_definition_in_block.rb +1 -1
  51. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +16 -4
  52. data/lib/rubocop/cop/lint/deprecated_constants.rb +3 -2
  53. data/lib/rubocop/cop/lint/deprecated_open_ssl_constant.rb +6 -0
  54. data/lib/rubocop/cop/lint/else_layout.rb +1 -1
  55. data/lib/rubocop/cop/lint/incompatible_io_select_with_fiber_scheduler.rb +4 -0
  56. data/lib/rubocop/cop/lint/number_conversion.rb +5 -2
  57. data/lib/rubocop/cop/lint/useless_ruby2_keywords.rb +117 -0
  58. data/lib/rubocop/cop/metrics/block_length.rb +1 -0
  59. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +0 -9
  60. data/lib/rubocop/cop/metrics/method_length.rb +1 -0
  61. data/lib/rubocop/cop/metrics/module_length.rb +1 -1
  62. data/lib/rubocop/cop/metrics/parameter_lists.rb +5 -2
  63. data/lib/rubocop/cop/metrics/utils/code_length_calculator.rb +1 -1
  64. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +1 -2
  65. data/lib/rubocop/cop/mixin/enforce_superclass.rb +5 -0
  66. data/lib/rubocop/cop/mixin/gemspec_help.rb +30 -0
  67. data/lib/rubocop/cop/mixin/hash_alignment_styles.rb +4 -3
  68. data/lib/rubocop/cop/mixin/hash_shorthand_syntax.rb +56 -0
  69. data/lib/rubocop/cop/mixin/hash_transform_method.rb +3 -3
  70. data/lib/rubocop/cop/mixin/multiline_element_indentation.rb +1 -1
  71. data/lib/rubocop/cop/mixin/multiline_literal_brace_layout.rb +1 -1
  72. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +1 -1
  73. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +1 -1
  74. data/lib/rubocop/cop/mixin/statement_modifier.rb +1 -1
  75. data/lib/rubocop/cop/mixin/string_literals_help.rb +1 -5
  76. data/lib/rubocop/cop/mixin/trailing_body.rb +1 -1
  77. data/lib/rubocop/cop/naming/block_forwarding.rb +102 -0
  78. data/lib/rubocop/cop/naming/file_name.rb +37 -4
  79. data/lib/rubocop/cop/security/json_load.rb +1 -1
  80. data/lib/rubocop/cop/security/open.rb +11 -1
  81. data/lib/rubocop/cop/style/character_literal.rb +8 -1
  82. data/lib/rubocop/cop/style/collection_compact.rb +31 -13
  83. data/lib/rubocop/cop/style/combinable_loops.rb +2 -2
  84. data/lib/rubocop/cop/style/commented_keyword.rb +5 -3
  85. data/lib/rubocop/cop/style/documentation.rb +1 -1
  86. data/lib/rubocop/cop/style/empty_case_condition.rb +10 -0
  87. data/lib/rubocop/cop/style/empty_method.rb +1 -1
  88. data/lib/rubocop/cop/style/file_read.rb +112 -0
  89. data/lib/rubocop/cop/style/file_write.rb +98 -0
  90. data/lib/rubocop/cop/style/format_string_token.rb +2 -1
  91. data/lib/rubocop/cop/style/hash_conversion.rb +2 -1
  92. data/lib/rubocop/cop/style/hash_syntax.rb +22 -0
  93. data/lib/rubocop/cop/style/if_inside_else.rb +15 -0
  94. data/lib/rubocop/cop/style/line_end_concatenation.rb +1 -1
  95. data/lib/rubocop/cop/style/map_to_hash.rb +68 -0
  96. data/lib/rubocop/cop/style/multiline_in_pattern_then.rb +1 -1
  97. data/lib/rubocop/cop/style/multiline_when_then.rb +1 -1
  98. data/lib/rubocop/cop/style/numeric_literals.rb +10 -1
  99. data/lib/rubocop/cop/style/one_line_conditional.rb +18 -39
  100. data/lib/rubocop/cop/style/open_struct_use.rb +69 -0
  101. data/lib/rubocop/cop/style/parentheses_around_condition.rb +12 -2
  102. data/lib/rubocop/cop/style/quoted_symbols.rb +11 -1
  103. data/lib/rubocop/cop/style/redundant_interpolation.rb +17 -3
  104. data/lib/rubocop/cop/style/redundant_regexp_character_class.rb +5 -1
  105. data/lib/rubocop/cop/style/redundant_self.rb +1 -1
  106. data/lib/rubocop/cop/style/safe_navigation.rb +1 -5
  107. data/lib/rubocop/cop/style/select_by_regexp.rb +9 -3
  108. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -2
  109. data/lib/rubocop/cop/style/sole_nested_conditional.rb +3 -1
  110. data/lib/rubocop/cop/team.rb +1 -1
  111. data/lib/rubocop/cop/util.rb +11 -1
  112. data/lib/rubocop/formatter/html_formatter.rb +5 -2
  113. data/lib/rubocop/formatter/json_formatter.rb +4 -1
  114. data/lib/rubocop/options.rb +6 -1
  115. data/lib/rubocop/remote_config.rb +2 -4
  116. data/lib/rubocop/result_cache.rb +1 -1
  117. data/lib/rubocop/rspec/parallel_formatter.rb +90 -0
  118. data/lib/rubocop/rspec/support.rb +1 -0
  119. data/lib/rubocop/target_finder.rb +1 -1
  120. data/lib/rubocop/version.rb +1 -1
  121. data/lib/rubocop/yaml_duplication_checker.rb +1 -1
  122. data/lib/rubocop.rb +11 -0
  123. metadata +24 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fc48ec8bad4f5af1a464cb2d8d512975a10efd1d9c73e74ce024f798a4b200cc
4
- data.tar.gz: 65ed09a920ce2211ab2d29a26780d1b198c08d29b3af92ef783c46024e056607
3
+ metadata.gz: 3080860c5102e2d42274c71316c7d9910e6e26019c9f39005e38fba136657c8e
4
+ data.tar.gz: 879fa716afcb1051f05f0ebc6832291cfb06655763e1aaac752cf6997096bcf2
5
5
  SHA512:
6
- metadata.gz: 9fff6f773ae50140975bfac3f671f1657cd7da4c1df10623a7e36096e21032630fa8c41eb5a5d4eb8f07b92a48e7d99fc2b40d20da5811fc4bb0060dfc410e3b
7
- data.tar.gz: 0aa4fa740168feb2643edbeecedc723c3da44c0f2c4843a39b9593c7dda07db21d05552ae52731b1b1ddbeeb2ffe0816d2c5e7d0423caec2dc40888cbd52758f
6
+ metadata.gz: 21bd87b421b7cae8c95a44cdfc9ef85e4b4259fc08bfd53b37f02f16d9808ef487d1ec385a4e5047fed1d3358cf185f8bc2ca2bfa504eeedd05c47d4ea9cb411
7
+ data.tar.gz: 933d030bae14fbaf659e21901ab49db9418dcb8afcaff33b68d765c9fa47576f6c957fe1b0771f23a3faa94c100353f739298d85b68c8a96e65b6b15c1a8f60e
data/README.md CHANGED
@@ -54,7 +54,7 @@ To prevent an unwanted RuboCop update you might want to use a conservative versi
54
54
  in your `Gemfile`:
55
55
 
56
56
  ```rb
57
- gem 'rubocop', '~> 1.22', require: false
57
+ gem 'rubocop', '~> 1.24', require: false
58
58
  ```
59
59
 
60
60
  See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for 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.
@@ -150,6 +152,7 @@ AllCops:
150
152
  rubocop-minitest: [minitest]
151
153
  rubocop-sequel: [sequel]
152
154
  rubocop-rake: [rake]
155
+ rubocop-graphql: [graphql]
153
156
 
154
157
  #################### Bundler ###############################
155
158
 
@@ -258,11 +261,20 @@ Gemspec/OrderedDependencies:
258
261
  Include:
259
262
  - '**/*.gemspec'
260
263
 
264
+ Gemspec/RequireMFA:
265
+ Description: 'Checks that the gemspec has metadata to require MFA from RubyGems.'
266
+ Enabled: pending
267
+ VersionAdded: '1.23'
268
+ Reference:
269
+ - https://guides.rubygems.org/mfa-requirement-opt-in/
270
+ Include:
271
+ - '**/*.gemspec'
272
+
261
273
  Gemspec/RequiredRubyVersion:
262
274
  Description: 'Checks that `required_ruby_version` of gemspec is specified and equal to `TargetRubyVersion` of .rubocop.yml.'
263
275
  Enabled: true
264
276
  VersionAdded: '0.52'
265
- VersionChanged: '0.89'
277
+ VersionChanged: '1.22'
266
278
  Include:
267
279
  - '**/*.gemspec'
268
280
 
@@ -439,7 +451,11 @@ Layout/ClosingParenthesisIndentation:
439
451
  Layout/CommentIndentation:
440
452
  Description: 'Indentation of comments.'
441
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
442
457
  VersionAdded: '0.49'
458
+ VersionChanged: '1.24'
443
459
 
444
460
  Layout/ConditionPosition:
445
461
  Description: >-
@@ -511,13 +527,13 @@ Layout/EmptyLineBetweenDefs:
511
527
  StyleGuide: '#empty-lines-between-methods'
512
528
  Enabled: true
513
529
  VersionAdded: '0.49'
514
- VersionChanged: '1.7'
530
+ VersionChanged: '1.23'
515
531
  EmptyLineBetweenMethodDefs: true
516
532
  EmptyLineBetweenClassDefs: true
517
533
  EmptyLineBetweenModuleDefs: true
518
- # If `true`, this parameter means that single line method definitions don't
519
- # need an empty line between them.
520
- AllowAdjacentOneLineDefs: false
534
+ # `AllowAdjacentOneLineDefs` means that single line method definitions don't
535
+ # need an empty line between them. `true` by default.
536
+ AllowAdjacentOneLineDefs: true
521
537
  # Can be array to specify minimum and maximum number of empty lines, e.g. [1, 2]
522
538
  NumberOfEmptyLines: 1
523
539
 
@@ -1568,6 +1584,7 @@ Lint/DeprecatedConstants:
1568
1584
  Description: 'Checks for deprecated constants.'
1569
1585
  Enabled: pending
1570
1586
  VersionAdded: '1.8'
1587
+ VersionChanged: '1.22'
1571
1588
  # You can configure deprecated constants.
1572
1589
  # If there is an alternative method, you can set alternative value as `Alternative`.
1573
1590
  # And you can set the deprecated version as `DeprecatedVersion`.
@@ -1588,6 +1605,9 @@ Lint/DeprecatedConstants:
1588
1605
  'FALSE':
1589
1606
  Alternative: 'false'
1590
1607
  DeprecatedVersion: '2.4'
1608
+ 'Net::HTTPServerException':
1609
+ Alternative: 'Net::HTTPClientException'
1610
+ DeprecatedVersion: '2.6'
1591
1611
  'Random::DEFAULT':
1592
1612
  Alternative: 'Random.new'
1593
1613
  DeprecatedVersion: '3.0'
@@ -1782,7 +1802,9 @@ Lint/ImplicitStringConcatenation:
1782
1802
  Lint/IncompatibleIoSelectWithFiberScheduler:
1783
1803
  Description: 'Checks for `IO.select` that is incompatible with Fiber Scheduler.'
1784
1804
  Enabled: pending
1805
+ SafeAutoCorrect: false
1785
1806
  VersionAdded: '1.21'
1807
+ VersionChanged: '1.24'
1786
1808
 
1787
1809
  Lint/IneffectiveAccessModifier:
1788
1810
  Description: >-
@@ -2304,6 +2326,11 @@ Lint/UselessMethodDefinition:
2304
2326
  Safe: false
2305
2327
  AllowComments: true
2306
2328
 
2329
+ Lint/UselessRuby2Keywords:
2330
+ Description: 'Finds unnecessary uses of `ruby2_keywords`.'
2331
+ Enabled: pending
2332
+ VersionAdded: '1.23'
2333
+
2307
2334
  Lint/UselessSetterCall:
2308
2335
  Description: 'Checks for useless setter call to a local variable.'
2309
2336
  Enabled: true
@@ -2460,6 +2487,15 @@ Naming/BinaryOperatorParameterName:
2460
2487
  VersionAdded: '0.50'
2461
2488
  VersionChanged: '1.2'
2462
2489
 
2490
+ Naming/BlockForwarding:
2491
+ Description: 'Use anonymous block forwarding.'
2492
+ Enabled: pending
2493
+ VersionAdded: '1.24'
2494
+ EnforcedStyle: anonymous
2495
+ SupportedStyles:
2496
+ - anonymous
2497
+ - explicit
2498
+
2463
2499
  Naming/BlockParameterName:
2464
2500
  Description: >-
2465
2501
  Checks for block parameter names that contain capital letters,
@@ -2497,6 +2533,7 @@ Naming/FileName:
2497
2533
  StyleGuide: '#snake-case-files'
2498
2534
  Enabled: true
2499
2535
  VersionAdded: '0.50'
2536
+ VersionChanged: '1.23'
2500
2537
  # Camel case file names listed in `AllCops:Include` and all file names listed
2501
2538
  # in `AllCops:Exclude` are excluded by default. Add extra excludes here.
2502
2539
  Exclude: []
@@ -2509,6 +2546,13 @@ Naming/FileName:
2509
2546
  # whether each source file's class or module name matches the file name --
2510
2547
  # not whether the nested module hierarchy matches the subdirectory path.
2511
2548
  CheckDefinitionPathHierarchy: true
2549
+ # paths that are considered root directories, for example "lib" in most ruby projects
2550
+ # or "app/models" in rails projects
2551
+ CheckDefinitionPathHierarchyRoots:
2552
+ - lib
2553
+ - spec
2554
+ - test
2555
+ - src
2512
2556
  # If non-`nil`, expect all source file names to match the following regex.
2513
2557
  # Only the file name itself is matched, not the entire file path.
2514
2558
  # Use anchors as necessary if you want to match the entire name rather than
@@ -2754,10 +2798,9 @@ Security/JSONLoad:
2754
2798
  Reference: 'https://ruby-doc.org/stdlib-2.7.0/libdoc/json/rdoc/JSON.html#method-i-load'
2755
2799
  Enabled: true
2756
2800
  VersionAdded: '0.43'
2757
- VersionChanged: '0.44'
2801
+ VersionChanged: '1.22'
2758
2802
  # Autocorrect here will change to a method that may cause crashes depending
2759
2803
  # on the value of the argument.
2760
- AutoCorrect: false
2761
2804
  SafeAutoCorrect: false
2762
2805
 
2763
2806
  Security/MarshalLoad:
@@ -3466,6 +3509,18 @@ Style/ExponentialNotation:
3466
3509
  - engineering
3467
3510
  - integral
3468
3511
 
3512
+ Style/FileRead:
3513
+ Description: 'Favor `File.(bin)read` convenience methods.'
3514
+ StyleGuide: '#file-read'
3515
+ Enabled: pending
3516
+ VersionAdded: '1.24'
3517
+
3518
+ Style/FileWrite:
3519
+ Description: 'Favor `File.(bin)write` convenience methods.'
3520
+ StyleGuide: '#file-write'
3521
+ Enabled: pending
3522
+ VersionAdded: '1.24'
3523
+
3469
3524
  Style/FloatDivision:
3470
3525
  Description: 'For performing float division, coerce one side only.'
3471
3526
  StyleGuide: '#float-division'
@@ -3624,7 +3679,7 @@ Style/HashSyntax:
3624
3679
  StyleGuide: '#hash-literals'
3625
3680
  Enabled: true
3626
3681
  VersionAdded: '0.9'
3627
- VersionChanged: '0.43'
3682
+ VersionChanged: '1.24'
3628
3683
  EnforcedStyle: ruby19
3629
3684
  SupportedStyles:
3630
3685
  # checks for 1.9 syntax (e.g. {a: 1}) for all symbol keys
@@ -3635,6 +3690,13 @@ Style/HashSyntax:
3635
3690
  - no_mixed_keys
3636
3691
  # enforces both ruby19 and no_mixed_keys styles
3637
3692
  - ruby19_no_mixed_keys
3693
+ # Force hashes that have a hash value omission
3694
+ EnforcedShorthandSyntax: always
3695
+ SupportedShorthandSyntax:
3696
+ # forces use of the 3.1 syntax (e.g. {foo:}) when the hash key and value are the same.
3697
+ - always
3698
+ # forces use of explicit hash literal value.
3699
+ - never
3638
3700
  # Force hashes that have a symbol value to use hash rockets
3639
3701
  UseHashRocketsWithSymbolValues: false
3640
3702
  # Do not suggest { a?: 1 } over { :a? => 1 } in ruby19 style
@@ -3811,6 +3873,12 @@ Style/LineEndConcatenation:
3811
3873
  VersionAdded: '0.18'
3812
3874
  VersionChanged: '0.64'
3813
3875
 
3876
+ Style/MapToHash:
3877
+ Description: 'Prefer `to_h` with a block over `map.to_h`.'
3878
+ Enabled: pending
3879
+ VersionAdded: '1.24'
3880
+ Safe: false
3881
+
3814
3882
  Style/MethodCallWithArgsParentheses:
3815
3883
  Description: 'Use parentheses for method calls with arguments.'
3816
3884
  StyleGuide: '#method-invocation-parens'
@@ -4179,6 +4247,8 @@ Style/NumericLiterals:
4179
4247
  VersionChanged: '0.48'
4180
4248
  MinDigits: 5
4181
4249
  Strict: false
4250
+ # You can specify allowed numbers. (e.g. port number 3000, 8080, and etc)
4251
+ AllowedNumbers: []
4182
4252
 
4183
4253
  Style/NumericPredicate:
4184
4254
  Description: >-
@@ -4213,6 +4283,16 @@ Style/OneLineConditional:
4213
4283
  VersionAdded: '0.9'
4214
4284
  VersionChanged: '0.90'
4215
4285
 
4286
+ Style/OpenStructUse:
4287
+ Description: >-
4288
+ Avoid using OpenStruct. As of Ruby 3.0, use is officially discouraged due to performance,
4289
+ version compatibility, and potential security issues.
4290
+ Reference:
4291
+ - https://docs.ruby-lang.org/en/3.0.0/OpenStruct.html#class-OpenStruct-label-Caveats
4292
+
4293
+ Enabled: pending
4294
+ VersionAdded: '1.23'
4295
+
4216
4296
  Style/OptionHash:
4217
4297
  Description: "Don't use option hashes when you can use keyword arguments."
4218
4298
  Enabled: false
@@ -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
@@ -88,7 +88,7 @@ module RuboCop
88
88
  CHECKED_OPTIONS_CONFIG = 'OnlyFor'
89
89
  VERSION_SPECIFIERS_OPTION = 'version_specifiers'
90
90
  RESTRICTIVE_VERSION_SPECIFIERS_OPTION = 'restrictive_version_specifiers'
91
- RESTRICTIVE_VERSION_PATTERN = /<|~>/.freeze
91
+ RESTRICTIVE_VERSION_PATTERN = /\A\s*(?:<|~>|\d|=)/.freeze
92
92
  RESTRICT_ON_SEND = %i[gem].freeze
93
93
 
94
94
  def on_send(node)
@@ -152,8 +152,8 @@ module RuboCop
152
152
  def restrictive_version_specified_gem?(node)
153
153
  return unless version_specified_gem?(node)
154
154
 
155
- node.arguments
156
- .any? { |arg| arg&.str_type? && RESTRICTIVE_VERSION_PATTERN.match?(arg.to_s) }
155
+ node.arguments[1..-1]
156
+ .any? { |arg| arg&.str_type? && RESTRICTIVE_VERSION_PATTERN.match?(arg.value) }
157
157
  end
158
158
 
159
159
  def contains_checked_options?(node)
@@ -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
@@ -21,21 +21,13 @@ module RuboCop
21
21
  #
22
22
  class DateAssignment < Base
23
23
  include RangeHelp
24
+ include GemspecHelp
24
25
  extend AutoCorrector
25
26
 
26
27
  MSG = 'Do not use `date =` in gemspec, it is set automatically when the gem is packaged.'
27
28
 
28
- # @!method gem_specification(node)
29
- def_node_matcher :gem_specification, <<~PATTERN
30
- (block
31
- (send
32
- (const
33
- (const {cbase nil?} :Gem) :Specification) :new)
34
- ...)
35
- PATTERN
36
-
37
29
  def on_block(block_node)
38
- return unless gem_specification(block_node)
30
+ return unless gem_specification?(block_node)
39
31
 
40
32
  block_parameter = block_node.arguments.first.source
41
33
 
@@ -36,20 +36,11 @@ module RuboCop
36
36
  # end
37
37
  class DuplicatedAssignment < Base
38
38
  include RangeHelp
39
+ include GemspecHelp
39
40
 
40
41
  MSG = '`%<assignment>s` method calls already given on line '\
41
42
  '%<line_of_first_occurrence>d of the gemspec.'
42
43
 
43
- # @!method gem_specification(node)
44
- def_node_search :gem_specification, <<~PATTERN
45
- (block
46
- (send
47
- (const
48
- (const {cbase nil?} :Gem) :Specification) :new)
49
- (args
50
- (arg $_)) ...)
51
- PATTERN
52
-
53
44
  # @!method assignment_method_declarations(node)
54
45
  def_node_search :assignment_method_declarations, <<~PATTERN
55
46
  (send
@@ -0,0 +1,146 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Gemspec
6
+ # Requires a gemspec to have `rubygems_mfa_required` metadata set.
7
+ #
8
+ # This setting tells RubyGems that MFA is required for accounts to
9
+ # be able perform privileged operations, such as (see
10
+ # RubyGems' documentation for the full list of privileged operations):
11
+ #
12
+ # * `gem push`
13
+ # * `gem yank`
14
+ # * `gem owner --add/remove`
15
+ # * adding or removing owners using gem ownership page
16
+ #
17
+ # This helps make your gem more secure, as users can be more
18
+ # confident that gem updates were pushed by maintainers.
19
+ #
20
+ # @example
21
+ # # bad
22
+ # Gem::Specification.new do |spec|
23
+ # # no `rubygems_mfa_required` metadata specified
24
+ # end
25
+ #
26
+ # # good
27
+ # Gem::Specification.new do |spec|
28
+ # spec.metadata = {
29
+ # 'rubygems_mfa_required' => 'true'
30
+ # }
31
+ # end
32
+ #
33
+ # # good
34
+ # Gem::Specification.new do |spec|
35
+ # spec.metadata['rubygems_mfa_required'] = 'true'
36
+ # end
37
+ #
38
+ # # bad
39
+ # Gem::Specification.new do |spec|
40
+ # spec.metadata = {
41
+ # 'rubygems_mfa_required' => 'false'
42
+ # }
43
+ # end
44
+ #
45
+ # # good
46
+ # Gem::Specification.new do |spec|
47
+ # spec.metadata = {
48
+ # 'rubygems_mfa_required' => 'true'
49
+ # }
50
+ # end
51
+ #
52
+ # # bad
53
+ # Gem::Specification.new do |spec|
54
+ # spec.metadata['rubygems_mfa_required'] = 'false'
55
+ # end
56
+ #
57
+ # # good
58
+ # Gem::Specification.new do |spec|
59
+ # spec.metadata['rubygems_mfa_required'] = 'true'
60
+ # end
61
+ #
62
+ class RequireMFA < Base
63
+ include GemspecHelp
64
+ extend AutoCorrector
65
+
66
+ MSG = "`metadata['rubygems_mfa_required']` must be set to `'true'`."
67
+
68
+ # @!method metadata(node)
69
+ def_node_matcher :metadata, <<~PATTERN
70
+ `{
71
+ (send _ :metadata= $_)
72
+ (send (send _ :metadata) :[]= (str "rubygems_mfa_required") $_)
73
+ }
74
+ PATTERN
75
+
76
+ # @!method rubygems_mfa_required(node)
77
+ def_node_search :rubygems_mfa_required, <<~PATTERN
78
+ (pair (str "rubygems_mfa_required") $_)
79
+ PATTERN
80
+
81
+ # @!method true_string?(node)
82
+ def_node_matcher :true_string?, <<~PATTERN
83
+ (str "true")
84
+ PATTERN
85
+
86
+ def on_block(node) # rubocop:disable Metrics/MethodLength
87
+ gem_specification(node) do |block_var|
88
+ metadata_value = metadata(node)
89
+ mfa_value = mfa_value(metadata_value)
90
+
91
+ if mfa_value
92
+ unless true_string?(mfa_value)
93
+ add_offense(mfa_value) do |corrector|
94
+ change_value(corrector, mfa_value)
95
+ end
96
+ end
97
+ else
98
+ add_offense(node) do |corrector|
99
+ autocorrect(corrector, node, block_var, metadata_value)
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ private
106
+
107
+ def mfa_value(metadata_value)
108
+ return unless metadata_value
109
+ return metadata_value if metadata_value.str_type?
110
+
111
+ rubygems_mfa_required(metadata_value).first
112
+ end
113
+
114
+ def autocorrect(corrector, node, block_var, metadata)
115
+ if metadata
116
+ return unless metadata.hash_type?
117
+
118
+ correct_metadata(corrector, metadata)
119
+ else
120
+ correct_missing_metadata(corrector, node, block_var)
121
+ end
122
+ end
123
+
124
+ def correct_metadata(corrector, metadata)
125
+ if metadata.pairs.any?
126
+ corrector.insert_after(metadata.pairs.last, ",\n'rubygems_mfa_required' => 'true'")
127
+ else
128
+ corrector.insert_before(metadata.loc.end, "'rubygems_mfa_required' => 'true'")
129
+ end
130
+ end
131
+
132
+ def correct_missing_metadata(corrector, node, block_var)
133
+ corrector.insert_before(node.loc.end, <<~RUBY)
134
+ #{block_var}.metadata = {
135
+ 'rubygems_mfa_required' => 'true'
136
+ }
137
+ RUBY
138
+ end
139
+
140
+ def change_value(corrector, value)
141
+ corrector.replace(value, "'true'")
142
+ end
143
+ end
144
+ end
145
+ end
146
+ end