rubocop 0.69.0 → 0.70.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 +1 -1
- data/config/default.yml +17 -1
- data/lib/rubocop.rb +1 -0
- data/lib/rubocop/ast/builder.rb +37 -37
- data/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +10 -0
- data/lib/rubocop/cached_data.rb +2 -2
- data/lib/rubocop/config.rb +9 -1
- data/lib/rubocop/config_loader.rb +2 -2
- data/lib/rubocop/config_loader_resolver.rb +3 -2
- data/lib/rubocop/cop/generator.rb +7 -1
- data/lib/rubocop/cop/layout/align_hash.rb +74 -31
- data/lib/rubocop/cop/layout/closing_parenthesis_indentation.rb +6 -6
- data/lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb +75 -4
- data/lib/rubocop/cop/layout/indentation_width.rb +1 -7
- data/lib/rubocop/cop/lint/ambiguous_operator.rb +5 -5
- data/lib/rubocop/cop/lint/handle_exceptions.rb +47 -8
- data/lib/rubocop/cop/lint/number_conversion.rb +7 -0
- data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +3 -0
- data/lib/rubocop/cop/mixin/configurable_naming.rb +1 -1
- data/lib/rubocop/cop/mixin/configurable_numbering.rb +2 -2
- data/lib/rubocop/cop/mixin/ignored_method_patterns.rb +19 -0
- data/lib/rubocop/cop/rails/refute_methods.rb +13 -13
- data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +17 -3
- data/lib/rubocop/cop/variable_force/scope.rb +3 -3
- data/lib/rubocop/formatter/formatter_set.rb +13 -13
- data/lib/rubocop/formatter/html_formatter.rb +4 -4
- data/lib/rubocop/formatter/json_formatter.rb +16 -16
- data/lib/rubocop/formatter/simple_text_formatter.rb +4 -4
- data/lib/rubocop/options.rb +89 -83
- data/lib/rubocop/version.rb +1 -1
- metadata +4 -24
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: f98c70ae4897b3f4c793fa73cb716986f9d63815928c278accf6879a0190e97e
         | 
| 4 | 
            +
              data.tar.gz: 89111e2312bdf926aab76ca58bfb90a414ff3b5f58ba48257e5d1949763d4776
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 83462908a6383ab72503c4af338d395a118e435d8f4f73e7cdda54b6d8d1cc05f40a5ebdb6a3197bf9a2734046665c7c2d6616e0bb0847f198d11b410ae4b7f8
         | 
| 7 | 
            +
              data.tar.gz: 39c1a0fca5a9251e3a60f9ca3958d228d79f5797de21da608f69cb133611c683913673bbdc426a537c9578bc4394607a20617d394d1abc3454878373589a0fdd
         | 
    
        data/README.md
    CHANGED
    
    | @@ -53,7 +53,7 @@ haven't reached version 1.0 yet). To prevent an unwanted RuboCop update you | |
| 53 53 | 
             
            might want to use a conservative version lock in your `Gemfile`:
         | 
| 54 54 |  | 
| 55 55 | 
             
            ```rb
         | 
| 56 | 
            -
            gem 'rubocop', '~> 0. | 
| 56 | 
            +
            gem 'rubocop', '~> 0.70.0', require: false
         | 
| 57 57 | 
             
            ```
         | 
| 58 58 |  | 
| 59 59 | 
             
            ## Quickstart
         | 
    
        data/config/default.yml
    CHANGED
    
    | @@ -260,6 +260,7 @@ Layout/AlignHash: | |
| 260 260 | 
             
                             Align the elements of a hash literal if they span more than
         | 
| 261 261 | 
             
                             one line.
         | 
| 262 262 | 
             
              Enabled: true
         | 
| 263 | 
            +
              AllowMultipleStyles: true
         | 
| 263 264 | 
             
              VersionAdded: '0.49'
         | 
| 264 265 | 
             
              # Alignment of entries using hash rocket as separator. Valid values are:
         | 
| 265 266 | 
             
              #
         | 
| @@ -508,6 +509,13 @@ Layout/EmptyLinesAroundAccessModifier: | |
| 508 509 | 
             
              StyleGuide: '#empty-lines-around-access-modifier'
         | 
| 509 510 | 
             
              Enabled: true
         | 
| 510 511 | 
             
              VersionAdded: '0.49'
         | 
| 512 | 
            +
              EnforcedStyle: around
         | 
| 513 | 
            +
              SupportedStyles:
         | 
| 514 | 
            +
                - around
         | 
| 515 | 
            +
                - only_before
         | 
| 516 | 
            +
              Reference:
         | 
| 517 | 
            +
                # A reference to `EnforcedStyle: only_before`.
         | 
| 518 | 
            +
                - https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions
         | 
| 511 519 |  | 
| 512 520 | 
             
            Layout/EmptyLinesAroundArguments:
         | 
| 513 521 | 
             
              Description: "Keeps track of empty lines around method arguments."
         | 
| @@ -780,6 +788,9 @@ Layout/IndentationConsistency: | |
| 780 788 | 
             
              SupportedStyles:
         | 
| 781 789 | 
             
                - normal
         | 
| 782 790 | 
             
                - rails
         | 
| 791 | 
            +
              Reference:
         | 
| 792 | 
            +
                # A reference to `EnforcedStyle: rails`.
         | 
| 793 | 
            +
                - https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions
         | 
| 783 794 |  | 
| 784 795 | 
             
            Layout/IndentationWidth:
         | 
| 785 796 | 
             
              Description: 'Use 2 spaces for indentation.'
         | 
| @@ -1359,7 +1370,9 @@ Lint/HandleExceptions: | |
| 1359 1370 | 
             
              Description: "Don't suppress exception."
         | 
| 1360 1371 | 
             
              StyleGuide: '#dont-hide-exceptions'
         | 
| 1361 1372 | 
             
              Enabled: true
         | 
| 1373 | 
            +
              AllowComments: false
         | 
| 1362 1374 | 
             
              VersionAdded: '0.9'
         | 
| 1375 | 
            +
              VersionChanged: '0.70'
         | 
| 1363 1376 |  | 
| 1364 1377 | 
             
            Lint/HeredocMethodCallPosition:
         | 
| 1365 1378 | 
             
              Description: >-
         | 
| @@ -1462,6 +1475,8 @@ Lint/NumberConversion: | |
| 1462 1475 | 
             
              Description: 'Checks unsafe usage of number conversion methods.'
         | 
| 1463 1476 | 
             
              Enabled: false
         | 
| 1464 1477 | 
             
              VersionAdded: '0.53'
         | 
| 1478 | 
            +
              VersionChanged: '0.70'
         | 
| 1479 | 
            +
              SafeAutoCorrect: false
         | 
| 1465 1480 |  | 
| 1466 1481 | 
             
            Lint/OrderedMagicComments:
         | 
| 1467 1482 | 
             
              Description: 'Checks the proper ordering of magic comments and whether a magic comment is not placed before a shebang.'
         | 
| @@ -3752,8 +3767,9 @@ Style/PreferredHashMethods: | |
| 3752 3767 | 
             
              Description: 'Checks use of `has_key?` and `has_value?` Hash methods.'
         | 
| 3753 3768 | 
             
              StyleGuide: '#hash-key'
         | 
| 3754 3769 | 
             
              Enabled: true
         | 
| 3770 | 
            +
              Safe: false
         | 
| 3755 3771 | 
             
              VersionAdded: '0.41'
         | 
| 3756 | 
            -
              VersionChanged: '0. | 
| 3772 | 
            +
              VersionChanged: '0.70'
         | 
| 3757 3773 | 
             
              EnforcedStyle: short
         | 
| 3758 3774 | 
             
              SupportedStyles:
         | 
| 3759 3775 | 
             
                - short
         | 
    
        data/lib/rubocop.rb
    CHANGED
    
    | @@ -117,6 +117,7 @@ require_relative 'rubocop/cop/mixin/frozen_string_literal' | |
| 117 117 | 
             
            require_relative 'rubocop/cop/mixin/hash_alignment'
         | 
| 118 118 | 
             
            require_relative 'rubocop/cop/mixin/ignored_pattern'
         | 
| 119 119 | 
             
            require_relative 'rubocop/cop/mixin/ignored_methods'
         | 
| 120 | 
            +
            require_relative 'rubocop/cop/mixin/ignored_method_patterns'
         | 
| 120 121 | 
             
            require_relative 'rubocop/cop/mixin/integer_node'
         | 
| 121 122 | 
             
            require_relative 'rubocop/cop/mixin/match_range'
         | 
| 122 123 | 
             
            require_relative 'rubocop/cop/mixin/method_complexity'
         | 
    
        data/lib/rubocop/ast/builder.rb
    CHANGED
    
    | @@ -15,45 +15,45 @@ module RuboCop | |
| 15 15 | 
             
                #   root_node = parser.parse(buffer)
         | 
| 16 16 | 
             
                class Builder < Parser::Builders::Default
         | 
| 17 17 | 
             
                  NODE_MAP = {
         | 
| 18 | 
            -
                    and: | 
| 19 | 
            -
                    alias: | 
| 20 | 
            -
                    args: | 
| 21 | 
            -
                    array: | 
| 22 | 
            -
                    block: | 
| 23 | 
            -
                    break: | 
| 24 | 
            -
                    case: | 
| 25 | 
            -
                    class: | 
| 26 | 
            -
                    def: | 
| 27 | 
            -
                    defined?: | 
| 28 | 
            -
                    defs: | 
| 29 | 
            -
                    ensure: | 
| 30 | 
            -
                    for: | 
| 31 | 
            -
                    hash: | 
| 32 | 
            -
                    if: | 
| 33 | 
            -
                    irange: | 
| 34 | 
            -
                    erange: | 
| 35 | 
            -
                    kwsplat: | 
| 36 | 
            -
                    module: | 
| 37 | 
            -
                    or: | 
| 38 | 
            -
                    pair: | 
| 39 | 
            -
                    regexp: | 
| 40 | 
            -
                    resbody: | 
| 41 | 
            -
                    retry: | 
| 42 | 
            -
                    csend: | 
| 43 | 
            -
                    send: | 
| 44 | 
            -
                    str: | 
| 45 | 
            -
                    dstr: | 
| 46 | 
            -
                    xstr: | 
| 47 | 
            -
                    sclass: | 
| 48 | 
            -
                    super: | 
| 49 | 
            -
                    zsuper: | 
| 50 | 
            -
                    sym: | 
| 51 | 
            -
                    until: | 
| 18 | 
            +
                    and:        AndNode,
         | 
| 19 | 
            +
                    alias:      AliasNode,
         | 
| 20 | 
            +
                    args:       ArgsNode,
         | 
| 21 | 
            +
                    array:      ArrayNode,
         | 
| 22 | 
            +
                    block:      BlockNode,
         | 
| 23 | 
            +
                    break:      BreakNode,
         | 
| 24 | 
            +
                    case:       CaseNode,
         | 
| 25 | 
            +
                    class:      ClassNode,
         | 
| 26 | 
            +
                    def:        DefNode,
         | 
| 27 | 
            +
                    defined?:   DefinedNode,
         | 
| 28 | 
            +
                    defs:       DefNode,
         | 
| 29 | 
            +
                    ensure:     EnsureNode,
         | 
| 30 | 
            +
                    for:        ForNode,
         | 
| 31 | 
            +
                    hash:       HashNode,
         | 
| 32 | 
            +
                    if:         IfNode,
         | 
| 33 | 
            +
                    irange:     RangeNode,
         | 
| 34 | 
            +
                    erange:     RangeNode,
         | 
| 35 | 
            +
                    kwsplat:    KeywordSplatNode,
         | 
| 36 | 
            +
                    module:     ModuleNode,
         | 
| 37 | 
            +
                    or:         OrNode,
         | 
| 38 | 
            +
                    pair:       PairNode,
         | 
| 39 | 
            +
                    regexp:     RegexpNode,
         | 
| 40 | 
            +
                    resbody:    ResbodyNode,
         | 
| 41 | 
            +
                    retry:      RetryNode,
         | 
| 42 | 
            +
                    csend:      SendNode,
         | 
| 43 | 
            +
                    send:       SendNode,
         | 
| 44 | 
            +
                    str:        StrNode,
         | 
| 45 | 
            +
                    dstr:       StrNode,
         | 
| 46 | 
            +
                    xstr:       StrNode,
         | 
| 47 | 
            +
                    sclass:     SelfClassNode,
         | 
| 48 | 
            +
                    super:      SuperNode,
         | 
| 49 | 
            +
                    zsuper:     SuperNode,
         | 
| 50 | 
            +
                    sym:        SymbolNode,
         | 
| 51 | 
            +
                    until:      UntilNode,
         | 
| 52 52 | 
             
                    until_post: UntilNode,
         | 
| 53 | 
            -
                    when: | 
| 54 | 
            -
                    while: | 
| 53 | 
            +
                    when:       WhenNode,
         | 
| 54 | 
            +
                    while:      WhileNode,
         | 
| 55 55 | 
             
                    while_post: WhileNode,
         | 
| 56 | 
            -
                    yield: | 
| 56 | 
            +
                    yield:      YieldNode
         | 
| 57 57 | 
             
                  }.freeze
         | 
| 58 58 |  | 
| 59 59 | 
             
                  # Generates {Node} from the given information.
         | 
| @@ -9,6 +9,7 @@ module RuboCop | |
| 9 9 | 
             
                  include MethodIdentifierPredicates
         | 
| 10 10 |  | 
| 11 11 | 
             
                  ARITHMETIC_OPERATORS = %i[+ - * / % **].freeze
         | 
| 12 | 
            +
                  SPECIAL_MODIFIERS = %w[private protected].freeze
         | 
| 12 13 |  | 
| 13 14 | 
             
                  # The receiving node of the method dispatch.
         | 
| 14 15 | 
             
                  #
         | 
| @@ -75,6 +76,15 @@ module RuboCop | |
| 75 76 | 
             
                    macro? && non_bare_access_modifier_declaration?
         | 
| 76 77 | 
             
                  end
         | 
| 77 78 |  | 
| 79 | 
            +
                  # Checks whether the dispatched method is a bare `private` or `protected`
         | 
| 80 | 
            +
                  # access modifier that affects all methods defined after the macro.
         | 
| 81 | 
            +
                  #
         | 
| 82 | 
            +
                  # @return [Boolean] whether the dispatched method is a bare
         | 
| 83 | 
            +
                  #                    `private` or `protected` access modifier
         | 
| 84 | 
            +
                  def special_modifier?
         | 
| 85 | 
            +
                    bare_access_modifier? && SPECIAL_MODIFIERS.include?(source)
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
             | 
| 78 88 | 
             
                  # Checks whether the name of the dispatched method matches the argument
         | 
| 79 89 | 
             
                  # and has an implicit receiver.
         | 
| 80 90 | 
             
                  #
         | 
    
        data/lib/rubocop/cached_data.rb
    CHANGED
    
    | @@ -29,9 +29,9 @@ module RuboCop | |
| 29 29 | 
             
                      begin_pos: offense.location.begin_pos,
         | 
| 30 30 | 
             
                      end_pos: offense.location.end_pos
         | 
| 31 31 | 
             
                    },
         | 
| 32 | 
            -
                    message: | 
| 32 | 
            +
                    message:  message(offense),
         | 
| 33 33 | 
             
                    cop_name: offense.cop_name,
         | 
| 34 | 
            -
                    status: | 
| 34 | 
            +
                    status:   :uncorrected
         | 
| 35 35 | 
             
                  }
         | 
| 36 36 | 
             
                end
         | 
| 37 37 |  | 
    
        data/lib/rubocop/config.rb
    CHANGED
    
    | @@ -543,8 +543,10 @@ module RuboCop | |
| 543 543 | 
             
                    styles.each do |style_name, style|
         | 
| 544 544 | 
             
                      supported_key = RuboCop::Cop::Util.to_supported_styles(style_name)
         | 
| 545 545 | 
             
                      valid = ConfigLoader.default_configuration[name][supported_key]
         | 
| 546 | 
            +
             | 
| 546 547 | 
             
                      next unless valid
         | 
| 547 548 | 
             
                      next if valid.include?(style)
         | 
| 549 | 
            +
                      next if validate_support_and_has_list(name, style, valid)
         | 
| 548 550 |  | 
| 549 551 | 
             
                      msg = "invalid #{style_name} '#{style}' for #{name} found in " \
         | 
| 550 552 | 
             
                        "#{smart_loaded_path}\n" \
         | 
| @@ -554,6 +556,12 @@ module RuboCop | |
| 554 556 | 
             
                  end
         | 
| 555 557 | 
             
                end
         | 
| 556 558 |  | 
| 559 | 
            +
                def validate_support_and_has_list(name, formats, valid)
         | 
| 560 | 
            +
                  ConfigLoader.default_configuration[name]['AllowMultipleStyles'] &&
         | 
| 561 | 
            +
                    formats.is_a?(Array) &&
         | 
| 562 | 
            +
                    formats.all? { |format| valid.include?(format) }
         | 
| 563 | 
            +
                end
         | 
| 564 | 
            +
             | 
| 557 565 | 
             
                def reject_obsolete_cops_and_parameters
         | 
| 558 566 | 
             
                  messages = [
         | 
| 559 567 | 
             
                    obsolete_cops,
         | 
| @@ -712,7 +720,7 @@ module RuboCop | |
| 712 720 | 
             
                    end
         | 
| 713 721 | 
             
                  end
         | 
| 714 722 |  | 
| 715 | 
            -
                  cop_options.fetch('Enabled' | 
| 723 | 
            +
                  cop_options.fetch('Enabled') { !for_all_cops['DisabledByDefault'] }
         | 
| 716 724 | 
             
                end
         | 
| 717 725 |  | 
| 718 726 | 
             
                def smart_loaded_path
         | 
| @@ -120,8 +120,8 @@ module RuboCop | |
| 120 120 | 
             
                  # If AllCops::EnabledByDefault is true, it changes the Enabled params
         | 
| 121 121 | 
             
                  # so that only cops explicitly disabled in user configuration are
         | 
| 122 122 | 
             
                  # disabled.
         | 
| 123 | 
            -
                  def merge_with_default(config, config_file)
         | 
| 124 | 
            -
                    resolver.merge_with_default(config, config_file)
         | 
| 123 | 
            +
                  def merge_with_default(config, config_file, unset_nil: true)
         | 
| 124 | 
            +
                    resolver.merge_with_default(config, config_file, unset_nil: unset_nil)
         | 
| 125 125 | 
             
                  end
         | 
| 126 126 |  | 
| 127 127 | 
             
                  def add_inheritance_from_auto_generated_file
         | 
| @@ -55,7 +55,7 @@ module RuboCop | |
| 55 55 | 
             
                # only cops from user configuration are enabled. If
         | 
| 56 56 | 
             
                # AllCops::EnabledByDefault is true, it changes the Enabled params so that
         | 
| 57 57 | 
             
                # only cops explicitly disabled in user configuration are disabled.
         | 
| 58 | 
            -
                def merge_with_default(config, config_file)
         | 
| 58 | 
            +
                def merge_with_default(config, config_file, unset_nil:)
         | 
| 59 59 | 
             
                  default_configuration = ConfigLoader.default_configuration
         | 
| 60 60 |  | 
| 61 61 | 
             
                  disabled_by_default = config.for_all_cops['DisabledByDefault']
         | 
| @@ -71,7 +71,8 @@ module RuboCop | |
| 71 71 | 
             
                    config = handle_disabled_by_default(config, default_configuration)
         | 
| 72 72 | 
             
                  end
         | 
| 73 73 |  | 
| 74 | 
            -
                  opts = { inherit_mode: config['inherit_mode'] || {}, | 
| 74 | 
            +
                  opts = { inherit_mode: config['inherit_mode'] || {},
         | 
| 75 | 
            +
                           unset_nil: unset_nil }
         | 
| 75 76 | 
             
                  Config.new(merge(default_configuration, config, opts), config_file)
         | 
| 76 77 | 
             
                end
         | 
| 77 78 |  | 
| @@ -7,7 +7,13 @@ module RuboCop | |
| 7 7 | 
             
                # This generator will take a cop name and generate a source file
         | 
| 8 8 | 
             
                # and spec file when given a valid qualified cop name.
         | 
| 9 9 | 
             
                class Generator
         | 
| 10 | 
            -
                   | 
| 10 | 
            +
                  # Note: RDoc 5.1.0 or lower has the following issue.
         | 
| 11 | 
            +
                  # https://github.com/rubocop-hq/rubocop/issues/7043
         | 
| 12 | 
            +
                  #
         | 
| 13 | 
            +
                  # The following `String#strip_indent` can be replaced with
         | 
| 14 | 
            +
                  # squiggly heredoc when RuboCop supports Ruby 2.5 or higher
         | 
| 15 | 
            +
                  # (RDoc 6.0 or higher).
         | 
| 16 | 
            +
                  SOURCE_TEMPLATE = <<-RUBY.strip_indent
         | 
| 11 17 | 
             
                    # frozen_string_literal: true
         | 
| 12 18 |  | 
| 13 19 | 
             
                    # TODO: when finished, run `rake generate_cops_documentation` to update the docs
         | 
| @@ -17,7 +17,9 @@ module RuboCop | |
| 17 17 | 
             
                  #   - always_inspect
         | 
| 18 18 | 
             
                  #   - always_ignore
         | 
| 19 19 | 
             
                  #   - ignore_implicit (without curly braces)
         | 
| 20 | 
            -
                  # | 
| 20 | 
            +
                  #
         | 
| 21 | 
            +
                  # Alternatively you can specify multiple allowed styles. That's done by
         | 
| 22 | 
            +
                  # passing a list of styles to EnforcedStyles.
         | 
| 21 23 | 
             
                  #
         | 
| 22 24 | 
             
                  # @example EnforcedHashRocketStyle: key (default)
         | 
| 23 25 | 
             
                  #   # bad
         | 
| @@ -198,48 +200,65 @@ module RuboCop | |
| 198 200 | 
             
                      return if ignored_node?(node)
         | 
| 199 201 | 
             
                      return if node.pairs.empty? || node.single_line?
         | 
| 200 202 |  | 
| 201 | 
            -
                      return unless alignment_for_hash_rockets | 
| 202 | 
            -
                                     | 
| 203 | 
            +
                      return unless alignment_for_hash_rockets
         | 
| 204 | 
            +
                                    .any? { |a| a.checkable_layout?(node) } &&
         | 
| 205 | 
            +
                                    alignment_for_colons
         | 
| 206 | 
            +
                                    .any? { |a| a.checkable_layout?(node) }
         | 
| 203 207 |  | 
| 204 208 | 
             
                      check_pairs(node)
         | 
| 205 209 | 
             
                    end
         | 
| 206 210 |  | 
| 207 211 | 
             
                    def autocorrect(node)
         | 
| 208 | 
            -
                       | 
| 209 | 
            -
                       | 
| 210 | 
            -
                      # last value of each. A local variable fixes the problem.
         | 
| 211 | 
            -
                      key_delta = column_deltas[:key] || 0
         | 
| 212 | 
            +
                      delta = column_deltas[alignment_for(node).first.class][node]
         | 
| 213 | 
            +
                      return if delta.nil?
         | 
| 212 214 |  | 
| 213 | 
            -
                       | 
| 214 | 
            -
                        correct_no_value(key_delta, node.source_range)
         | 
| 215 | 
            -
                      else
         | 
| 216 | 
            -
                        correct_key_value(key_delta, node.key.source_range,
         | 
| 217 | 
            -
                                          node.value.source_range,
         | 
| 218 | 
            -
                                          node.loc.operator)
         | 
| 219 | 
            -
                      end
         | 
| 215 | 
            +
                      correct_node(node, delta)
         | 
| 220 216 | 
             
                    end
         | 
| 221 217 |  | 
| 222 | 
            -
                     | 
| 223 | 
            -
             | 
| 218 | 
            +
                    attr_accessor :offences_by
         | 
| 224 219 | 
             
                    attr_accessor :column_deltas
         | 
| 225 220 |  | 
| 221 | 
            +
                    private
         | 
| 222 | 
            +
             | 
| 226 223 | 
             
                    def double_splat?(node)
         | 
| 227 224 | 
             
                      node.children.last.is_a?(Symbol)
         | 
| 228 225 | 
             
                    end
         | 
| 229 226 |  | 
| 230 227 | 
             
                    def check_pairs(node)
         | 
| 231 228 | 
             
                      first_pair = node.pairs.first
         | 
| 232 | 
            -
                      self. | 
| 233 | 
            -
             | 
| 234 | 
            -
             | 
| 229 | 
            +
                      self.offences_by = {}
         | 
| 230 | 
            +
                      self.column_deltas = Hash.new { |hash, key| hash[key] = {} }
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                      alignment_for(first_pair).each do |alignment|
         | 
| 233 | 
            +
                        delta = alignment.deltas_for_first_pair(first_pair, node)
         | 
| 234 | 
            +
                        check_delta delta, node: first_pair, alignment: alignment
         | 
| 235 | 
            +
                      end
         | 
| 235 236 |  | 
| 236 237 | 
             
                      node.children.each do |current|
         | 
| 237 | 
            -
                         | 
| 238 | 
            -
             | 
| 239 | 
            -
             | 
| 238 | 
            +
                        alignment_for(current).each do |alignment|
         | 
| 239 | 
            +
                          delta = alignment.deltas(first_pair, current)
         | 
| 240 | 
            +
                          check_delta delta, node: current, alignment: alignment
         | 
| 241 | 
            +
                        end
         | 
| 242 | 
            +
                      end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                      add_offences
         | 
| 245 | 
            +
                    end
         | 
| 246 | 
            +
             | 
| 247 | 
            +
                    def add_offences
         | 
| 248 | 
            +
                      _format, offences = offences_by.min_by { |_, v| v.length }
         | 
| 249 | 
            +
                      (offences || []).each do |offence|
         | 
| 250 | 
            +
                        add_offense offence
         | 
| 240 251 | 
             
                      end
         | 
| 241 252 | 
             
                    end
         | 
| 242 253 |  | 
| 254 | 
            +
                    def check_delta(delta, node:, alignment:)
         | 
| 255 | 
            +
                      offences_by[alignment.class] ||= []
         | 
| 256 | 
            +
                      return if good_alignment? delta
         | 
| 257 | 
            +
             | 
| 258 | 
            +
                      column_deltas[alignment.class][node] = delta
         | 
| 259 | 
            +
                      offences_by[alignment.class].push(node)
         | 
| 260 | 
            +
                    end
         | 
| 261 | 
            +
             | 
| 243 262 | 
             
                    def ignore_hash_argument?(node)
         | 
| 244 263 | 
             
                      case cop_config['EnforcedLastArgumentHashStyle']
         | 
| 245 264 | 
             
                      when 'always_inspect'  then false
         | 
| @@ -267,16 +286,31 @@ module RuboCop | |
| 267 286 | 
             
                        new_alignment('EnforcedColonStyle')
         | 
| 268 287 | 
             
                    end
         | 
| 269 288 |  | 
| 289 | 
            +
                    def correct_node(node, delta)
         | 
| 290 | 
            +
                      # We can't use the instance variable inside the lambda. That would
         | 
| 291 | 
            +
                      # just give each lambda the same reference and they would all get the
         | 
| 292 | 
            +
                      # last value of each. A local variable fixes the problem.
         | 
| 293 | 
            +
             | 
| 294 | 
            +
                      if !node.value
         | 
| 295 | 
            +
                        correct_no_value(delta[:key] || 0, node.source_range)
         | 
| 296 | 
            +
                      else
         | 
| 297 | 
            +
                        correct_key_value(delta, node.key.source_range,
         | 
| 298 | 
            +
                                          node.value.source_range,
         | 
| 299 | 
            +
                                          node.loc.operator)
         | 
| 300 | 
            +
                      end
         | 
| 301 | 
            +
                    end
         | 
| 302 | 
            +
             | 
| 270 303 | 
             
                    def correct_no_value(key_delta, key)
         | 
| 271 304 | 
             
                      ->(corrector) { adjust(corrector, key_delta, key) }
         | 
| 272 305 | 
             
                    end
         | 
| 273 306 |  | 
| 274 | 
            -
                    def correct_key_value( | 
| 307 | 
            +
                    def correct_key_value(delta, key, value, separator)
         | 
| 275 308 | 
             
                      # We can't use the instance variable inside the lambda. That would
         | 
| 276 309 | 
             
                      # just give each lambda the same reference and they would all get the
         | 
| 277 310 | 
             
                      # last value of each. Some local variables fix the problem.
         | 
| 278 | 
            -
                      separator_delta =  | 
| 279 | 
            -
                      value_delta     =  | 
| 311 | 
            +
                      separator_delta = delta[:separator] || 0
         | 
| 312 | 
            +
                      value_delta     = delta[:value]     || 0
         | 
| 313 | 
            +
                      key_delta       = delta[:key]       || 0
         | 
| 280 314 |  | 
| 281 315 | 
             
                      key_column = key.column
         | 
| 282 316 | 
             
                      key_delta = -key_column if key_delta < -key_column
         | 
| @@ -289,11 +323,20 @@ module RuboCop | |
| 289 323 | 
             
                    end
         | 
| 290 324 |  | 
| 291 325 | 
             
                    def new_alignment(key)
         | 
| 292 | 
            -
                       | 
| 293 | 
            -
                       | 
| 294 | 
            -
             | 
| 295 | 
            -
                       | 
| 296 | 
            -
             | 
| 326 | 
            +
                      formats = cop_config[key]
         | 
| 327 | 
            +
                      formats = [formats] if formats.is_a? String
         | 
| 328 | 
            +
             | 
| 329 | 
            +
                      formats.uniq.map do |format|
         | 
| 330 | 
            +
                        case format
         | 
| 331 | 
            +
                        when 'key'
         | 
| 332 | 
            +
                          KeyAlignment.new
         | 
| 333 | 
            +
                        when 'table'
         | 
| 334 | 
            +
                          TableAlignment.new
         | 
| 335 | 
            +
                        when 'separator'
         | 
| 336 | 
            +
                          SeparatorAlignment.new
         | 
| 337 | 
            +
                        else
         | 
| 338 | 
            +
                          raise "Unknown #{key}: #{formats}"
         | 
| 339 | 
            +
                        end
         | 
| 297 340 | 
             
                      end
         | 
| 298 341 | 
             
                    end
         | 
| 299 342 |  | 
| @@ -306,7 +349,7 @@ module RuboCop | |
| 306 349 | 
             
                      end
         | 
| 307 350 | 
             
                    end
         | 
| 308 351 |  | 
| 309 | 
            -
                    def good_alignment?
         | 
| 352 | 
            +
                    def good_alignment?(column_deltas)
         | 
| 310 353 | 
             
                      column_deltas.values.all?(&:zero?)
         | 
| 311 354 | 
             
                    end
         | 
| 312 355 | 
             
                  end
         |