#' Throw informative error messages
#'
#' Helpers to generate readable and informative error messages for package
#' users.
#' @param \dots arguments to be passed to \code{fmt}
#' @param call the calling context from which the error is raised
#' @param subclass an optional subclass name for the error condition to be
#' raised
#'
#' @details
#' For \code{rethrow}, the \code{call} argument overrides the rethrown error’s
#' own stored call.
#' @keywords internal
throw = function (..., call = sys.call(sys.parent()), subclass = NULL) {
message = fmt(..., envir = parent.frame())
stop(box_error(message, call = call, subclass = subclass))
}
#' @param error an object of class \code{c("error", "condition")} to rethrow
#' @rdname throw
rethrow = function (error, call = sys.call(sys.parent())) {
if (inherits(error, 'box_error')) {
# R calls all exit handlers during stack unwind after internally setting
# the stack traceback. We use this fact to override the traceback with a
# more useful version that shows the actual calls causing the error,
# instead of the detour via the `rethrow` logic.
on.exit({
# In non-interactive sessions, `.Traceback` might not be created.
if (exists('.Traceback', .BaseNamespaceEnv)) {
# In all versions of R currently supported, `tryCatch` inserts 4
# calls into the call stack, which we excise here.
tb = error$traceback
start = Position(function (x) x[[1L]] %==% quote(rethrow_on_error), tb)
tb = tb[- seq(start + 1L, start + 4L)]
if (getRversion() < '4.0.0') {
# Prior to R 4.0.0, `.Traceback` contains deparsed calls.
tb = map(deparse1, tb)
}
if (getRversion() >= '4.1.0') box_unlock_binding('.Traceback', .BaseNamespaceEnv)
.BaseNamespaceEnv$.Traceback = tb
if (getRversion() >= '4.1.0') lockBinding('.Traceback', .BaseNamespaceEnv)
}
})
}
message = conditionMessage(error)
subclass = setdiff(class(error), box_error_class)
stop(box_error(message, call = call, subclass = subclass))
}
#' @param expr an expression to evaluate inside \code{tryCatch}
#' @return If it does not throw an error, \code{rethrow_on_error} returns the
#' value of evaluating \code{expr}.
#' @rdname throw
rethrow_on_error = function (expr, call = sys.call(sys.parent())) {
tryCatch(expr, error = function (error) rethrow(error, call))
}
expect = function (condition, ..., call = sys.call(sys.parent()), subclass = NULL) {
if (condition) return()
message = fmt(..., envir = parent.frame())
stop(box_error(message, call = call, subclass = subclass))
}
box_error_class = c('box_error', 'error', 'condition')
#' @param message the error message
#' @return \code{box_error} returns a new \sQuote{box} error condition object
#' with a given message and call, and optionally a given subclass type.
#' @rdname throw
box_error = function (message, call = NULL, subclass = NULL) {
class = c(subclass, box_error_class)
# Store real traceback, in case this is being called from inside
# `rethrow_on_error`, which overrides the stack trace.
traceback = sys.calls()
traceback = traceback[seq_len(length(traceback) - 2L)]
structure(list(message = message, call = call, traceback = traceback), class = class)
}
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.