rubocop-exception_messages
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
- Installation
- Cops
- ExceptionMessages/Casing
- ExceptionMessages/Punctuation
- ExceptionMessages/RedundantExceptionName
- ExceptionMessages/QuoteStyle
- ExceptionMessages/RequireMessage
- ExceptionMessages/NoGenericMessage
- Contributing
- Copyright and License
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
endThen require it in your .rubocop.yml:
plugins:
- rubocop-exception_messagesCops
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)
raiseAllowedExceptions 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 NotImplementedErrorRuboCop 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::PluginErrorExceptionMessages/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: 30Contributing
See CONTRIBUTING.md.
Copyright and License
MIT License, see LICENSE for details.