enkessler/cuke_linter

View on GitHub
lib/cuke_linter/formatters/pretty_formatter.rb

Summary

Maintainability
A
25 mins
Test Coverage
module CukeLinter

  # Formats linting data into organized, user readable text
  class PrettyFormatter

    # Formats the given linting data
    def format(data)
      format_data(categorize_problems(data), data.count)
    end


    private


    def categorize_problems(data)
      {}.tap do |categorized_problems|
        data.each do |lint_item|
          categorized_problems[lint_item[:linter]]                      ||= {}
          categorized_problems[lint_item[:linter]][lint_item[:problem]] ||= []
          categorized_problems[lint_item[:linter]][lint_item[:problem]] << lint_item[:location]
        end
      end
    end

    def format_data(problem_data, problem_count)
      ''.tap do |formatted_data|
        problem_data.each_pair do |linter, problems|
          formatted_data << "#{linter}\n"

          problems.each_pair do |problem, locations|
            formatted_data << "  #{problem}\n"

            sort_locations(locations).each do |location|
              formatted_data << "    #{location}\n"
            end
          end
        end

        formatted_data << "\n" unless problem_count.zero?
        formatted_data << "#{problem_count} issues found"
      end
    end

    def sort_locations(locations)
      locations.sort do |a, b|
        file_name_1   = a.match(/(.*?)(?::\d+)?$/)[1]
        line_number_1 = a =~ /:\d+$/ ? a.match(/:(\d+)$/)[1].to_i : 0
        file_name_2   = b.match(/(.*?)(?::\d+)?$/)[1]
        line_number_2 = b =~ /:\d+$/ ? b.match(/:(\d+)$/)[1].to_i : 0

        compare_locations(file_name_1, file_name_2, line_number_1, line_number_2)
      end
    end

    def compare_locations(file_name_1, file_name_2, line_number_1, line_number_2)
      if earlier_file(file_name_1, file_name_2) ||
         same_file_earlier_line(file_name_1, file_name_2, line_number_1, line_number_2)
        -1
      elsif later_file(file_name_1, file_name_2) ||
            same_file_later_line(file_name_1, file_name_2, line_number_1, line_number_2)
        1
      else
        0
      end
    end

    def earlier_file(file_name_1, file_name_2)
      (file_name_1 < file_name_2)
    end

    def same_file_earlier_line(file_name_1, file_name_2, line_number_1, line_number_2)
      (file_name_1 == file_name_2) && (line_number_1 < line_number_2)
    end

    def later_file(file_name_1, file_name_2)
      (file_name_1 > file_name_2)
    end

    def same_file_later_line(file_name_1, file_name_2, line_number_1, line_number_2)
      (file_name_1 == file_name_2) && (line_number_1 > line_number_2)
    end

  end
end