rubocop 1.22.1 → 1.24.0

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