rubocop-hq/rubocop

View on GitHub
lib/rubocop/cop/layout/array_alignment.rb

Summary

Maintainability
A
20 mins
Test Coverage
A
100%
# frozen_string_literal: true

module RuboCop
  module Cop
    module Layout
      # Here we check if the elements of a multi-line array literal are
      # aligned.
      #
      # @example EnforcedStyle: with_first_element (default)
      #   # good
      #
      #   array = [1, 2, 3,
      #            4, 5, 6]
      #   array = ['run',
      #            'forrest',
      #            'run']
      #
      #   # bad
      #
      #   array = [1, 2, 3,
      #     4, 5, 6]
      #   array = ['run',
      #        'forrest',
      #        'run']
      #
      # @example EnforcedStyle: with_fixed_indentation
      #   # good
      #
      #   array = [1, 2, 3,
      #     4, 5, 6]
      #
      #   # bad
      #
      #   array = [1, 2, 3,
      #            4, 5, 6]
      class ArrayAlignment < Base
        include Alignment
        extend AutoCorrector

        ALIGN_ELEMENTS_MSG = 'Align the elements of an array literal ' \
                             'if they span more than one line.'

        FIXED_INDENT_MSG = 'Use one level of indentation for elements ' \
                           'following the first line of a multi-line array.'

        def on_array(node)
          return if node.children.size < 2
          return if node.parent&.masgn_type?

          check_alignment(node.children, base_column(node, node.children))
        end

        private

        def autocorrect(corrector, node)
          AlignmentCorrector.correct(corrector, processed_source, node, column_delta)
        end

        def message(_range)
          fixed_indentation? ? FIXED_INDENT_MSG : ALIGN_ELEMENTS_MSG
        end

        def fixed_indentation?
          cop_config['EnforcedStyle'] == 'with_fixed_indentation'
        end

        def base_column(node, args)
          if fixed_indentation?
            lineno = target_method_lineno(node)
            line = node.source_range.source_buffer.source_line(lineno)
            indentation_of_line = /\S.*/.match(line).begin(0)
            indentation_of_line + configured_indentation_width
          else
            display_column(args.first.source_range)
          end
        end

        def target_method_lineno(node)
          node.bracketed? ? node.loc.line : node.parent.loc.line
        end
      end
    end
  end
end