rubocop 1.32.0 → 1.33.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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/config/default.yml +45 -16
- data/config/obsoletion.yml +23 -1
- data/lib/rubocop/cache_config.rb +29 -0
- data/lib/rubocop/cli/command/auto_genenerate_config.rb +2 -2
- data/lib/rubocop/cli/command/init_dotfile.rb +1 -1
- data/lib/rubocop/config_finder.rb +68 -0
- data/lib/rubocop/config_loader.rb +5 -45
- data/lib/rubocop/config_obsoletion/changed_parameter.rb +5 -0
- data/lib/rubocop/config_obsoletion/parameter_rule.rb +4 -0
- data/lib/rubocop/config_obsoletion.rb +7 -2
- data/lib/rubocop/cop/layout/block_end_newline.rb +32 -5
- data/lib/rubocop/cop/layout/first_argument_indentation.rb +6 -1
- data/lib/rubocop/cop/lint/ambiguous_block_association.rb +21 -8
- data/lib/rubocop/cop/lint/debugger.rb +11 -1
- data/lib/rubocop/cop/lint/empty_conditional_body.rb +60 -1
- data/lib/rubocop/cop/lint/number_conversion.rb +24 -8
- data/lib/rubocop/cop/metrics/abc_size.rb +3 -1
- data/lib/rubocop/cop/metrics/block_length.rb +6 -7
- data/lib/rubocop/cop/metrics/method_length.rb +8 -8
- data/lib/rubocop/cop/mixin/allowed_methods.rb +15 -1
- data/lib/rubocop/cop/mixin/allowed_pattern.rb +9 -1
- data/lib/rubocop/cop/mixin/comments_help.rb +5 -1
- data/lib/rubocop/cop/mixin/method_complexity.rb +4 -9
- data/lib/rubocop/cop/naming/predicate_name.rb +24 -3
- data/lib/rubocop/cop/style/block_delimiters.rb +26 -7
- data/lib/rubocop/cop/style/class_and_module_children.rb +4 -4
- data/lib/rubocop/cop/style/class_equality_comparison.rb +32 -7
- data/lib/rubocop/cop/style/empty_heredoc.rb +15 -1
- data/lib/rubocop/cop/style/format_string_token.rb +21 -8
- data/lib/rubocop/cop/style/hash_except.rb +0 -4
- data/lib/rubocop/cop/style/method_call_with_args_parentheses/require_parentheses.rb +5 -1
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +7 -7
- data/lib/rubocop/cop/style/method_call_without_args_parentheses.rb +11 -6
- data/lib/rubocop/cop/style/numeric_predicate.rb +28 -8
- data/lib/rubocop/cop/style/redundant_condition.rb +19 -4
- data/lib/rubocop/cop/style/redundant_sort.rb +21 -6
- data/lib/rubocop/cop/style/symbol_proc.rb +29 -9
- data/lib/rubocop/result_cache.rb +22 -20
- data/lib/rubocop/server/cache.rb +33 -1
- data/lib/rubocop/server/cli.rb +19 -2
- data/lib/rubocop/version.rb +1 -1
- data/lib/rubocop.rb +0 -1
- metadata +5 -4
- data/lib/rubocop/cop/mixin/ignored_methods.rb +0 -52
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: 141b5fc0ee48c7fdf1fc347bb2b59b59933f6d46f575cfb4f380bfc101090345
         | 
| 4 | 
            +
              data.tar.gz: 862c5d1952e777ec19bd1b8782c9e98e065c3d80db7a7d2c91da4406afeb886c
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 2be012822408e3aa884dfe85e8a2153144f53d47550a0f7233a60448a8ab18c5c5411959742a4cb9652e972451f05cf0d447451eba53e46260baefa8f2c234e6
         | 
| 7 | 
            +
              data.tar.gz: 063e8ef0056793c86aee9f952db454eac5422c369bdf1ce4a719fcc21279214b86a800f58229b0ade17b963fb2c8e49608bd1883c840d8370b207b3aa4ee916c
         | 
    
        data/README.md
    CHANGED
    
    | @@ -46,14 +46,14 @@ If you'd rather install RuboCop using `bundler`, add a line for it in your `Gemf | |
| 46 46 | 
             
            gem 'rubocop', require: false
         | 
| 47 47 | 
             
            ```
         | 
| 48 48 |  | 
| 49 | 
            -
            RuboCop is stable between  | 
| 49 | 
            +
            RuboCop is stable between minor versions, both in terms of API and cop configuration.
         | 
| 50 50 | 
             
            We aim to ease the maintenance of RuboCop extensions and the upgrades between RuboCop
         | 
| 51 51 | 
             
            releases. All big changes are reserved for major releases.
         | 
| 52 52 | 
             
            To prevent an unwanted RuboCop update you might want to use a conservative version lock
         | 
| 53 53 | 
             
            in your `Gemfile`:
         | 
| 54 54 |  | 
| 55 55 | 
             
            ```rb
         | 
| 56 | 
            -
            gem 'rubocop', '~> 1. | 
| 56 | 
            +
            gem 'rubocop', '~> 1.33', 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
    
    | @@ -1502,7 +1502,9 @@ Lint/AmbiguousBlockAssociation: | |
| 1502 1502 | 
             
              Enabled: true
         | 
| 1503 1503 | 
             
              VersionAdded: '0.48'
         | 
| 1504 1504 | 
             
              VersionChanged: '1.13'
         | 
| 1505 | 
            -
               | 
| 1505 | 
            +
              AllowedMethods: []
         | 
| 1506 | 
            +
              AllowedPatterns: []
         | 
| 1507 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 1506 1508 |  | 
| 1507 1509 | 
             
            Lint/AmbiguousOperator:
         | 
| 1508 1510 | 
             
              Description: >-
         | 
| @@ -1753,6 +1755,7 @@ Lint/EmptyConditionalBody: | |
| 1753 1755 | 
             
              Enabled: true
         | 
| 1754 1756 | 
             
              AllowComments: true
         | 
| 1755 1757 | 
             
              VersionAdded: '0.89'
         | 
| 1758 | 
            +
              VersionChanged: '1.33'
         | 
| 1756 1759 |  | 
| 1757 1760 | 
             
            Lint/EmptyEnsure:
         | 
| 1758 1761 | 
             
              Description: 'Checks for empty ensure block.'
         | 
| @@ -1970,6 +1973,7 @@ Lint/NoReturnInBeginEndBlocks: | |
| 1970 1973 |  | 
| 1971 1974 | 
             
            Lint/NonAtomicFileOperation:
         | 
| 1972 1975 | 
             
              Description: Checks for non-atomic file operations.
         | 
| 1976 | 
            +
              StyleGuide: '#atomic-file-operations'
         | 
| 1973 1977 | 
             
              Enabled: pending
         | 
| 1974 1978 | 
             
              VersionAdded: '1.31'
         | 
| 1975 1979 | 
             
              SafeAutoCorrect: false
         | 
| @@ -1991,7 +1995,9 @@ Lint/NumberConversion: | |
| 1991 1995 | 
             
              VersionAdded: '0.53'
         | 
| 1992 1996 | 
             
              VersionChanged: '1.1'
         | 
| 1993 1997 | 
             
              SafeAutoCorrect: false
         | 
| 1994 | 
            -
               | 
| 1998 | 
            +
              AllowedMethods: []
         | 
| 1999 | 
            +
              AllowedPatterns: []
         | 
| 2000 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 1995 2001 | 
             
              IgnoredClasses:
         | 
| 1996 2002 | 
             
                - Time
         | 
| 1997 2003 | 
             
                - DateTime
         | 
| @@ -2443,7 +2449,9 @@ Metrics/AbcSize: | |
| 2443 2449 | 
             
              VersionChanged: '1.5'
         | 
| 2444 2450 | 
             
              # The ABC size is a calculated magnitude, so this number can be an Integer or
         | 
| 2445 2451 | 
             
              # a Float.
         | 
| 2446 | 
            -
               | 
| 2452 | 
            +
              AllowedMethods: []
         | 
| 2453 | 
            +
              AllowedPatterns: []
         | 
| 2454 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 2447 2455 | 
             
              CountRepeatedAttributes: true
         | 
| 2448 2456 | 
             
              Max: 17
         | 
| 2449 2457 |  | 
| @@ -2456,10 +2464,12 @@ Metrics/BlockLength: | |
| 2456 2464 | 
             
              Max: 25
         | 
| 2457 2465 | 
             
              CountAsOne: []
         | 
| 2458 2466 | 
             
              ExcludedMethods: [] # deprecated, retained for backwards compatibility
         | 
| 2459 | 
            -
               | 
| 2467 | 
            +
              AllowedMethods:
         | 
| 2460 2468 | 
             
                # By default, exclude the `#refine` method, as it tends to have larger
         | 
| 2461 2469 | 
             
                # associated blocks.
         | 
| 2462 2470 | 
             
                - refine
         | 
| 2471 | 
            +
              AllowedPatterns: []
         | 
| 2472 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 2463 2473 | 
             
              Exclude:
         | 
| 2464 2474 | 
             
                - '**/*.gemspec'
         | 
| 2465 2475 |  | 
| @@ -2489,7 +2499,9 @@ Metrics/CyclomaticComplexity: | |
| 2489 2499 | 
             
              Enabled: true
         | 
| 2490 2500 | 
             
              VersionAdded: '0.25'
         | 
| 2491 2501 | 
             
              VersionChanged: '0.81'
         | 
| 2492 | 
            -
               | 
| 2502 | 
            +
              AllowedMethods: []
         | 
| 2503 | 
            +
              AllowedPatterns: []
         | 
| 2504 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 2493 2505 | 
             
              Max: 7
         | 
| 2494 2506 |  | 
| 2495 2507 | 
             
            Metrics/MethodLength:
         | 
| @@ -2502,7 +2514,9 @@ Metrics/MethodLength: | |
| 2502 2514 | 
             
              Max: 10
         | 
| 2503 2515 | 
             
              CountAsOne: []
         | 
| 2504 2516 | 
             
              ExcludedMethods: [] # deprecated, retained for backwards compatibility
         | 
| 2505 | 
            -
               | 
| 2517 | 
            +
              AllowedMethods: []
         | 
| 2518 | 
            +
              AllowedPatterns: []
         | 
| 2519 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 2506 2520 |  | 
| 2507 2521 | 
             
            Metrics/ModuleLength:
         | 
| 2508 2522 | 
             
              Description: 'Avoid modules longer than 100 lines of code.'
         | 
| @@ -2530,7 +2544,9 @@ Metrics/PerceivedComplexity: | |
| 2530 2544 | 
             
              Enabled: true
         | 
| 2531 2545 | 
             
              VersionAdded: '0.25'
         | 
| 2532 2546 | 
             
              VersionChanged: '0.81'
         | 
| 2533 | 
            -
               | 
| 2547 | 
            +
              AllowedMethods: []
         | 
| 2548 | 
            +
              AllowedPatterns: []
         | 
| 2549 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 2534 2550 | 
             
              Max: 8
         | 
| 2535 2551 |  | 
| 2536 2552 | 
             
            ################## Migration #############################
         | 
| @@ -3061,7 +3077,7 @@ Style/BlockDelimiters: | |
| 3061 3077 | 
             
                # This looks at the usage of a block's method to determine its type (e.g. is
         | 
| 3062 3078 | 
             
                # the result of a `map` assigned to a variable or passed to another
         | 
| 3063 3079 | 
             
                # method) but exceptions are permitted in the `ProceduralMethods`,
         | 
| 3064 | 
            -
                # `FunctionalMethods` and ` | 
| 3080 | 
            +
                # `FunctionalMethods` and `AllowedMethods` sections below.
         | 
| 3065 3081 | 
             
                - semantic
         | 
| 3066 3082 | 
             
                # The `braces_for_chaining` style enforces braces around single line blocks
         | 
| 3067 3083 | 
             
                # and do..end around multi-line blocks, except for multi-line blocks whose
         | 
| @@ -3102,7 +3118,7 @@ Style/BlockDelimiters: | |
| 3102 3118 | 
             
                - let!
         | 
| 3103 3119 | 
             
                - subject
         | 
| 3104 3120 | 
             
                - watch
         | 
| 3105 | 
            -
               | 
| 3121 | 
            +
              AllowedMethods:
         | 
| 3106 3122 | 
             
                # Methods that can be either procedural or functional and cannot be
         | 
| 3107 3123 | 
             
                # categorised from their usage alone, e.g.
         | 
| 3108 3124 | 
             
                #
         | 
| @@ -3119,6 +3135,8 @@ Style/BlockDelimiters: | |
| 3119 3135 | 
             
                - lambda
         | 
| 3120 3136 | 
             
                - proc
         | 
| 3121 3137 | 
             
                - it
         | 
| 3138 | 
            +
              AllowedPatterns: []
         | 
| 3139 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 3122 3140 | 
             
              # The AllowBracesOnProceduralOneLiners option is ignored unless the
         | 
| 3123 3141 | 
             
              # EnforcedStyle is set to `semantic`. If so:
         | 
| 3124 3142 | 
             
              #
         | 
| @@ -3222,10 +3240,12 @@ Style/ClassEqualityComparison: | |
| 3222 3240 | 
             
              StyleGuide: '#instance-of-vs-class-comparison'
         | 
| 3223 3241 | 
             
              Enabled: true
         | 
| 3224 3242 | 
             
              VersionAdded: '0.93'
         | 
| 3225 | 
            -
               | 
| 3243 | 
            +
              AllowedMethods:
         | 
| 3226 3244 | 
             
                - ==
         | 
| 3227 3245 | 
             
                - equal?
         | 
| 3228 3246 | 
             
                - eql?
         | 
| 3247 | 
            +
              AllowedPatterns: []
         | 
| 3248 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 3229 3249 |  | 
| 3230 3250 | 
             
            Style/ClassMethods:
         | 
| 3231 3251 | 
             
              Description: 'Use self when defining module/class methods.'
         | 
| @@ -3687,7 +3707,9 @@ Style/FormatStringToken: | |
| 3687 3707 | 
             
              MaxUnannotatedPlaceholdersAllowed: 1
         | 
| 3688 3708 | 
             
              VersionAdded: '0.49'
         | 
| 3689 3709 | 
             
              VersionChanged: '1.0'
         | 
| 3690 | 
            -
               | 
| 3710 | 
            +
              AllowedMethods: []
         | 
| 3711 | 
            +
              AllowedPatterns: []
         | 
| 3712 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 3691 3713 |  | 
| 3692 3714 | 
             
            Style/FrozenStringLiteralComment:
         | 
| 3693 3715 | 
             
              Description: >-
         | 
| @@ -4006,7 +4028,8 @@ Style/MethodCallWithArgsParentheses: | |
| 4006 4028 | 
             
              VersionAdded: '0.47'
         | 
| 4007 4029 | 
             
              VersionChanged: '1.7'
         | 
| 4008 4030 | 
             
              IgnoreMacros: true
         | 
| 4009 | 
            -
               | 
| 4031 | 
            +
              AllowedMethods: []
         | 
| 4032 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 4010 4033 | 
             
              AllowedPatterns: []
         | 
| 4011 4034 | 
             
              IgnoredPatterns: [] # deprecated
         | 
| 4012 4035 | 
             
              IncludedMacros: []
         | 
| @@ -4023,7 +4046,9 @@ Style/MethodCallWithoutArgsParentheses: | |
| 4023 4046 | 
             
              Description: 'Do not use parentheses for method calls with no arguments.'
         | 
| 4024 4047 | 
             
              StyleGuide: '#method-invocation-parens'
         | 
| 4025 4048 | 
             
              Enabled: true
         | 
| 4026 | 
            -
               | 
| 4049 | 
            +
              AllowedMethods: []
         | 
| 4050 | 
            +
              AllowedPatterns: []
         | 
| 4051 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 4027 4052 | 
             
              VersionAdded: '0.47'
         | 
| 4028 4053 | 
             
              VersionChanged: '0.55'
         | 
| 4029 4054 |  | 
| @@ -4393,7 +4418,9 @@ Style/NumericPredicate: | |
| 4393 4418 | 
             
              SupportedStyles:
         | 
| 4394 4419 | 
             
                - predicate
         | 
| 4395 4420 | 
             
                - comparison
         | 
| 4396 | 
            -
               | 
| 4421 | 
            +
              AllowedMethods: []
         | 
| 4422 | 
            +
              AllowedPatterns: []
         | 
| 4423 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 4397 4424 | 
             
              # Exclude RSpec specs because assertions like `expect(1).to be > 0` cause
         | 
| 4398 4425 | 
             
              # false positives.
         | 
| 4399 4426 | 
             
              Exclude:
         | 
| @@ -5030,11 +5057,13 @@ Style/SymbolProc: | |
| 5030 5057 | 
             
              VersionAdded: '0.26'
         | 
| 5031 5058 | 
             
              VersionChanged: '1.28'
         | 
| 5032 5059 | 
             
              AllowMethodsWithArguments: false
         | 
| 5033 | 
            -
              # A list of method names to be  | 
| 5060 | 
            +
              # A list of method names to be always allowed by the check.
         | 
| 5034 5061 | 
             
              # The names should be fairly unique, otherwise you'll end up ignoring lots of code.
         | 
| 5035 | 
            -
               | 
| 5062 | 
            +
              AllowedMethods:
         | 
| 5036 5063 | 
             
                - respond_to
         | 
| 5037 5064 | 
             
                - define_method
         | 
| 5065 | 
            +
              AllowedPatterns: []
         | 
| 5066 | 
            +
              IgnoredMethods: [] # deprecated
         | 
| 5038 5067 | 
             
              AllowComments: false
         | 
| 5039 5068 |  | 
| 5040 5069 | 
             
            Style/TernaryParentheses:
         | 
    
        data/config/obsoletion.yml
    CHANGED
    
    | @@ -187,7 +187,9 @@ changed_parameters: | |
| 187 187 | 
             
                  - Metrics/BlockLength
         | 
| 188 188 | 
             
                  - Metrics/MethodLength
         | 
| 189 189 | 
             
                parameters: ExcludedMethods
         | 
| 190 | 
            -
                 | 
| 190 | 
            +
                alternatives:
         | 
| 191 | 
            +
                  - AllowedMethods
         | 
| 192 | 
            +
                  - AllowedPatterns
         | 
| 191 193 | 
             
                severity: warning
         | 
| 192 194 | 
             
              - cops: Lint/Debugger
         | 
| 193 195 | 
             
                parameters: DebuggerReceivers
         | 
| @@ -202,6 +204,26 @@ changed_parameters: | |
| 202 204 | 
             
                parameters: IgnoredPatterns
         | 
| 203 205 | 
             
                alternative: AllowedPatterns
         | 
| 204 206 | 
             
                severity: warning
         | 
| 207 | 
            +
              - cops:
         | 
| 208 | 
            +
                  - Lint/AmbiguousBlockAssociation
         | 
| 209 | 
            +
                  - Lint/NumberConversion
         | 
| 210 | 
            +
                  - Metrics/AbcSize
         | 
| 211 | 
            +
                  - Metrics/BlockLength
         | 
| 212 | 
            +
                  - Metrics/CyclomaticComplexity
         | 
| 213 | 
            +
                  - Metrics/MethodLength
         | 
| 214 | 
            +
                  - Metrics/PerceivedComplexity
         | 
| 215 | 
            +
                  - Style/BlockDelimiters
         | 
| 216 | 
            +
                  - Style/ClassEqualityComparison
         | 
| 217 | 
            +
                  - Style/FormatStringToken
         | 
| 218 | 
            +
                  - Style/MethodCallWithArgsParentheses
         | 
| 219 | 
            +
                  - Style/MethodCallWithoutArgsParentheses
         | 
| 220 | 
            +
                  - Style/NumericPredicate
         | 
| 221 | 
            +
                  - Style/SymbolLiteral
         | 
| 222 | 
            +
                parameters: IgnoredMethods
         | 
| 223 | 
            +
                alternatives:
         | 
| 224 | 
            +
                  - AllowedMethods
         | 
| 225 | 
            +
                  - AllowedPatterns
         | 
| 226 | 
            +
                severity: warning
         | 
| 205 227 |  | 
| 206 228 | 
             
            # Enforced styles that have been removed or replaced
         | 
| 207 229 | 
             
            changed_enforced_styles:
         | 
| @@ -0,0 +1,29 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module RuboCop
         | 
| 4 | 
            +
              # This class represents the cache config of the caching RuboCop runs.
         | 
| 5 | 
            +
              # @api private
         | 
| 6 | 
            +
              class CacheConfig
         | 
| 7 | 
            +
                def self.root_dir
         | 
| 8 | 
            +
                  root = ENV.fetch('RUBOCOP_CACHE_ROOT', nil)
         | 
| 9 | 
            +
                  root ||= yield
         | 
| 10 | 
            +
                  root ||= if ENV.key?('XDG_CACHE_HOME')
         | 
| 11 | 
            +
                             # Include user ID in the path to make sure the user has write
         | 
| 12 | 
            +
                             # access.
         | 
| 13 | 
            +
                             File.join(ENV.fetch('XDG_CACHE_HOME'), Process.uid.to_s)
         | 
| 14 | 
            +
                           else
         | 
| 15 | 
            +
                             # On FreeBSD, the /home path is a symbolic link to /usr/home
         | 
| 16 | 
            +
                             # and the $HOME environment variable returns the /home path.
         | 
| 17 | 
            +
                             #
         | 
| 18 | 
            +
                             # As $HOME is a built-in environment variable, FreeBSD users
         | 
| 19 | 
            +
                             # always get a warning message.
         | 
| 20 | 
            +
                             #
         | 
| 21 | 
            +
                             # To avoid raising warn log messages on FreeBSD, we retrieve
         | 
| 22 | 
            +
                             # the real path of the home folder.
         | 
| 23 | 
            +
                             File.join(File.realpath(Dir.home), '.cache')
         | 
| 24 | 
            +
                           end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  File.join(root, 'rubocop_cache')
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
            end
         | 
| @@ -98,7 +98,7 @@ module RuboCop | |
| 98 98 | 
             
                    def add_inheritance_from_auto_generated_file(config_file)
         | 
| 99 99 | 
             
                      file_string = " #{relative_path_to_todo_from_options_config}"
         | 
| 100 100 |  | 
| 101 | 
            -
                      config_file ||=  | 
| 101 | 
            +
                      config_file ||= ConfigFinder::DOTFILE
         | 
| 102 102 |  | 
| 103 103 | 
             
                      if File.exist?(config_file)
         | 
| 104 104 | 
             
                        files = Array(ConfigLoader.load_yaml_configuration(config_file)['inherit_from'])
         | 
| @@ -113,7 +113,7 @@ module RuboCop | |
| 113 113 | 
             
                      write_config_file(config_file, file_string, rubocop_yml_contents)
         | 
| 114 114 |  | 
| 115 115 | 
             
                      puts "Added inheritance from `#{relative_path_to_todo_from_options_config}` " \
         | 
| 116 | 
            -
                           "in `#{ | 
| 116 | 
            +
                           "in `#{ConfigFinder::DOTFILE}`."
         | 
| 117 117 | 
             
                    end
         | 
| 118 118 |  | 
| 119 119 | 
             
                    def existing_configuration(config_file)
         | 
| @@ -0,0 +1,68 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require_relative 'file_finder'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module RuboCop
         | 
| 6 | 
            +
              # This class has methods related to finding configuration path.
         | 
| 7 | 
            +
              # @api private
         | 
| 8 | 
            +
              class ConfigFinder
         | 
| 9 | 
            +
                DOTFILE = '.rubocop.yml'
         | 
| 10 | 
            +
                XDG_CONFIG = 'config.yml'
         | 
| 11 | 
            +
                RUBOCOP_HOME = File.realpath(File.join(File.dirname(__FILE__), '..', '..'))
         | 
| 12 | 
            +
                DEFAULT_FILE = File.join(RUBOCOP_HOME, 'config', 'default.yml')
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                class << self
         | 
| 15 | 
            +
                  include FileFinder
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  attr_writer :project_root
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def find_config_path(target_dir)
         | 
| 20 | 
            +
                    find_project_dotfile(target_dir) || find_user_dotfile || find_user_xdg_config ||
         | 
| 21 | 
            +
                      DEFAULT_FILE
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  # Returns the path RuboCop inferred as the root of the project. No file
         | 
| 25 | 
            +
                  # searches will go past this directory.
         | 
| 26 | 
            +
                  def project_root
         | 
| 27 | 
            +
                    @project_root ||= find_project_root
         | 
| 28 | 
            +
                  end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  private
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def find_project_root
         | 
| 33 | 
            +
                    pwd = Dir.pwd
         | 
| 34 | 
            +
                    gems_file = find_last_file_upwards('Gemfile', pwd) || find_last_file_upwards('gems.rb', pwd)
         | 
| 35 | 
            +
                    return unless gems_file
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                    File.dirname(gems_file)
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                  def find_project_dotfile(target_dir)
         | 
| 41 | 
            +
                    find_file_upwards(DOTFILE, target_dir, project_root)
         | 
| 42 | 
            +
                  end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                  def find_user_dotfile
         | 
| 45 | 
            +
                    return unless ENV.key?('HOME')
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    file = File.join(Dir.home, DOTFILE)
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                    return file if File.exist?(file)
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  def find_user_xdg_config
         | 
| 53 | 
            +
                    xdg_config_home = expand_path(ENV.fetch('XDG_CONFIG_HOME', '~/.config'))
         | 
| 54 | 
            +
                    xdg_config = File.join(xdg_config_home, 'rubocop', XDG_CONFIG)
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    return xdg_config if File.exist?(xdg_config)
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  def expand_path(path)
         | 
| 60 | 
            +
                    File.expand_path(path)
         | 
| 61 | 
            +
                  rescue ArgumentError
         | 
| 62 | 
            +
                    # Could happen because HOME or ID could not be determined. Fall back on
         | 
| 63 | 
            +
                    # using the path literally in that case.
         | 
| 64 | 
            +
                    path
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
            end
         | 
| @@ -3,6 +3,7 @@ | |
| 3 3 | 
             
            require 'erb'
         | 
| 4 4 | 
             
            require 'yaml'
         | 
| 5 5 | 
             
            require 'pathname'
         | 
| 6 | 
            +
            require_relative 'config_finder'
         | 
| 6 7 |  | 
| 7 8 | 
             
            module RuboCop
         | 
| 8 9 | 
             
              # Raised when a RuboCop configuration file is not found.
         | 
| @@ -15,8 +16,7 @@ module RuboCop | |
| 15 16 | 
             
              # during a run of the rubocop program, if files in several
         | 
| 16 17 | 
             
              # directories are inspected.
         | 
| 17 18 | 
             
              class ConfigLoader
         | 
| 18 | 
            -
                DOTFILE =  | 
| 19 | 
            -
                XDG_CONFIG = 'config.yml'
         | 
| 19 | 
            +
                DOTFILE = ConfigFinder::DOTFILE
         | 
| 20 20 | 
             
                RUBOCOP_HOME = File.realpath(File.join(File.dirname(__FILE__), '..', '..'))
         | 
| 21 21 | 
             
                DEFAULT_FILE = File.join(RUBOCOP_HOME, 'config', 'default.yml')
         | 
| 22 22 |  | 
| @@ -25,7 +25,7 @@ module RuboCop | |
| 25 25 |  | 
| 26 26 | 
             
                  attr_accessor :debug, :ignore_parent_exclusion, :disable_pending_cops, :enable_pending_cops,
         | 
| 27 27 | 
             
                                :ignore_unrecognized_cops
         | 
| 28 | 
            -
                  attr_writer :default_configuration | 
| 28 | 
            +
                  attr_writer :default_configuration
         | 
| 29 29 | 
             
                  attr_reader :loaded_features
         | 
| 30 30 |  | 
| 31 31 | 
             
                  alias debug? debug
         | 
| @@ -95,8 +95,7 @@ module RuboCop | |
| 95 95 | 
             
                  # user's home directory is checked. If there's no .rubocop.yml
         | 
| 96 96 | 
             
                  # there either, the path to the default file is returned.
         | 
| 97 97 | 
             
                  def configuration_file_for(target_dir)
         | 
| 98 | 
            -
                     | 
| 99 | 
            -
                      find_user_xdg_config || DEFAULT_FILE
         | 
| 98 | 
            +
                    ConfigFinder.find_config_path(target_dir)
         | 
| 100 99 | 
             
                  end
         | 
| 101 100 |  | 
| 102 101 | 
             
                  def configuration_from_file(config_file, check: true)
         | 
| @@ -122,7 +121,7 @@ module RuboCop | |
| 122 121 | 
             
                  end
         | 
| 123 122 |  | 
| 124 123 | 
             
                  def add_excludes_from_files(config, config_file)
         | 
| 125 | 
            -
                    exclusion_file = find_last_file_upwards(DOTFILE, config_file, project_root)
         | 
| 124 | 
            +
                    exclusion_file = find_last_file_upwards(DOTFILE, config_file, ConfigFinder.project_root)
         | 
| 126 125 |  | 
| 127 126 | 
             
                    return unless exclusion_file
         | 
| 128 127 | 
             
                    return if PathUtil.relative_path(exclusion_file) == PathUtil.relative_path(config_file)
         | 
| @@ -138,12 +137,6 @@ module RuboCop | |
| 138 137 | 
             
                    end
         | 
| 139 138 | 
             
                  end
         | 
| 140 139 |  | 
| 141 | 
            -
                  # Returns the path RuboCop inferred as the root of the project. No file
         | 
| 142 | 
            -
                  # searches will go past this directory.
         | 
| 143 | 
            -
                  def project_root
         | 
| 144 | 
            -
                    @project_root ||= find_project_root
         | 
| 145 | 
            -
                  end
         | 
| 146 | 
            -
             | 
| 147 140 | 
             
                  PENDING_BANNER = <<~BANNER
         | 
| 148 141 | 
             
                    The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file.
         | 
| 149 142 |  | 
| @@ -187,39 +180,6 @@ module RuboCop | |
| 187 180 | 
             
                    File.absolute_path(file.is_a?(RemoteConfig) ? file.file : file)
         | 
| 188 181 | 
             
                  end
         | 
| 189 182 |  | 
| 190 | 
            -
                  def find_project_dotfile(target_dir)
         | 
| 191 | 
            -
                    find_file_upwards(DOTFILE, target_dir, project_root)
         | 
| 192 | 
            -
                  end
         | 
| 193 | 
            -
             | 
| 194 | 
            -
                  def find_project_root
         | 
| 195 | 
            -
                    pwd = Dir.pwd
         | 
| 196 | 
            -
                    gems_file = find_last_file_upwards('Gemfile', pwd) || find_last_file_upwards('gems.rb', pwd)
         | 
| 197 | 
            -
                    return unless gems_file
         | 
| 198 | 
            -
             | 
| 199 | 
            -
                    File.dirname(gems_file)
         | 
| 200 | 
            -
                  end
         | 
| 201 | 
            -
             | 
| 202 | 
            -
                  def find_user_dotfile
         | 
| 203 | 
            -
                    return unless ENV.key?('HOME')
         | 
| 204 | 
            -
             | 
| 205 | 
            -
                    file = File.join(Dir.home, DOTFILE)
         | 
| 206 | 
            -
                    return file if File.exist?(file)
         | 
| 207 | 
            -
                  end
         | 
| 208 | 
            -
             | 
| 209 | 
            -
                  def find_user_xdg_config
         | 
| 210 | 
            -
                    xdg_config_home = expand_path(ENV.fetch('XDG_CONFIG_HOME', '~/.config'))
         | 
| 211 | 
            -
                    xdg_config = File.join(xdg_config_home, 'rubocop', XDG_CONFIG)
         | 
| 212 | 
            -
                    return xdg_config if File.exist?(xdg_config)
         | 
| 213 | 
            -
                  end
         | 
| 214 | 
            -
             | 
| 215 | 
            -
                  def expand_path(path)
         | 
| 216 | 
            -
                    File.expand_path(path)
         | 
| 217 | 
            -
                  rescue ArgumentError
         | 
| 218 | 
            -
                    # Could happen because HOME or ID could not be determined. Fall back on
         | 
| 219 | 
            -
                    # using the path literally in that case.
         | 
| 220 | 
            -
                    path
         | 
| 221 | 
            -
                  end
         | 
| 222 | 
            -
             | 
| 223 183 | 
             
                  def resolver
         | 
| 224 184 | 
             
                    @resolver ||= ConfigLoaderResolver.new
         | 
| 225 185 | 
             
                  end
         | 
| @@ -12,6 +12,11 @@ module RuboCop | |
| 12 12 |  | 
| 13 13 | 
             
                    if alternative
         | 
| 14 14 | 
             
                      "#{base}\n`#{parameter}` has been renamed to `#{alternative.chomp}`."
         | 
| 15 | 
            +
                    elsif alternatives
         | 
| 16 | 
            +
                      "#{base}\n`#{parameter}` has been renamed to #{to_sentence(alternatives.map do |item|
         | 
| 17 | 
            +
                                                                                   "`#{item}`"
         | 
| 18 | 
            +
                                                                                 end,
         | 
| 19 | 
            +
                                                                                 connector: 'and/or')}."
         | 
| 15 20 | 
             
                    else
         | 
| 16 21 | 
             
                      "#{base}\n#{reason.chomp}"
         | 
| 17 22 | 
             
                    end
         | 
| @@ -47,10 +47,15 @@ module RuboCop | |
| 47 47 |  | 
| 48 48 | 
             
                # Default rules for obsoletions are in config/obsoletion.yml
         | 
| 49 49 | 
             
                # Additional rules files can be added with `RuboCop::ConfigObsoletion.files << filename`
         | 
| 50 | 
            -
                def load_rules
         | 
| 50 | 
            +
                def load_rules # rubocop:disable Metrics/AbcSize
         | 
| 51 51 | 
             
                  rules = self.class.files.each_with_object({}) do |filename, hash|
         | 
| 52 52 | 
             
                    hash.merge!(YAML.safe_load(File.read(filename))) do |_key, first, second|
         | 
| 53 | 
            -
                      first | 
| 53 | 
            +
                      case first
         | 
| 54 | 
            +
                      when Hash
         | 
| 55 | 
            +
                        first.merge(second)
         | 
| 56 | 
            +
                      when Array
         | 
| 57 | 
            +
                        first.concat(second)
         | 
| 58 | 
            +
                      end
         | 
| 54 59 | 
             
                    end
         | 
| 55 60 | 
             
                  end
         | 
| 56 61 |  | 
| @@ -36,24 +36,51 @@ module RuboCop | |
| 36 36 | 
             
                      # If the end is on its own line, there is no offense
         | 
| 37 37 | 
             
                      return if begins_its_line?(node.loc.end)
         | 
| 38 38 |  | 
| 39 | 
            -
                       | 
| 40 | 
            -
                        corrector.replace(delimiter_range(node), "\n#{node.loc.end.source}#{offset(node)}")
         | 
| 41 | 
            -
                      end
         | 
| 39 | 
            +
                      register_offense(node)
         | 
| 42 40 | 
             
                    end
         | 
| 43 41 |  | 
| 44 42 | 
             
                    private
         | 
| 45 43 |  | 
| 44 | 
            +
                    def register_offense(node)
         | 
| 45 | 
            +
                      add_offense(node.loc.end, message: message(node)) do |corrector|
         | 
| 46 | 
            +
                        offense_range = offense_range(node)
         | 
| 47 | 
            +
                        replacement = "\n#{offense_range.source.strip}"
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                        if (heredoc = last_heredoc_argument(node.body))
         | 
| 50 | 
            +
                          corrector.remove(offense_range)
         | 
| 51 | 
            +
                          corrector.insert_after(heredoc.loc.heredoc_end, replacement)
         | 
| 52 | 
            +
                        else
         | 
| 53 | 
            +
                          corrector.replace(offense_range, replacement)
         | 
| 54 | 
            +
                        end
         | 
| 55 | 
            +
                      end
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
             | 
| 46 58 | 
             
                    def message(node)
         | 
| 47 59 | 
             
                      format(MSG, line: node.loc.end.line, column: node.loc.end.column + 1)
         | 
| 48 60 | 
             
                    end
         | 
| 49 61 |  | 
| 50 | 
            -
                    def  | 
| 62 | 
            +
                    def last_heredoc_argument(node)
         | 
| 63 | 
            +
                      return unless (arguments = node&.arguments)
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                      heredoc = arguments.reverse.detect(&:heredoc?)
         | 
| 66 | 
            +
                      return heredoc if heredoc
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                      last_heredoc_argument(node.children.first)
         | 
| 69 | 
            +
                    end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                    def offense_range(node)
         | 
| 51 72 | 
             
                      Parser::Source::Range.new(
         | 
| 52 73 | 
             
                        node.loc.expression.source_buffer,
         | 
| 53 74 | 
             
                        node.children.compact.last.loc.expression.end_pos,
         | 
| 54 | 
            -
                        node.loc.expression.end_pos
         | 
| 75 | 
            +
                        end_of_method_chain(node).loc.expression.end_pos
         | 
| 55 76 | 
             
                      )
         | 
| 56 77 | 
             
                    end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    def end_of_method_chain(node)
         | 
| 80 | 
            +
                      return node unless node.parent&.call_type?
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                      end_of_method_chain(node.parent)
         | 
| 83 | 
            +
                    end
         | 
| 57 84 | 
             
                  end
         | 
| 58 85 | 
             
                end
         | 
| 59 86 | 
             
              end
         | 
| @@ -153,7 +153,8 @@ module RuboCop | |
| 153 153 | 
             
                    MSG = 'Indent the first argument one step more than %<base>s.'
         | 
| 154 154 |  | 
| 155 155 | 
             
                    def on_send(node)
         | 
| 156 | 
            -
                      return if style != :consistent && enforce_first_argument_with_fixed_indentation?
         | 
| 156 | 
            +
                      return if style != :consistent && enforce_first_argument_with_fixed_indentation? &&
         | 
| 157 | 
            +
                                !enable_layout_first_method_argument_line_break?
         | 
| 157 158 | 
             
                      return if !node.arguments? || bare_operator?(node) || node.setter_method?
         | 
| 158 159 |  | 
| 159 160 | 
             
                      indent = base_indentation(node) + configured_indentation_width
         | 
| @@ -267,6 +268,10 @@ module RuboCop | |
| 267 268 | 
             
                      argument_alignment_config['EnforcedStyle'] == 'with_fixed_indentation'
         | 
| 268 269 | 
             
                    end
         | 
| 269 270 |  | 
| 271 | 
            +
                    def enable_layout_first_method_argument_line_break?
         | 
| 272 | 
            +
                      config.for_cop('Layout/FirstMethodArgumentLineBreak')['Enabled']
         | 
| 273 | 
            +
                    end
         | 
| 274 | 
            +
             | 
| 270 275 | 
             
                    def argument_alignment_config
         | 
| 271 276 | 
             
                      config.for_cop('Layout/ArgumentAlignment')
         | 
| 272 277 | 
             
                    end
         | 
| @@ -6,8 +6,8 @@ module RuboCop | |
| 6 6 | 
             
                  # Checks for ambiguous block association with method
         | 
| 7 7 | 
             
                  # when param passed without parentheses.
         | 
| 8 8 | 
             
                  #
         | 
| 9 | 
            -
                  # This cop can customize  | 
| 10 | 
            -
                  # By default, there are no methods to  | 
| 9 | 
            +
                  # This cop can customize allowed methods with `AllowedMethods`.
         | 
| 10 | 
            +
                  # By default, there are no methods to allowed.
         | 
| 11 11 | 
             
                  #
         | 
| 12 12 | 
             
                  # @example
         | 
| 13 13 | 
             
                  #
         | 
| @@ -30,18 +30,30 @@ module RuboCop | |
| 30 30 | 
             
                  #   # Lambda arguments require no disambiguation
         | 
| 31 31 | 
             
                  #   foo = ->(bar) { bar.baz }
         | 
| 32 32 | 
             
                  #
         | 
| 33 | 
            -
                  # @example  | 
| 33 | 
            +
                  # @example AllowedMethods: [] (default)
         | 
| 34 34 | 
             
                  #
         | 
| 35 35 | 
             
                  #   # bad
         | 
| 36 36 | 
             
                  #   expect { do_something }.to change { object.attribute }
         | 
| 37 37 | 
             
                  #
         | 
| 38 | 
            -
                  # @example  | 
| 38 | 
            +
                  # @example AllowedMethods: [change]
         | 
| 39 39 | 
             
                  #
         | 
| 40 40 | 
             
                  #   # good
         | 
| 41 41 | 
             
                  #   expect { do_something }.to change { object.attribute }
         | 
| 42 42 | 
             
                  #
         | 
| 43 | 
            +
                  # @example AllowedPatterns: [] (default)
         | 
| 44 | 
            +
                  #
         | 
| 45 | 
            +
                  #   # bad
         | 
| 46 | 
            +
                  #   expect { do_something }.to change { object.attribute }
         | 
| 47 | 
            +
                  #
         | 
| 48 | 
            +
                  # @example AllowedPatterns: [/change/]
         | 
| 49 | 
            +
                  #
         | 
| 50 | 
            +
                  #   # good
         | 
| 51 | 
            +
                  #   expect { do_something }.to change { object.attribute }
         | 
| 52 | 
            +
                  #   expect { do_something }.to not_change { object.attribute }
         | 
| 53 | 
            +
                  #
         | 
| 43 54 | 
             
                  class AmbiguousBlockAssociation < Base
         | 
| 44 | 
            -
                    include  | 
| 55 | 
            +
                    include AllowedMethods
         | 
| 56 | 
            +
                    include AllowedPattern
         | 
| 45 57 |  | 
| 46 58 | 
             
                    MSG = 'Parenthesize the param `%<param>s` to make sure that the ' \
         | 
| 47 59 | 
             
                          'block will be associated with the `%<method>s` method ' \
         | 
| @@ -52,7 +64,7 @@ module RuboCop | |
| 52 64 |  | 
| 53 65 | 
             
                      return unless ambiguous_block_association?(node)
         | 
| 54 66 | 
             
                      return if node.parenthesized? || node.last_argument.lambda? || node.last_argument.proc? ||
         | 
| 55 | 
            -
                                 | 
| 67 | 
            +
                                allowed_method_pattern?(node)
         | 
| 56 68 |  | 
| 57 69 | 
             
                      message = message(node)
         | 
| 58 70 |  | 
| @@ -66,9 +78,10 @@ module RuboCop | |
| 66 78 | 
             
                      send_node.last_argument.block_type? && !send_node.last_argument.send_node.arguments?
         | 
| 67 79 | 
             
                    end
         | 
| 68 80 |  | 
| 69 | 
            -
                    def  | 
| 81 | 
            +
                    def allowed_method_pattern?(node)
         | 
| 70 82 | 
             
                      node.assignment? || node.operator_method? || node.method?(:[]) ||
         | 
| 71 | 
            -
                         | 
| 83 | 
            +
                        allowed_method?(node.last_argument.method_name) ||
         | 
| 84 | 
            +
                        matches_allowed_pattern?(node.last_argument.method_name)
         | 
| 72 85 | 
             
                    end
         | 
| 73 86 |  | 
| 74 87 | 
             
                    def message(send_node)
         |