Skip to content

Repository files navigation

rubocop-exception_messages

Ruby Coverage Status

RuboCop cops that standardize the style of raised exception messages, consistent with Ruby's own core and standard library exceptions (e.g. TypeError: no implicit conversion from nil to integer, ArgumentError: wrong number of arguments).

Table of Contents

Rationale

Ruby's built-in exceptions never capitalize or punctuate their messages. This reads naturally when Ruby prints the exception class name, a colon, and the message together in a backtrace (ArgumentError: block is required, not ArgumentError: Block is required.). These cops help keep custom raise messages consistent with that convention.

Installation

Add to your Gemfile:

group :development do
  gem "rubocop-exception_messages", require: false
end

Then require it in your .rubocop.yml:

plugins:
  - rubocop-exception_messages

Cops

All cops recognize both raise Class, "message" and raise Class.new("message") forms. Examples below use the raise Class, "message" form for brevity, except for ExceptionMessages/RequireMessage, where the choice between the two forms matters to the check itself.

ExceptionMessages/Casing

Checks the capitalization of raised exception messages. Defaults to EnforcedStyle: lowercase.

# bad
raise ArgumentError, "Block is required"

# good
raise ArgumentError, "block is required"

Configure EnforcedStyle: uppercase to require the opposite convention instead.

ExceptionMessages/Casing:
  EnforcedStyle: uppercase
# bad
raise ArgumentError, "block is required"

# good
raise ArgumentError, "Block is required"

ExceptionMessages/Punctuation

Checks the trailing punctuation of raised exception messages. Defaults to EnforcedStyle: no_period. A literal ellipsis ("...") is never considered an offense.

# bad
raise ArgumentError, "block is required."

# good
raise ArgumentError, "block is required"

Configure EnforcedStyle: period to require a trailing period instead.

ExceptionMessages/Punctuation:
  EnforcedStyle: period
# bad
raise ArgumentError, "block is required"

# good
raise ArgumentError, "block is required."

Both cops support autocorrection (rubocop -A).

ExceptionMessages/RedundantExceptionName

Checks that raised exception messages do not redundantly repeat the exception class name, since Ruby already prints the class name ahead of the message in a backtrace.

# bad
raise ArgumentError, "ArgumentError: block is required"

# good
raise ArgumentError, "block is required"

ExceptionMessages/QuoteStyle

Checks that interpolated values in raised exception messages are consistently quoted, making it easier to spot where a dynamic value begins and ends in a rendered message. Defaults to EnforcedStyle: backticks.

# bad
raise ArgumentError, "unknown type: #{type}"

# good
raise ArgumentError, "unknown type: `#{type}`"

Configure EnforcedStyle: single_quotes, double_quotes, square_brackets, parentheses, or curly_braces to require a different wrapping instead.

ExceptionMessages/QuoteStyle:
  Enabled: true
  EnforcedStyle: single_quotes
# good
raise ArgumentError, "unknown type: '#{type}'"

Configure EnforcedStyle: custom with Prefix/Suffix for anything else, including a single-sided marker with no closing character.

ExceptionMessages/QuoteStyle:
  Enabled: true
  EnforcedStyle: custom
  Prefix: '?'
# good
raise ArgumentError, "unknown type: ?#{type}"

Prefix/Suffix aren't limited to a single character.

ExceptionMessages/QuoteStyle:
  Enabled: true
  EnforcedStyle: custom
  Prefix: '--'
# good
raise ArgumentError, "unknown type: --#{type}"

Configure EnforcedStyle: none to require interpolated values not be wrapped at all, and flag existing wrapping instead.

ExceptionMessages/QuoteStyle:
  Enabled: true
  EnforcedStyle: none
# bad
raise ArgumentError, "unknown type: `#{type}`"

# good
raise ArgumentError, "unknown type: #{type}"

ExceptionMessages/RequireMessage

Checks that a raised exception is given a message, since a bare raise SomeError produces a backtrace with nothing but the class name to go on.

# bad
raise ArgumentError
raise ArgumentError.new

# good
raise ArgumentError, "block is required"

# good (bare re-raise)
raise

AllowedExceptions exempts exception classes that don't need a message, and defaults to NotImplementedError, since it's conventionally raised bare (e.g. for an abstract method, or a feature unsupported on the current platform).

# good, by default
raise NotImplementedError

RuboCop configuration doesn't merge arrays, it replaces them, so if you configure your own AllowedExceptions, repeat NotImplementedError in the list if you still want it exempted.

ExceptionMessages/RequireMessage:
  Enabled: true
  AllowedExceptions:
    - NotImplementedError
    - MyApp::PluginError
# good
raise NotImplementedError
raise MyApp::PluginError

ExceptionMessages/NoGenericMessage

Checks that a raised exception message provides context by staying within configured character and word limits and not matching a generic message. This catches messages like "invalid" or "failed" by default, as well as messages shorter or longer than the configured limits.

# bad
raise ArgumentError, "invalid"
raise StandardError, "error"
raise RuntimeError, "failed"

# good
raise ArgumentError, "invalid type: `#{type}`"
raise StandardError, "error connecting to the database"
raise RuntimeError, "failed to acquire lock"

MinimumWords defaults to 1. MinimumLength, MaximumLength, and MaximumWords are optional; when configured, messages outside those limits are flagged. GenericMessages is a configurable, case-insensitive list of exact messages that are always flagged, even when they meet the length limits. Entries written as /pattern/flags are treated as regular expressions.

ExceptionMessages/NoGenericMessage:
  Enabled: true
  MaximumLength: 200
  MinimumWords: 1
  MaximumWords: 30
  GenericMessages:
    - bad
    - error
    - failed
    - invalid
    - not found
    - '/^operation (failed|aborted)$/i'

Use Exceptions to override the global settings for a particular exception class. Fully qualified names and short names are supported; per-exception values replace the corresponding global setting.

ExceptionMessages/NoGenericMessage:
  MinimumLength: 1
  GenericMessages:
    - bad
    - error
  Exceptions:
    ArgumentError:
      MinimumLength: 10
      MaximumLength: 100
      MinimumWords: 3
      MaximumWords: 20
      GenericMessages:
        - bad argument
        - '/^invalid argument/i'
# bad
raise ArgumentError, "nope"

To require more context, increase MinimumLength:

ExceptionMessages/NoGenericMessage:
  MinimumLength: 20
  MaximumLength: 200
  MinimumWords: 3
  MaximumWords: 30

Contributing

See CONTRIBUTING.md.

Copyright and License

MIT License, see LICENSE for details.

About

RuboCop cops that standardize the style of raised exception messages

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages