class RuboCop::Cop::Style::RaiseArgs
fail “message”
raise MyCustomError.new(arg1, arg2, arg3)
raise StandardError.new(“message”)
# good
raise RuntimeError, arg1, arg2, arg3
raise StandardError, “message”
# bad
@example EnforcedStyle: compact
raise MyKwArgError.new(key1: val1, key2: val2)
raise MyCustomError.new(arg1, arg2, arg3)
fail “message”
raise StandardError, “message”
# good
raise StandardError.new(“message”)
# bad
@example EnforcedStyle: exploded (default)
passed multiple arguments.
will also suggest constructing error objects when the exception is
The exploded style works identically, but with the addition that it
with more than one argument.
still allow passing just a message, or the construction of an error
to ‘raise`, rather than construct an instance of the error. It will
style (default), it recommends passing the exception class and message
This cop checks the args passed to `fail` and `raise`. For exploded
def acceptable_exploded_args?(args)
def acceptable_exploded_args?(args) # Allow code like `raise Ex.new(arg1, arg2)`. return true if args.size > 1 # Disallow zero arguments. return false if args.empty? arg = args.first # Allow code like `raise Ex.new(kw: arg)`. # Allow code like `raise Ex.new(*args)`. arg.hash_type? || arg.splat_type? end
def autocorrect(node)
def autocorrect(node) replacement = if style == :compact correction_exploded_to_compact(node) else correction_compact_to_exploded(node) end ->(corrector) { corrector.replace(node.source_range, replacement) } end
def check_compact(node)
def check_compact(node) if node.arguments.size > 1 add_offense(node) do opposite_style_detected end else correct_style_detected end end
def check_exploded(node)
def check_exploded(node) return correct_style_detected unless node.arguments.one? first_arg = node.first_argument return unless first_arg.send_type? && first_arg.method?(:new) return if acceptable_exploded_args?(first_arg.arguments) add_offense(node) do opposite_style_detected end end
def correction_compact_to_exploded(node)
def correction_compact_to_exploded(node) exception_node, _new, message_node = *node.first_argument arguments = [exception_node, message_node].compact.map(&:source).join(', ') if node.parent && requires_parens?(node.parent) "#{node.method_name}(#{arguments})" else "#{node.method_name} #{arguments}" end end
def correction_exploded_to_compact(node)
def correction_exploded_to_compact(node) exception_node, *message_nodes = *node.arguments return node.source if message_nodes.size > 1 argument = message_nodes.first.source if node.parent && requires_parens?(node.parent) "#{node.method_name}(#{exception_node.const_name}.new(#{argument}))" else "#{node.method_name} #{exception_node.const_name}.new(#{argument})" end end
def message(node)
def message(node) if style == :compact format(COMPACT_MSG, method: node.method_name) else format(EXPLODED_MSG, method: node.method_name) end end
def on_send(node)
def on_send(node) return unless node.command?(:raise) || node.command?(:fail) case style when :compact check_compact(node) when :exploded check_exploded(node) end end
def requires_parens?(parent)
def requires_parens?(parent) parent.and_type? || parent.or_type? || parent.if_type? && parent.ternary? end