Nothing
#' @include internals.R
NULL
#' @include utils.R
NULL
#' Function Checks
#'
#' A set of tiny functions to check that functions adhere to a layout style.
#' A function should have a clear layout, it should
#' \itemize{
#' \item not have too many arguments,
#' \item not have too many levels of nesting,
#' \item neither have too many lines nor
#' \item have too many lines of code,
#' \item not have lines too wide and
#' \item explicitly \code{\link{return}} an object.
#' }
#'
#' In case of a fail all \code{\link{function_checks}} \code{\link{throw}} a
#' condition of class c("cleanr", "error", "condition").
#'
#' @section Warning: \code{\link{check_return}} just \code{\link{grep}}s for a
#' for a line starting with a \code{\link{return}} statement (ah, see the code
#' for the real thing).
#' This does not ensure that \emph{all} \code{\link{return}} paths from the
#' function are explicit and it may miss a \code{\link{return}} path after a
#' semicolon.
#' It just checks if you use \code{\link{return}} at all.
#'
#' @param object The function to be checked.
#' Should have been sourced with keep.source = TRUE (see
#' \code{\link{get_function_body}}).
#' @template return_invisibly_true_see_details
#' @name function_checks
#' @examples
#' print(cleanr::check_num_arguments(cleanr::check_num_arguments))
#' print(cleanr::check_nesting_depth(cleanr::check_nesting_depth))
#' print(cleanr::check_num_lines(cleanr::check_num_lines))
#' print(cleanr::check_num_lines_of_code(cleanr::check_num_lines_of_code))
#' print(cleanr::check_return(cleanr::check_return))
#' # R reformats functions on import (see
#' # help(get_function_body, package = "cleanr")), so we need 90 characters:
#' print(cleanr::check_line_width(cleanr::check_line_width,
#' max_line_width = 90))
NULL
#' @rdname function_checks
#' @param max_num_arguments The maximum number of arguments accepted.
#' Set (preferably via \code{\link{set_cleanr_options}}) to \code{NULL} or
#' \code{FALSE} to disable the check.
#' @export
#' @family check functions
check_num_arguments <- function(object,
max_num_arguments = gco("max_num_arguments")) {
if (is_not_false(max_num_arguments, where = environment())) {
checkmate::checkFunction(object)
checkmate::qassert(max_num_arguments, "N1")
num_arguments <- length(formals(object))
if (num_arguments > max_num_arguments)
throw(paste("found", num_arguments,
"arguments, max_num_arguments was", max_num_arguments))
}
return(invisible(TRUE))
}
#' @rdname function_checks
#' @param max_nesting_depth The maximum nesting depth accepted.
#' Set (preferably via \code{\link{set_cleanr_options}}) to \code{NULL} or
#' \code{FALSE} to disable the check.
#' @export
check_nesting_depth <- function(object,
max_nesting_depth = gco("max_nesting_depth")) {
if (is_not_false(max_nesting_depth, where = environment())) {
checkmate::checkFunction(object)
checkmate::qassert(max_nesting_depth, "N1")
function_body <- get_function_body(object)
# break if no braces in function
if (!any(grepl("}", function_body, fixed = TRUE)))
return(invisible(TRUE))
braces <- paste(gsub("\\", "",
gsub("[^\\{\\}]", "", function_body),
fixed = TRUE),
collapse = "")
consectutive_openings <- strsplit(braces, "}",
fixed = TRUE)[[1]]
nesting_depths <- nchar(consectutive_openings)
nesting_depth <- max(nesting_depths)
if (nesting_depth > max_nesting_depth)
throw(paste0("found nesting depth ", nesting_depth,
", max_nesting_depth was ", max_nesting_depth))
}
return(invisible(TRUE))
}
#' @rdname function_checks
#' @param max_lines The maximum number of lines accepted.
#' Set (preferably via \code{\link{set_cleanr_options}}) to \code{NULL} or
#' \code{FALSE} to disable the check.
#' @export
check_num_lines <- function(object, max_lines = gco("max_lines")) {
if (is_not_false(max_lines, where = environment())) {
checkmate::checkFunction(object)
checkmate::qassert(max_lines, "N1")
function_body <- get_function_body(object)
num_lines <- length(function_body)
if (num_lines > max_lines)
throw(paste("found", num_lines, "lines, max_lines was", max_lines))
}
return(invisible(TRUE))
}
#' @rdname function_checks
#' @param max_lines_of_code The maximum number of lines of code accepted.
#' Set (preferably via \code{\link{set_cleanr_options}}) to \code{NULL} or
#' \code{FALSE} to disable the check.
#' @export
check_num_lines_of_code <- function(object,
max_lines_of_code =
gco("max_lines_of_code")) {
if (is_not_false(max_lines_of_code, where = environment())) {
checkmate::checkFunction(object)
checkmate::qassert(max_lines_of_code, "N1")
function_body <- get_function_body(object)
line_is_comment_pattern <- "^\\s*#"
lines_of_code <- grep(line_is_comment_pattern, function_body,
value = TRUE, invert = TRUE)
num_lines_of_code <- length(lines_of_code)
if (num_lines_of_code > max_lines_of_code)
throw(paste("found", num_lines_of_code,
"lines of code, max_lines_of_code was",
max_lines_of_code))
}
return(invisible(TRUE))
}
#' @rdname function_checks
#' @param max_line_width The maximum line width accepted.
#' Set (preferably via \code{\link{set_cleanr_options}}) to \code{NULL} or
#' \code{FALSE} to disable the check.
#' @export
check_line_width <- function(object,
max_line_width = gco("max_line_width")) {
if (is_not_false(max_line_width, where = environment())) {
checkmate::checkFunction(object)
checkmate::qassert(max_line_width, "N1")
function_body <- get_function_body(object)
line_widths <- nchar(function_body)
if (any(line_widths > max_line_width)) {
long_lines_index <- line_widths > max_line_width
long_lines <- seq(along = function_body)[long_lines_index]
throw(paste("line ", long_lines, ": found width ",
line_widths[long_lines_index], " max_line_width was ",
max_line_width,
sep = "", collapse = "\n")
)
}
}
return(invisible(TRUE))
}
#' @rdname function_checks
#' @param check_return
#' Set (preferably via \code{\link{set_cleanr_options}}) to \code{NULL} or
#' \code{FALSE} to disable the check.
#' @export
check_return <- function(object,
check_return = gco("check_return")) {
if (is_not_false(check_return, where = environment())) {
checkmate::checkFunction(object)
message_string <- paste("Just checking for a line starting with a ",
"return statement.\n",
"This is no check for all return paths ",
"being explicit.")
warning(message_string)
checkmate::checkFunction(object)
function_body <- body(object) # body gives us the statements line
# by line, some_command; return(somewhat) will be matched
# by: ^\\s*return\\(
if (! any(grepl("^\\s*return\\(", function_body)))
throw("found no return() statement at all.")
}
return(invisible(TRUE))
}
#' File Checks
#'
#' A set of tiny functions to check that files adhere to a layout style.
#' A file should have a clear layout, it should
#' \itemize{
#' \item not have too many lines and
#' \item not have lines too wide.
#' }
#'
#' In case of a fail all \code{\link{file_checks}} \code{\link{throw}} a
#' condition of class c("cleanr", "error", "condition").
#'
#'
#' @param path Path to the file to be checked.
#' @return \code{\link[base:invisible]{Invisibly}} \code{\link{TRUE}},
#' but see \emph{Details}.
#' @name file_checks
#' @family check functions
#' @examples
#' print(cleanr::check_file_width(system.file("source", "R", "checks.R",
#' package = "cleanr")))
#' print(cleanr::check_file_length(system.file("source", "R", "checks.R",
#' package = "cleanr"),
#' max_file_length = 300))
NULL
#' @rdname file_checks
#' @param max_file_width The maximum line width accepted.
#' Set (preferably via \code{\link{set_cleanr_options}}) to \code{NULL} or
#' \code{FALSE} to disable the check.
#' @export
check_file_width <- function(path,
max_file_width = gco("max_file_width")) {
if (is_not_false(max_file_width, where = environment())) {
checkmate::qassert(path, "S1")
checkmate::qassert(max_file_width, "N1")
file_content <- readLines(path)
line_widths <- nchar(file_content)
if (any(line_widths > max_file_width)) {
long_lines_index <- line_widths > max_file_width
throw(paste0(path, ": line ",
seq(along = file_content)[long_lines_index],
" counts ", line_widths[long_lines_index],
" characters.",
collapse = "\n")
)
}
}
return(invisible(TRUE))
}
#' @rdname file_checks
#' @param max_file_length The maximum number of lines accepted.
#' Set (preferably via \code{\link{set_cleanr_options}}) to \code{NULL} or
#' \code{FALSE} to disable the check.
#' @export
check_file_length <- function(path,
max_file_length = gco("max_file_length")) {
if (is_not_false(max_file_length, where = environment())) {
checkmate::qassert(path, "S1")
checkmate::qassert(max_file_length, "N1")
file_content <- readLines(path)
num_lines <- length(file_content)
if (num_lines > max_file_length) {
throw(paste0(path, ": ", num_lines, " lines in file.",
collapse = "\n"))
}
}
return(invisible(TRUE))
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.