sds/lint-trappings

View on GitHub
lib/lint_trappings/errors.rb

Summary

Maintainability
A
55 mins
Test Coverage
# Collection of errors that can be raised by the framework.
module LintTrappings
  # Abstract error. Separates LintTrappings errors from other kinds of
  # errors in the exception hierarchy.
  #
  # @abstract
  class LintTrappingsError < StandardError
    # Returns the status code that should be output if this error goes
    # unhandled.
    #
    # Ideally these should resemble exit codes from the sysexits documentation
    # where it makes sense.
    def self.exit_status(*args)
      if args.any?
        @exit_status = args.first
      elsif @exit_status
        @exit_status
      else
        ancestors.each do |ancestor|
          return 70 if ancestor == LintTrappingsError # No exit status defined
          return ancestor.exit_status if ancestor.exit_status
        end
      end
    end

    def exit_status
      self.class.exit_status
    end
  end

  # Superclass of all configuration-related errors.
  # @abstract
  class ConfigurationError < LintTrappingsError
    exit_status 78 # EX_CONFIG
  end

  # Raised when a LintTrappings::Application subclass does not set a value for a
  # required configuration attribute.
  class ApplicationConfigurationError < ConfigurationError; end

  # Raised when a configuration file could not be parsed.
  class ConfigurationParseError < ConfigurationError; end

  # Raised when configuration file was not found.
  class NoConfigurationFileError < ConfigurationError; end

  # Raised when a linter's configuration does not match its specification.
  class LinterConfigurationError < ConfigurationError; end

  # Superclass of all usage-related errors
  # @abstract
  class UsageError < LintTrappingsError
    exit_status 64 # EX_USAGE
  end

  # Raised when there was a problem loading a formatter.
  class FormatterLoadError < UsageError; end

  # Raised when invalid/incompatible command line options are specified.
  class InvalidCliOptionError < UsageError; end

  # Raised when invalid command was specified.
  class InvalidCommandError < UsageError; end

  # Raised when an invalid file path is specified.
  class InvalidFilePathError < UsageError; end

  # Raised when an invalid file glob pattern is specified.
  class InvalidFilePatternError < UsageError; end

  # Raised when an invalid option specification is specified for a linter.
  class InvalidOptionSpecificationError < ConfigurationError; end

  # Raised when a linter raises an unexpected error.
  class LinterError < LintTrappingsError; end

  # Raised when an error occurs loading a linter file.
  class LinterLoadError < ConfigurationError; end

  # Raised when an external preprocessor command returns a non-zero exit status.
  class PreprocessorError < LintTrappingsError
    exit_status 84
  end

  # Raised when a report contains lints which qualify as warnings, but does not
  # contain failures.
  class ScanWarned < LintTrappingsError
    exit_status 0 # Don't fail for warnings
  end

  # Raised when a report contains lints which qualify as failures.
  class ScanFailed < LintTrappingsError
    exit_status 2
  end

  # Raised when running with options that would result in no linters being
  # enabled.
  class NoLintersError < ConfigurationError; end

  # Raised when a specified linter does not exist.
  class NonExistentLinter < ConfigurationError; end

  # Raised when there was a problem parsing a document.
  class ParseError < LintTrappingsError
    # @return [String] path to the file that failed to parse
    attr_reader :path

    # @return [Range<LintTrappings::Location>] source range of the parse error
    attr_reader :source_range

    # @param options [Hash]
    # @option options :message [String]
    # @option options :path [String]
    # @option options :source_range [Range<LintTrappings::Location>]
    def initialize(options)
      @message = options[:message]
      @path = options[:path]

      if @source_range = options[:source_range]
        @line = @source_range.begin.line
        @column = @source_range.begin.column
      end
    end

    def message
      msg = @message
      msg << " on line #{@line}" if @line
      msg << ", column #{@column}" if @column
      msg
    end
  end
end