diff --git a/DESCRIPTION b/DESCRIPTION
index 79e9273..2e678b7 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -2,12 +2,28 @@ Package: kwb.code
Title: Analyse Your R Code!
Version: 0.3.0
Authors@R: c(
- person("Hauke", "Sonnenberg", , "hauke.sonnenberg@kompetenz-wasser.de", role = c("aut", "cre"),
- comment = c(ORCID = "0000-0001-9134-2871")),
- person("Michael", "Rustler", , "michael.rustler@kompetenz-wasser.de", role = "ctb",
- comment = "0000-0003-0647-7726"),
- person("FAKIN", role = "fnd"),
- person("Kompetenzzentrum Wasser Berlin gGmbH (KWB)", role = "cph")
+ person(
+ given = "Hauke",
+ family = "Sonnenberg",
+ email = "hauke.sonnenberg@kompetenz-wasser.de",
+ role = c("aut", "cre"),
+ comment = c(ORCID = "0000-0001-9134-2871")
+ ),
+ person(
+ given = "Michael",
+ family = "Rustler",
+ email = "michael.rustler@kompetenz-wasser.de",
+ role = "ctb",
+ comment = "0000-0003-0647-7726"
+ ),
+ person(
+ given = "FAKIN",
+ role = "fnd"
+ ),
+ person(
+ given = "Kompetenzzentrum Wasser Berlin gGmbH (KWB)",
+ role = "cph"
+ )
)
Description: This package allows you to parse your R scripts and to
calculate some staticstics on your code.
@@ -18,6 +34,7 @@ Imports:
dplyr,
kwb.file,
kwb.utils,
+ magrittr,
stringr
Suggests:
covr,
@@ -33,4 +50,4 @@ ByteCompile: true
Config/testthat/edition: 3
Encoding: UTF-8
LazyData: true
-RoxygenNote: 7.2.3
+RoxygenNote: 7.3.1
diff --git a/NAMESPACE b/NAMESPACE
index c95360a..6d968fa 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -1,38 +1,54 @@
# Generated by roxygen2: do not edit by hand
+export("%>%")
export(analyse)
export(arg_names)
+export(find_function_name_duplicates)
export(find_string_constants)
export(find_weaknesses_in_scripts)
export(get_elements_by_type)
export(get_full_function_info)
+export(get_function_assignments)
export(get_names_of_used_packages)
export(get_package_function_usage)
export(get_package_usage_per_script)
export(get_string_constants_in_scripts)
+export(normalise_expression)
export(parse_scripts)
export(to_full_script_info)
export(walk_tree)
-importFrom(dplyr,bind_rows)
+importFrom(kwb.utils,backspace)
importFrom(kwb.utils,catAndRun)
importFrom(kwb.utils,catIf)
+importFrom(kwb.utils,checkForMissingColumns)
+importFrom(kwb.utils,collapsed)
importFrom(kwb.utils,commaCollapsed)
importFrom(kwb.utils,createDirectory)
+importFrom(kwb.utils,defaultIfNULL)
+importFrom(kwb.utils,excludeNULL)
importFrom(kwb.utils,extractSubstring)
-importFrom(kwb.utils,hsQuoteChr)
+importFrom(kwb.utils,getAttribute)
+importFrom(kwb.utils,hsOpenWindowsExplorer)
+importFrom(kwb.utils,isTryError)
+importFrom(kwb.utils,left)
importFrom(kwb.utils,matchesCriteria)
importFrom(kwb.utils,moveColumnsToFront)
importFrom(kwb.utils,multiSubstitute)
importFrom(kwb.utils,noFactorDataFrame)
+importFrom(kwb.utils,pairwise)
importFrom(kwb.utils,printIf)
importFrom(kwb.utils,rbindAll)
importFrom(kwb.utils,removeAttributes)
+importFrom(kwb.utils,removeColumns)
importFrom(kwb.utils,removeEmptyColumns)
importFrom(kwb.utils,renameColumns)
importFrom(kwb.utils,resetRowNames)
importFrom(kwb.utils,safeRowBindAll)
importFrom(kwb.utils,selectColumns)
importFrom(kwb.utils,selectElements)
+importFrom(kwb.utils,shorten)
+importFrom(kwb.utils,stopFormatted)
+importFrom(kwb.utils,stringList)
+importFrom(magrittr,"%>%")
importFrom(stats,aggregate)
-importFrom(stats,setNames)
importFrom(stringr,str_extract_all)
diff --git a/NEWS.md b/NEWS.md
index 22ff876..f3aa967 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,7 @@
+# Latest Changes
+
+* Add normalise_expression()
+
# [kwb.code 0.3.0](https://github.com/KWB-R/kwb.code/releases/tag/v0.3.0) 2023-07-15
* repair GitHub Actions
diff --git a/R/analyse.R b/R/analyse.R
index f4f140a..c8f72d8 100644
--- a/R/analyse.R
+++ b/R/analyse.R
@@ -17,22 +17,65 @@
#' str(result, 3)
analyse <- function(x, path = "")
{
- info <- type_info(x)
-
- # result <- list(
- # self = info_to_text(info)
- # )
-
- result <- info
+ result <- type_info(x)
+ result[["fulltype"]] <- info_to_text(result)
result[["path"]] <- path
- result[["fulltype"]] <- info_to_text(info)
if (is.recursive(x)) {
-
result[["children"]] <- lapply(seq_along(x), function(i) {
- analyse(x[[i]], path = paste(path, i, sep = "/"))
+ analyse(x[[i]], path = paste0(path, "/", i))
})
}
result
}
+
+# type_info --------------------------------------------------------------------
+type_info <- function(x, as_character = FALSE)
+{
+ shorten <- function(x) paste(substr(x, 1, 30), "...")
+
+ text <- as.character(x)
+ mode_x <- mode(x)
+ class_x <- class(x)
+
+ info <- list(
+ type = typeof(x),
+ mode = mode_x,
+ class = class_x,
+ length = length(x),
+ text = shorten(paste0("[", seq_along(text), "]", text, collapse = "")),
+ is = is_what(x),
+ n_modes = length(mode_x),
+ n_classes = length(class_x)
+ )
+
+ if (as_character) {
+ info_to_text(info)
+ } else {
+ info
+ }
+}
+
+# info_to_text -----------------------------------------------------------------
+info_to_text <- function(info)
+{
+ collapse <- function(element) {
+ select_elements(info, element) %>%
+ comma_collapsed()
+ }
+
+ #prefix <- "type|mode|class|length|is: "
+ prefix <- NULL
+
+ paste0(
+ prefix,
+ paste(collapse = "|", c(
+ collapse("type"),
+ collapse("mode"),
+ collapse("class"),
+ collapse("length"),
+ collapse("is")
+ ))
+ )
+}
diff --git a/R/duplicatesToFiles.R b/R/duplicatesToFiles.R
index fb782a5..d7a1c4a 100644
--- a/R/duplicatesToFiles.R
+++ b/R/duplicatesToFiles.R
@@ -1,27 +1,59 @@
# duplicatesToFiles ------------------------------------------------------------
-#' @importFrom kwb.utils catIf
-#' @importFrom kwb.utils createDirectory
-#' @importFrom kwb.utils selectColumns
-#' @importFrom kwb.utils selectElements
duplicatesToFiles <- function
(
- trees, fun_duplicates, function_name, target_root = tempdir(), dbg = TRUE,
+ trees,
+ fun_duplicates = NULL,
+ function_name = NULL,
+ target_root = tempdir(),
+ dbg = TRUE,
write.all = FALSE
-) {
-
- selected <- selectColumns(fun_duplicates, "functionName") == function_name
+)
+{
+ if (is.null(fun_duplicates)) {
+ fun_duplicates <- get_info_on_duplicated_function_names(trees)
+ }
+
+ if (nrow(fun_duplicates) == 0L) {
+ message("No duplications given or no duplications found.")
+ return()
+ }
+
+ function_names <- select_columns(fun_duplicates, "functionName")
+
+ # Call this function for each function name if no function name is given
+ if (is.null(function_name)) {
+
+ message("No function name given.")
+
+ lapply(unique(function_names), function(function_name) {
+ #function_name <- unique(function_names)[1L]
+ cat_and_run(
+ sprintf(
+ "Calling duplicatesToFiles(..., function_name = \"%s\")",
+ function_name
+ ),
+ duplicatesToFiles(trees, fun_duplicates, function_name),
+ newLine = 3L
+ )
+ })
+ }
- scripts <- as.character(selectColumns(fun_duplicates[selected, ], "script"))
+ # Script files that contain a function
+ scripts <- fun_duplicates[function_names == function_name, ] %>%
+ selectColumns("script") %>%
+ as.character()
- function_defs <- lapply(scripts, function(script) {
- extract_function_definition(selectElements(trees, script), function_name)
+ # From each script, extract the definition of function
+ function_defs <- lapply(stats::setNames(nm = scripts), function(script) {
+ trees %>%
+ select_elements(script) %>%
+ extract_function_definition(function_name)
})
-
- names(function_defs) <- scripts
-
- target_dir <- file.path(target_root, "clean", function_name)
- target_dir <- createDirectory(target_dir, dbg = FALSE)
-
+
+ target_dir <- target_root %>%
+ file.path("clean", function_name) %>%
+ create_directory(dbg = FALSE)
+
contents <- lapply(function_defs, function(x) deparse(x[[3L]]))
# Write one file per function definition
@@ -30,36 +62,46 @@ duplicatesToFiles <- function
}
# Write one file per unique function definition
- n_files <- writeContentsToLessFiles(
+ files <- writeContentsToLessFiles(
contents, target_dir, function_name, dbg = dbg
)
- if (n_files != length(contents)) {
+ if (length(files) != length(contents)) {
message("There are identical definitions for ", function_name)
}
- target_dir
+ files
}
-# extract_function_definition --------------------------------------------------
-extract_function_definition <- function(tree, function_name) {
-
- tree <- tree[sapply(tree, is_function_assignment)]
+# get_info_on_duplicated_function_names ----------------------------------------
+get_info_on_duplicated_function_names <- function(trees)
+{
+ result <- get_full_function_info(trees)
+ result[selectColumns(result, "n.def") > 1L, ]
+}
- fnames <- sapply(tree, function(x) split_function_assignment(x)$functionName)
+# extract_function_definition --------------------------------------------------
+extract_function_definition <- function(tree, function_name)
+{
+ fnames <- tree[sapply(tree, is_function_assignment)] %>%
+ sapply(function(x) split_function_assignment(x)$functionName)
index <- which(fnames == function_name)
n_defs <- length(index)
if (n_defs == 0L) {
- stop("No such function: '", function_name, "' defined in the given tree")
+ stop_formatted(
+ "No such function: '%s' defined in the given tree",
+ function_name
+ )
}
-
+
if (n_defs > 1L) {
- warning(
- "The function '", function_name, "' is defined multiple times in ",
- "the given tree. I return the first definition!"
+ warn_formatted(
+ "The function '%s' is defined multiple times in ",
+ "the given tree. I return the first definition!",
+ function_name
)
}
diff --git a/R/extract_from_parse_tree.R b/R/extract_from_parse_tree.R
index e743d43..0b05d8b 100644
--- a/R/extract_from_parse_tree.R
+++ b/R/extract_from_parse_tree.R
@@ -18,76 +18,93 @@
#' @param index for internal use
#' @return vector of character or \code{NULL}
extract_from_parse_tree <- function(
- x, matches = matches_function, dbg = FALSE, path = integer(), parent = NULL,
- index = -1
-) {
-
+ x,
+ matches = matches_function,
+ dbg = FALSE,
+ path = integer(),
+ parent = NULL,
+ index = -1
+)
+{
if (is.null(matches) || ! is.function(matches)) {
- stop(call. = FALSE, "Please give a function in argument 'matches'")
+ stop_formatted("Please give a function in argument 'matches'")
}
+ # If this function is called with a list of parse trees, call the function for
+ # each list element
if (is.list(x) && length(path) == 0L) {
+
return(lapply(
- x, extract_from_parse_tree, matches, dbg, path, parent, index
+ X = x,
+ FUN = extract_from_parse_tree,
+ matches = matches,
+ dbg = dbg,
+ path = path,
+ parent = parent,
+ index = index
))
}
-
- kwb.utils::catIf(dbg, sprintf(
+
+ cat_if(dbg, sprintf(
"[[%s]]: %s\n",
- kwb.utils::commaCollapsed(path),
+ comma_collapsed(path),
utils::capture.output(utils::str(x))
))
-
+
# Is the current element wanted? If yes, store this element
element <- if (wanted <- matches(x, parent, index)) {
- kwb.utils::getAttribute(wanted, "name")
+ get_attribute(wanted, "name")
} # else NULL implicitly
-
- # Do we have to climb further branches up?
- if (is.expression(x) || is.list(x) || length(x) > 1L) {
-
- c(element, unlist(lapply(seq_along(x), function(i) extract_from_parse_tree(
- x = x[[i]], matches = matches, dbg = dbg, path = c(path, i),
- parent = x, index = i
- ))))
-
- } else {
-
- element
+
+ # Do we have to climb further branches up?
+ is_recursive <- is.expression(x) || is.list(x) || length(x) > 1L
+
+ if (!is_recursive) {
+ return(element)
}
+
+ # Call this function recursively
+ more_elements <- seq_along(x) %>%
+ lapply(function(i) {
+ extract_from_parse_tree(
+ x = x[[i]],
+ matches = matches,
+ dbg = dbg,
+ path = c(path, i),
+ parent = x,
+ index = i
+ )
+ }) %>%
+ unlist()
+
+ c(element, more_elements)
}
# matches_function -------------------------------------------------------------
matches_function <- function(
- x, parent = NULL, index, exclude = base_functions()
+ x, parent = NULL, index, exclude = base_functions()
)
{
- if (! is.call(x)) {
+ if (!is.call(x) || (is.call(parent) && index == 1L)) {
return(FALSE)
}
- if (is.call(parent) && index == 1L) {
- return(FALSE)
- }
-
name <- as.character(x[[1L]])
n <- length(name)
- if (! (n == 1L || n == 3L)) {
-
- message(sprintf(
+ if (!(n == 1L || n == 3L)) {
+ message_formatted(
"Not expected: n = %d, str(x) = %s",
n, utils::capture.output(utils::str(x))
- ))
-
+ )
return(FALSE)
}
if (n == 3L) {
name <- paste(name[c(2L, 1L, 3L)], collapse = "")
}
-
+
if (name %in% exclude) {
return(FALSE)
}
diff --git a/R/filter_scripts.R b/R/filter_scripts.R
new file mode 100644
index 0000000..8e0daa1
--- /dev/null
+++ b/R/filter_scripts.R
@@ -0,0 +1,14 @@
+# filter_scripts ---------------------------------------------------------------
+filter_scripts <- function(scriptInfo, fun.min = 5, epf.min = 10)
+{
+ keep <- matches_criteria(
+ Data = scriptInfo,
+ criteria = c(
+ paste("fun >=", fun.min),
+ paste("epf >=", epf.min)
+ )
+ )
+
+ scriptInfo[keep, ] %>%
+ remove_empty_columns()
+}
diff --git a/R/find_function_name_duplicates.R b/R/find_function_name_duplicates.R
new file mode 100644
index 0000000..ae1cc43
--- /dev/null
+++ b/R/find_function_name_duplicates.R
@@ -0,0 +1,20 @@
+# find_function_name_duplicates ------------------------------------------------
+
+#' Find Duplicated Function Names
+#'
+#' @param rscripts full paths to R scripts. By default, the paths to all files
+#' with file name extension ".R" in the "R" subfolder of the current directory
+#' (if it exists) are used here
+#' @returns vector of character with the names of functions that were defined
+#' at least twice
+#' @export
+find_function_name_duplicates <- function(
+ rscripts = dir("./R", pattern = "\\.R$", full.names = TRUE)
+)
+{
+ assignments <- lapply(rscripts, get_function_assignments)
+
+ function_names <- unlist(lapply(assignments, names))
+
+ function_names[duplicated(function_names)]
+}
diff --git a/R/find_string_constants.R b/R/find_string_constants.R
index 8527cbb..9cebe35 100644
--- a/R/find_string_constants.R
+++ b/R/find_string_constants.R
@@ -1,10 +1,10 @@
#' Show String Constants Used in R Scripts
#'
-#' @param root path from which to look recursively for R scripts
+#' @param root path from which to look recursively for R scripts. Default: "./R"
#' @export
find_string_constants <- function(root = "./R")
{
- kwb.file::add_file_info(get_string_constants_in_scripts(
- root = root, FUN = fetch_string_constants_2
- ))
+ root %>%
+ get_string_constants_in_scripts(FUN = fetch_string_constants_2) %>%
+ kwb.file::add_file_info()
}
diff --git a/R/find_weaknesses_in_scripts.R b/R/find_weaknesses_in_scripts.R
index 4b7dea0..3b50698 100644
--- a/R/find_weaknesses_in_scripts.R
+++ b/R/find_weaknesses_in_scripts.R
@@ -21,13 +21,14 @@ find_weaknesses_in_scripts <- function(
)
{
is_expression <- sapply(x, is.expression)
- is_error <- sapply(x, kwb.utils::isTryError)
+ is_error <- sapply(x, is_try_error)
stopifnot(all(is_expression | is_error))
# Remove scripts that could not be parsed by setting elements to NULL first
+ # and excluding NULL second (just to use its reporting)
x[is_error] <- lapply(which(is_error), function(i) NULL)
- x <- kwb.utils::excludeNULL(x)
+ x <- exclude_null(x)
results <- list(
find_code_snippets(
@@ -65,11 +66,13 @@ find_weaknesses_in_scripts <- function(
)
strings <- find_code_snippets(x, is.character, "check for duplicated strings")
+
+ nchars <- nchar(as.character(strings$expression))
is_relevant <-
- nchar(as.character(strings$expression)) >= min_duplicate_string_length &
+ nchars >= min_duplicate_string_length &
strings$frequency >= min_duplicate_frequency
-
+
if (any(is_relevant)) {
results <- c(results, list(strings[is_relevant, ]))
}
@@ -84,9 +87,9 @@ find_code_snippets <- function(
{
matches <- to_matches_function(check_function, type = type)
- result <- summarise_extracted_matches(
- extract_from_parse_tree(x, matches = matches)
- )
+ result <- x %>%
+ extract_from_parse_tree(matches = matches) %>%
+ summarise_extracted_matches()
if (nrow(result) == 0L) {
return(NULL)
@@ -104,154 +107,34 @@ to_matches_function <- function(check_function, type = "self", max_chars = 50L)
return(FALSE)
}
- structure(
- TRUE,
- name = kwb.utils::shorten(max_chars = max_chars, kwb.utils::collapsed(
- if (identical(type, "self")) {
- deparse(x)
- } else if (identical(type, "element_2")) {
- deparse(x[[2L]])
- } else if (identical(type, "parent")) {
- deparse(parent)
- } else {
- stop("unknown type: ", type)
- }
- ))
- )
- }
-}
-
-# is_logical_constant_false ----------------------------------------------------
-is_logical_constant_false <- function(x, type = "short")
-{
- is_logical_constant(x, type, use_true = FALSE)
-}
-
-# is_logical_constant_true -----------------------------------------------------
-is_logical_constant_true <- function(x, type = "short")
-{
- is_logical_constant(x, type, use_false = FALSE)
-}
-
-# is_logical_constant ----------------------------------------------------------
-is_logical_constant <- function(
- x,
- type = "short",
- use_false = TRUE,
- use_true = TRUE
-)
-{
- if (!is.symbol(x)) {
- return(FALSE)
- }
-
- deparse(x) %in% deparsed_logical_values(type, use_false, use_true)
-}
-
-# deparsed_logical_values ------------------------------------------------------
-deparsed_logical_values <- function(
- type = c("short", "long", "either")[3L],
- use_false = TRUE,
- use_true = TRUE
-)
-{
- values <- c("F", "T", "FALSE", "TRUE")
- use_false_true <- c(use_false, use_true)
-
- if (type == "short") {
- values[1:2][use_false_true]
- } else if (type == "long") {
- values[3:4][use_false_true]
- } else if (type == "either") {
- values[rep(use_false_true, 2L)]
- } else {
- stop("Unknown type: ", type)
- }
-}
-
-# is_colon_seq_1_to_length -----------------------------------------------------
-is_colon_seq_1_to_length <- function(x)
-{
- is_colon_seq_1_to_any(x) &&
- mode(x[[3]]) == "call" &&
- identical(deparse(x[[3]][[1]]), "length")
-}
-
-# is_colon_seq_1_to_variable ---------------------------------------------------
-is_colon_seq_1_to_variable <- function(x)
-{
- is_colon_seq_1_to_any(x) &&
- !is.numeric(x[[3]]) &&
- mode(x[[3]]) != "call"
-}
-
-# is_colon_seq_1_to_any --------------------------------------------------------
-is_colon_seq_1_to_any <- function(x)
-{
- is_colon_seq(x) && identical(x[[2]], 1)
-}
-
-# is_colon_seq -----------------------------------------------------------------
-is_colon_seq <- function(x)
-{
- is.language(x) &&
- length(x) == 3L &&
- is.symbol(x[[1L]]) &&
- identical(as.character(x[[1]]), ":")
-}
-
-# is_bad_function_name ---------------------------------------------------------
-is_bad_function_name <- function(x)
-{
- if (!is_function_assignment(x)) {
- return(FALSE)
- }
-
- function_name <- split_assignment(x)$leftSide
-
- is.name(function_name) &&
- grepl("\\.", deparse(function_name))
-}
-
-
-# is_comparison_with_false -----------------------------------------------------
-is_comparison_with_false <- function(x)
-{
- is_comparison_with_logical(x, use_true = FALSE)
-}
-
-# is_comparison_with_true ------------------------------------------------------
-is_comparison_with_true <- function(x)
-{
- is_comparison_with_logical(x, use_false = FALSE)
-}
-
-# is_comparison_with_logical ---------------------------------------------------
-is_comparison_with_logical <- function(x, use_false = TRUE, use_true = TRUE)
-{
- if (!is.call(x)) {
- return(FALSE)
+ object <- if (identical(type, "self")) {
+ x
+ } else if (identical(type, "element_2")) {
+ x[[2L]]
+ } else if (identical(type, "parent")) {
+ parent
+ } else {
+ stop("unknown type: ", type)
+ }
+
+ name <- deparse(object) %>%
+ collapsed() %>%
+ shorten(max_chars)
+
+ structure(TRUE, name = name)
}
-
- operator <- deparse(x[[1]])
- operator %in% c("==", "!=") && (
- is_logical_constant(x[[2]], type = "either", use_false, use_true) ||
- is_logical_constant(x[[3]], type = "either", use_false, use_true)
- )
}
# summarise_extracted_matches --------------------------------------------------
summarise_extracted_matches <- function(x)
{
- result <- kwb.utils::excludeNULL(x, dbg = FALSE)
-
- result <- lapply(result, function(xx) {
- stats::setNames(
- as.data.frame(table(xx)),
- c("expression", "frequency")
- )
- })
-
- dplyr::bind_rows(result, .id = "file")
+ x %>%
+ exclude_null(dbg = FALSE) %>%
+ lapply(function(y) {
+ table(y) %>%
+ as.data.frame() %>%
+ stats::setNames(c("expression", "frequency"))
+ }) %>%
+ dplyr::bind_rows(.id = "file")
}
diff --git a/R/get_depth_expression.R b/R/get_depth_expression.R
index b9994be..dc0badc 100644
--- a/R/get_depth_expression.R
+++ b/R/get_depth_expression.R
@@ -1,5 +1,4 @@
# get_depth_expression ---------------------------------------------------------
-#' @importFrom kwb.utils hsQuoteChr
get_depth_expression <- function(e)
{
noExpression <- ! is.expression(e)
@@ -7,7 +6,7 @@ get_depth_expression <- function(e)
if (noExpression || length(e) == 0L) {
msg <- if (noExpression) {
- paste("Skipping non-expression of class: ", hsQuoteChr(class(e)))
+ sprintf("Skipping non-expression of class: '%s'", class(e))
} else {
"Skipping expression of legth 0"
}
@@ -21,7 +20,6 @@ get_depth_expression <- function(e)
}
# get_depth_any ----------------------------------------------------------------
-#' @importFrom kwb.utils hsQuoteChr
get_depth_any <- function(x)
{
if (is_assignment(x)) {
@@ -36,7 +34,7 @@ get_depth_any <- function(x)
return (0L)
}
- stop("need to treat object of class: ", kwb.utils::hsQuoteChr(class(x)))
+ stop_formatted("need to treat object of class: '%s'", (class(x)))
}
# get_depth_assignment ---------------------------------------------------------
@@ -121,7 +119,6 @@ get_depth_call_usual <- function(x)
}
# get_depth --------------------------------------------------------------------
-#' @importFrom kwb.utils hsQuoteChr
get_depth <- function(e, depth = 0)
{
if (is_assignment(e)) {
@@ -150,6 +147,6 @@ get_depth <- function(e, depth = 0)
} else {
- message("This must be a class of depth 0: ", hsQuoteChr(class(e)))
+ message_formatted("This must be a class of depth 0: '%s'", class(e))
}
}
diff --git a/R/get_elements_by_type.R b/R/get_elements_by_type.R
index 625a177..5a8eb74 100644
--- a/R/get_elements_by_type.R
+++ b/R/get_elements_by_type.R
@@ -25,28 +25,55 @@
get_elements_by_type <- function(x, result = NULL, dbg = TRUE)
{
if (is.null(result)) {
- kwb.utils::catAndRun(dbg = dbg, "Analysing the parse tree", {
- result <- analyse(x)
- })
+ cat_and_run(
+ "Analysing the parse tree",
+ dbg = dbg,
+ expr = {
+ result <- analyse(x)
+ }
+ )
}
type_paths <- get_paths_to_types(result)
- code_parts <- lapply(type_paths, extract_by_path, x = x)
-
- stats::setNames(code_parts, names(type_paths))
+ type_paths %>%
+ lapply(extract_by_path, x = x) %>%
+ stats::setNames(names(type_paths))
}
# extract_by_path --------------------------------------------------------------
extract_by_path <- function(x, paths)
{
- # Remove leading slash from the type path
- clean_paths <- gsub("^/", "", paths)
+ stopifnot(is.recursive(x))
+
+ paths %>%
+
+ # Split the path strings into vectors of integer
+ split_index_path() %>%
+
+ # Use the segments of the type path as (recursive) list indices
+ lapply(function(indices) {
+ if (length(indices)) {
+ x[[indices]]
+ }
+ })
+}
+
+# split_index_path -------------------------------------------------------------
+split_index_path <- function(x)
+{
+ stopifnot(is.character(x))
+ stopifnot(all(is_index_path(x)))
- # Use the segments of the type path as (recursive) list indices
- lapply(strsplit(clean_paths, "/"), function(indices) {
- if (length(indices)) {
- x[[as.integer(indices)]]
- }
- })
+ x %>%
+ remove_first_and_last_slash() %>%
+ strsplit("/") %>%
+ lapply(as.integer)
+}
+
+# is_index_path ----------------------------------------------------------------
+# @examples is_index_path(c("1", "/1", "/11", "1/2/3"))
+is_index_path <- function(x)
+{
+ grepl("^/?([0-9]+/?)*$", x)
}
diff --git a/R/get_full_function_info.R b/R/get_full_function_info.R
new file mode 100644
index 0000000..37eb883
--- /dev/null
+++ b/R/get_full_function_info.R
@@ -0,0 +1,38 @@
+# get_full_function_info -------------------------------------------------------
+
+#' Get information on function definitions in parsed R scripts
+#'
+#' @param trees list of R script parse trees as provided by
+#' \code{\link{parse_scripts}}
+#' @export
+#' @seealso \code{\link{parse_scripts}}
+get_full_function_info <- function(trees)
+{
+ function_info <- trees %>%
+ lapply(function(tree) {
+ tree %>%
+ get_functions() %>%
+ lapply(FUN = get_function_info) %>%
+ rbind_all()
+ }) %>%
+ rbind_all(nameColumn = "script")
+
+ merge(
+ x = function_info,
+ y = multi_defined_functions(function_info),
+ by = "functionName"
+ ) %>%
+ move_columns_to_front(c("script", "functionName", "n.def"))
+}
+
+# multi_defined_functions ------------------------------------------------------
+multi_defined_functions <- function(functionInfo)
+{
+ count <- stats::aggregate(
+ n.def ~ functionName,
+ cbind(n.def = seq_len(nrow(functionInfo)), functionInfo),
+ length
+ )
+
+ count[order(count$n, decreasing = TRUE), ]
+}
diff --git a/R/get_function_assignments.R b/R/get_function_assignments.R
new file mode 100644
index 0000000..44fb84d
--- /dev/null
+++ b/R/get_function_assignments.R
@@ -0,0 +1,39 @@
+# get_function_assignments -----------------------------------------------------
+
+#' Extract the function assignments from an R script
+#'
+#' @param file path to R script from which function definitions are to be
+#' extracted
+#' @param \dots further arguments passed to \code{\link{parse}}
+#' @return named list of expressions. The names of the list elements represent
+#' the names of the functions that are defined by the expressions in the list.
+#' @export
+get_function_assignments <- function(file, ...)
+{
+ # code <- as.list(parse(file))
+ #
+ # #expr <- code[[2]]
+ #
+ # is_function_assignment <- sapply(code, function(expr) {
+ #
+ # ok <- as.character(expr[[1]]) == "<-"
+ #
+ # ok && length(expr) >= 3 && as.character(expr[[3]][[1]]) == "function"
+ # })
+ #
+ # assignments <- code[is_function_assignment]
+
+ assignments <- parse(file, ...) %>%
+ get_functions() %>%
+ as.list()
+
+ # Get the function names from the assignments
+ # function_names <- sapply(lapply(assignments, "[[", 2L), deparse)
+ # sapply(assignments, function(x) as.character(x[[2]]))
+ function_names <- assignments %>%
+ lapply(split_assignment) %>%
+ lapply(select_elements, "leftSide")
+
+ # Name the assignments according to the function names
+ stats::setNames(assignments, function_names)
+}
diff --git a/R/get_names_of_used_packages.R b/R/get_names_of_used_packages.R
index e9679cf..dd9a979 100644
--- a/R/get_names_of_used_packages.R
+++ b/R/get_names_of_used_packages.R
@@ -5,29 +5,25 @@
#' @param root_dir directory in which to look recursively for R-scripts
#' @param pattern regular expression matching the names of the files to be
#' considered
-#'
-#' @importFrom kwb.utils catAndRun
-#' @importFrom kwb.utils extractSubstring
-#' @importFrom kwb.utils multiSubstitute
-#'
#' @export
-#'
get_names_of_used_packages <- function(root_dir, pattern = "[.][rR](md)?$")
{
script_paths <- list.files(
root_dir, pattern, full.names = TRUE, recursive = TRUE
)
- package_usages <- lapply(script_paths, function(file) catAndRun(
- paste("Analysing", file),
- grep("library", readLines(file), value = TRUE)
- ))
-
+ package_usages <- lapply(script_paths, function(file) {
+ cat_and_run(
+ paste("Analysing", file),
+ grep("library", readLines(file), value = TRUE)
+ )
+ })
+
usage_lines <- sort(unique(unlist(package_usages)))
- package_names <- extractSubstring("library\\(([^)]+)\\)", usage_lines, 1L)
+ package_names <- extract_substring("library\\(([^)]+)\\)", usage_lines, 1L)
- packages <- sort(unique(multiSubstitute(package_names, list(
+ packages <- sort(unique(multi_substitute(package_names, list(
"^\"|\"$" = "",
"[\",].*$" = ""
))))
diff --git a/R/get_package_function_usage.R b/R/get_package_function_usage.R
index 085f453..f1889bf 100644
--- a/R/get_package_function_usage.R
+++ b/R/get_package_function_usage.R
@@ -52,14 +52,13 @@ get_package_function_usage <- function(
result <- stats::aggregate(
. ~ package + name,
- kwb.utils::removeColumns(result, "script"),
+ remove_columns(result, "script"),
sum
)
row_order <- order(result$package, - result$count, result$name)
}
-
- kwb.utils::resetRowNames(result[row_order, ])
+ reset_row_names(result[row_order, ])
}
# get_function_call_frequency --------------------------------------------------
@@ -85,7 +84,7 @@ get_function_call_frequency <- function(tree, simple = FALSE, dbg = TRUE)
if (! all(is_expression)) {
- tree <- kwb.utils::catAndRun(
+ tree <- cat_and_run(
messageText = sprintf(
"Removing %d top level elements from the tree that are not expressions",
sum(! is_expression)
@@ -127,11 +126,11 @@ remove_non_installed_packages <- function(packages)
return(packages)
}
- message(sprintf(
+ message_formatted(
"Skipping %d package(s) that are not installed:\n",
sum(! available),
- kwb.utils::stringList(packages[! available])
- ))
+ string_list(packages[! available])
+ )
packages[available]
}
@@ -159,7 +158,7 @@ filter_for_package_functions <- function(frequency_data, package)
# digest_package_specifier -----------------------------------------------------
digest_package_specifier <- function(ff)
{
- kwb.utils::checkForMissingColumns(ff, c("script", "name", "count"))
+ check_for_missing_columns(ff, c("script", "name", "count"))
parts <- strsplit(as.character(ff$name), ":::?")
diff --git a/R/get_package_usage_per_script.R b/R/get_package_usage_per_script.R
index 774711e..57ad8cf 100644
--- a/R/get_package_usage_per_script.R
+++ b/R/get_package_usage_per_script.R
@@ -7,10 +7,6 @@
#' @param ... additional arguments passed to \code{\link{get_package_function_usage}}
#' @return tibble with information on used packages
#' @export
-#' @importFrom stats setNames
-#' @importFrom kwb.utils catAndRun
-#' @importFrom dplyr bind_rows
-
get_package_usage_per_script <- function(root, packages, pattern = "\\.R$", ...)
{
# Parse all scripts within this root folder
@@ -23,7 +19,7 @@ get_package_usage_per_script <- function(root, packages, pattern = "\\.R$", ...)
# For each package, check which script uses functions of this package
who_uses_what <- lapply(stats::setNames(nm = packages), function(package) {
- kwb.utils::catAndRun(paste("Checking usage of", package), newLine = 3, {
+ cat_and_run(paste("Checking usage of", package), newLine = 3, {
try(get_package_function_usage(
tree,
package = package,
diff --git a/R/get_string_constants_in_scripts.R b/R/get_string_constants_in_scripts.R
index 3ca88ee..70d9029 100644
--- a/R/get_string_constants_in_scripts.R
+++ b/R/get_string_constants_in_scripts.R
@@ -43,7 +43,7 @@ get_string_constants_in_scripts <- function(
names(tree) <- file_db$files$file_id
- strings <- kwb.utils::defaultIfNULL(FUN, fetch_string_constants_1)(tree)
+ strings <- default_if_null(FUN, fetch_string_constants_1)(tree)
if (two_version_check && is.null(FUN)) {
string_constants_2 <- fetch_string_constants_2(tree)
@@ -52,7 +52,7 @@ get_string_constants_in_scripts <- function(
result <- lapply(strings, function(x) if (! is.null(x)) {
f <- table(x)
- kwb.utils::noFactorDataFrame(string = names(f), count = as.integer(f))
+ no_factor_data_frame(string = names(f), count = as.integer(f))
})
structure(dplyr::bind_rows(result, .id = "file_id"), file_db = file_db)
diff --git a/R/helpers.R b/R/helpers.R
new file mode 100644
index 0000000..51a6a79
--- /dev/null
+++ b/R/helpers.R
@@ -0,0 +1,19 @@
+# deparsed_logical_values ------------------------------------------------------
+deparsed_logical_values <- function(
+ type = c("short", "long", "either")[3L],
+ logicals = c(FALSE, TRUE)
+)
+{
+ values <- c("F", "T", "FALSE", "TRUE")
+ use_false_true <- c(FALSE %in% logicals, TRUE %in% logicals)
+
+ if (type == "short") {
+ values[1:2][use_false_true]
+ } else if (type == "long") {
+ values[3:4][use_false_true]
+ } else if (type == "either") {
+ values[rep(use_false_true, 2L)]
+ } else {
+ stop("Unknown type: ", type)
+ }
+}
diff --git a/R/logical.R b/R/logical.R
index 9727843..a178691 100644
--- a/R/logical.R
+++ b/R/logical.R
@@ -4,6 +4,77 @@ is_assignment <- function(x)
inherits(x, "<-") || inherits(x, "=")
}
+# is_bad_function_name ---------------------------------------------------------
+is_bad_function_name <- function(x)
+{
+ if (!is_function_assignment(x)) {
+ return(FALSE)
+ }
+
+ function_name <- split_assignment(x)$leftSide
+
+ is.name(function_name) &&
+ grepl("\\.", deparse(function_name))
+}
+
+# is_colon_seq -----------------------------------------------------------------
+is_colon_seq <- function(x)
+{
+ is.language(x) &&
+ length(x) == 3L &&
+ is.symbol(x[[1L]]) &&
+ identical(as.character(x[[1]]), ":")
+}
+
+# is_colon_seq_1_to_any --------------------------------------------------------
+is_colon_seq_1_to_any <- function(x)
+{
+ is_colon_seq(x) && identical(x[[2]], 1)
+}
+
+# is_colon_seq_1_to_length -----------------------------------------------------
+is_colon_seq_1_to_length <- function(x)
+{
+ is_colon_seq_1_to_any(x) &&
+ mode(x[[3]]) == "call" &&
+ identical(deparse(x[[3]][[1]]), "length")
+}
+
+# is_colon_seq_1_to_variable ---------------------------------------------------
+is_colon_seq_1_to_variable <- function(x)
+{
+ is_colon_seq_1_to_any(x) &&
+ !is.numeric(x[[3]]) &&
+ mode(x[[3]]) != "call"
+}
+
+# is_comparison_with_false -----------------------------------------------------
+is_comparison_with_false <- function(x)
+{
+ is_comparison_with_logical(x, logicals = FALSE)
+}
+
+# is_comparison_with_logical ---------------------------------------------------
+is_comparison_with_logical <- function(x, logicals = c(FALSE, TRUE))
+{
+ if (!is.call(x)) {
+ return(FALSE)
+ }
+
+ operator <- deparse(x[[1]])
+
+ operator %in% c("==", "!=") && (
+ is_logical_constant(x[[2]], type = "either", logicals) ||
+ is_logical_constant(x[[3]], type = "either", logicals)
+ )
+}
+
+# is_comparison_with_true ------------------------------------------------------
+is_comparison_with_true <- function(x)
+{
+ is_comparison_with_logical(x, logicals = TRUE)
+}
+
# is_function_assignment -------------------------------------------------------
is_function_assignment <- function(assignment)
{
@@ -23,3 +94,26 @@ is_function_def_call <- function(x)
as.character(as.list(x)[[1L]])[1L] == "function"
}
+
+# is_logical_constant ----------------------------------------------------------
+is_logical_constant <- function(x, type = "short", logicals = c(FALSE, TRUE))
+{
+ if (!is.symbol(x)) {
+ return(FALSE)
+ }
+
+ deparse(x) %in% deparsed_logical_values(type, logicals)
+}
+
+# is_logical_constant_false ----------------------------------------------------
+is_logical_constant_false <- function(x, type = "short")
+{
+ is_logical_constant(x, type, logicals = FALSE)
+}
+
+# is_logical_constant_true -----------------------------------------------------
+is_logical_constant_true <- function(x, type = "short")
+{
+ is_logical_constant(x, type, logicals = TRUE)
+}
+
diff --git a/R/main.R b/R/main.R
deleted file mode 100644
index 69d151a..0000000
--- a/R/main.R
+++ /dev/null
@@ -1,131 +0,0 @@
-# parse_scripts ----------------------------------------------------------------
-#' Parse all given R scripts into a tree structure
-#'
-#' @param root root directory to which the relative paths given in
-#' \code{scripts} relate
-#' @param scripts relative file paths to R scripts. By default all files ending
-#' with ".R" or ".r" below the \code{root} folder (recursively) are parsed.
-#' @param dbg if \code{TRUE} debug messages are shown
-#'
-#' @export
-#'
-#' @importFrom kwb.utils catAndRun
-#'
-#' @seealso \code{\link{to_full_script_info}}
-#'
-#' @examples
-#' \dontrun{
-#' # Download some example code files from github...
-#' url.base <- "https://raw.githubusercontent.com/hsonne/blockrand2/master/R/"
-#' urls <- paste0(url.base, c("blockrand2_create.R", "blockrand2_main.R"))
-#'
-#' targetdir <- file.path(tempdir(), "blockrand2")
-#' targetdir <- kwb.utils::createDirectory(targetdir)
-#'
-#' for (url in urls) {
-#' download.file(url, file.path(targetdir, basename(url)))
-#' }
-#'
-#' # By default, all R scripts below the root are parse
-#' trees <- parse_scripts(root = targetdir)
-#'
-#' # All elements of trees are expressions
-#' sapply(trees, is.expression)
-#'
-#' # Analyse the scripts on the script level
-#' scriptInfo <- to_full_script_info(trees)
-#'
-#' scriptInfo
-#'
-#' # Analyse the scripts on the function level
-#' functionInfo <- get_full_function_info(trees)
-#'
-#' functionInfo
-#' }
-parse_scripts <- function
-(
- root,
- scripts = dir(root, "\\.R$", ignore.case = TRUE, recursive = TRUE),
- dbg = TRUE
-)
-{
- trees <- lapply(scripts, function(x) {
-
- file <- file.path(root, x)
-
- content <- catAndRun(
- paste("Reading", file), dbg = dbg, readLines(file, warn = FALSE)
- )
-
- expressions <- try(parse(text = content))
-
- structure(expressions, n.lines = length(content))
- })
-
- stats::setNames(trees, scripts)
-}
-
-# get_full_function_info -------------------------------------------------------
-#'
-#' Get information on function definitions in parsed R scripts
-#'
-#' @param trees list of R script parse trees as provided by
-#' \code{\link{parse_scripts}}
-#'
-#' @importFrom kwb.utils rbindAll
-#' @importFrom kwb.utils moveColumnsToFront
-#'
-#' @export
-#'
-#' @seealso \code{\link{parse_scripts}}
-get_full_function_info <- function(trees)
-{
- infos <- lapply(trees, function(tree) {
- rbindAll(lapply(get_functions(tree), get_function_info))
- })
-
- functionInfo <- rbindAll(infos, nameColumn = "script")
-
- count <- multi_defined_functions(functionInfo)
-
- functionInfo <- merge(functionInfo, count, by = "functionName")
-
- moveColumnsToFront(functionInfo, c("script", "functionName", "n.def"))
-}
-
-# multi_defined_functions ------------------------------------------------------
-multi_defined_functions <- function(functionInfo)
-{
- count <- aggregate(
- n.def ~ functionName,
- cbind(n.def = seq_len(nrow(functionInfo)), functionInfo),
- length
- )
-
- count[order(count$n, decreasing = TRUE), ]
-}
-
-# merge_function_info ----------------------------------------------------------
-merge_function_info <- function(scriptInfo, functionInfo)
-{
- funExpressions <- expressions_per_function(functionInfo)
-
- merge(
- scriptInfo,
- funExpressions[, c("script", "epf")],
- by = "script",
- all.x = TRUE
- )
-}
-
-# filter_scripts ---------------------------------------------------------------
-#' @importFrom kwb.utils matchesCriteria
-#' @importFrom kwb.utils removeEmptyColumns
-filter_scripts <- function(scriptInfo, fun.min = 5, epf.min = 10)
-{
- criteria <- c(paste("fun >=", fun.min), paste("epf >=", epf.min))
-
- scriptInfo <- scriptInfo[matchesCriteria(scriptInfo, criteria), ]
-
- removeEmptyColumns(scriptInfo)
-}
diff --git a/R/merge_function_info.R b/R/merge_function_info.R
new file mode 100644
index 0000000..da59dc4
--- /dev/null
+++ b/R/merge_function_info.R
@@ -0,0 +1,12 @@
+# merge_function_info ----------------------------------------------------------
+merge_function_info <- function(scriptInfo, functionInfo)
+{
+ funExpressions <- expressions_per_function(functionInfo)
+
+ merge(
+ scriptInfo,
+ funExpressions[, c("script", "epf")],
+ by = "script",
+ all.x = TRUE
+ )
+}
diff --git a/R/normaliseFunction.R b/R/normaliseFunction.R
index 0a7e503..be7f16b 100644
--- a/R/normaliseFunction.R
+++ b/R/normaliseFunction.R
@@ -1,8 +1,7 @@
# normaliseFunction ------------------------------------------------------------
-#' @importFrom kwb.utils printIf removeAttributes
normaliseFunction <- function(x, dbg = FALSE)
{
- kwb.utils::printIf(dbg, x, "Original")
+ print_if(dbg, x, "Original")
# Split the function assignment or raise an error
parts <- split_function_assignment(x)
@@ -11,7 +10,7 @@ normaliseFunction <- function(x, dbg = FALSE)
renames <- attr(newArglist, "renames")
- x[[3]][[2]] <- kwb.utils::removeAttributes(newArglist, "renames")
+ x[[3]][[2]] <- remove_attributes(newArglist, "renames")
# Rename the arguments in the body of the function
x[[3]][[3]] <- replaceNames(x[[3]][[3]], renames)
@@ -62,13 +61,14 @@ normalNames <- function(n, version = 1)
}
# replaceNames -----------------------------------------------------------------
-#' @importFrom kwb.utils catIf
+
## http://stackoverflow.com/questions/33850219/change-argument-names-inside-a-function-r
## Function to replace variables in function body
## expr is `body(f)`, keyvals is a lookup table for replacements
+
replaceNames <- function(expr, keyvals = NULL, dbg = FALSE)
{
- catIf(dbg, "replaceNames(", deparse(expr)[1L], ")...\n")
+ cat_if(dbg, "replaceNames(", deparse(expr)[1L], ")...\n")
if (is_function_assignment(expr)) {
diff --git a/R/normalise_expression.R b/R/normalise_expression.R
new file mode 100644
index 0000000..a23bd3d
--- /dev/null
+++ b/R/normalise_expression.R
@@ -0,0 +1,51 @@
+# normalise_expression ---------------------------------------------------------
+
+#' Get the Normalised Structure of an Expression
+#'
+#' All the different elements of an expression are replaced with nomalised names
+#' that represent their types, such as: "SYMBOL", "NUM_CONST"
+#'
+#' @param x an expression as returned by \code{\link{parse}} or a vector of
+#' character representing the text to be parsed
+#' @param collapse separator string to be put between the single tokens into
+#' which the expression is split. The default is the space character " ".
+#' @returns vector of character of length one with attribute "text"
+#' @examples
+#' normalised_1 <- normalise_expression("x + 1")
+#' normalised_2 <- normalise_expression("y + 2")
+#'
+#' # Use c() to remove the attributes
+#' identical(c(normalised_1), c(normalised_2))
+#'
+#' @export
+normalise_expression <- function(x, collapse = " ")
+{
+ if (!is.expression(x)) {
+
+ if (!is.character(x)) {
+ x <- deparse(x)
+ }
+
+ x <- parse(text = x, keep.source = TRUE)
+ }
+
+ parse_info <- get_parse_info(x)
+ not_empty <- nzchar(parse_info$text)
+
+ structure(
+ paste(parse_info$token[not_empty], collapse = collapse),
+ text = paste(parse_info$text[not_empty], collapse = collapse)
+ )
+}
+
+# get_parse_info ---------------------------------------------------------------
+get_parse_info <- function(x)
+{
+ envir <- get_attribute(x, "srcfile")
+ parse_data <- get("parseData", envir = envir)
+
+ data.frame(
+ text = get_attribute(parse_data, "text"),
+ token = get_attribute(parse_data, "tokens")
+ )
+}
diff --git a/R/parse_scripts.R b/R/parse_scripts.R
new file mode 100644
index 0000000..c05f30a
--- /dev/null
+++ b/R/parse_scripts.R
@@ -0,0 +1,64 @@
+# parse_scripts ----------------------------------------------------------------
+
+#' Parse all given R scripts into a tree structure
+#'
+#' @param root root directory to which the relative paths given in
+#' \code{scripts} relate
+#' @param scripts relative file paths to R scripts. By default all files ending
+#' with ".R" or ".r" below the \code{root} folder (recursively) are parsed.
+#' @param dbg if \code{TRUE} debug messages are shown
+#' @param \dots further arguments passed to \code{\link{parse}}
+#' @export
+#' @seealso \code{\link{to_full_script_info}}
+#' @examples
+#' \dontrun{
+#' # Download some example code files from github...
+#' url.base <- "https://raw.githubusercontent.com/hsonne/blockrand2/master/R/"
+#' urls <- paste0(url.base, c("blockrand2_create.R", "blockrand2_main.R"))
+#'
+#' targetdir <- file.path(tempdir(), "blockrand2")
+#' targetdir <- kwb.utils::createDirectory(targetdir)
+#'
+#' for (url in urls) {
+#' download.file(url, file.path(targetdir, basename(url)))
+#' }
+#'
+#' # By default, all R scripts below the root are parsed
+#' trees <- parse_scripts(root = targetdir)
+#'
+#' # All elements of trees are expressions
+#' sapply(trees, is.expression)
+#'
+#' # Analyse the scripts on the script level
+#' scriptInfo <- to_full_script_info(trees)
+#'
+#' scriptInfo
+#'
+#' # Analyse the scripts on the function level
+#' functionInfo <- get_full_function_info(trees)
+#'
+#' functionInfo
+#' }
+parse_scripts <- function
+(
+ root,
+ scripts = dir(root, "\\.R$", ignore.case = TRUE, recursive = TRUE),
+ dbg = TRUE,
+ ...
+)
+{
+ trees <- lapply(scripts, function(x) {
+
+ file <- file.path(root, x)
+
+ content <- cat_and_run(
+ paste("Reading", file), dbg = dbg, readLines(file, warn = FALSE)
+ )
+
+ expressions <- try(parse(text = content, ...))
+
+ structure(expressions, n.lines = length(content))
+ })
+
+ stats::setNames(trees, scripts)
+}
diff --git a/R/stat.R b/R/stat.R
index 5d0f89e..4aa993e 100644
--- a/R/stat.R
+++ b/R/stat.R
@@ -1,9 +1,7 @@
# expressions_stat -------------------------------------------------------------
-#' @importFrom kwb.utils rbindAll
-#' @importFrom kwb.utils noFactorDataFrame
expressions_stat <- function(x)
{
- rbindAll(lapply(x, function(xx) noFactorDataFrame(
+ rbindAll(lapply(x, function(xx) no_factor_data_frame(
mode = mode(xx),
class = class(x),
x2 = as.character(xx[[2]]),
@@ -12,14 +10,13 @@ expressions_stat <- function(x)
}
# get_function_info ------------------------------------------------------------
-#' @importFrom kwb.utils noFactorDataFrame
get_function_info <- function(f)
{
parts <- split_function_assignment(f)
args <- parts$args
- noFactorDataFrame(
+ no_factor_data_frame(
functionName = parts$functionName,
bodyClass = parts$bodyClass,
n.args = length(args),
@@ -33,12 +30,7 @@ get_function_info <- function(f)
#'
#' @param trees list of R script parse trees as provided by
#' \code{\link{parse_scripts}}
-#'
-#' @importFrom kwb.utils renameColumns
-#' @importFrom kwb.utils moveColumnsToFront
-#'
#' @export
-#'
#' @seealso \code{\link{parse_scripts}}
to_full_script_info <- function(trees)
{
@@ -63,15 +55,13 @@ to_full_script_info <- function(trees)
numeric = "num"
)
- renameColumns(moveColumnsToFront(info, columns), renames)
+ rename_columns(move_columns_to_front(info, columns), renames)
}
# trees_to_script_info ---------------------------------------------------------
-#' @importFrom kwb.utils resetRowNames
-#' @importFrom kwb.utils noFactorDataFrame
trees_to_script_info <- function(x)
{
- y <- noFactorDataFrame(
+ y <- no_factor_data_frame(
script = names(x),
rows = sapply(x, attr, "n.lines"),
expr = lengths(x),
@@ -85,15 +75,13 @@ trees_to_script_info <- function(x)
}
# trees_to_type_stat -----------------------------------------------------------
-#' @importFrom kwb.utils moveColumnsToFront
-#' @importFrom kwb.utils safeRowBindAll
trees_to_type_stat <- function(trees)
{
types <- lapply(trees, function(tree) {
as.data.frame(t(lengths(expressions_by_class(tree))))
})
- typestat <- safeRowBindAll(types)
+ typestat <- safe_row_bind_all(types)
typestat$script <- names(types)
diff --git a/R/type_info.R b/R/type_info.R
deleted file mode 100644
index 0734843..0000000
--- a/R/type_info.R
+++ /dev/null
@@ -1,43 +0,0 @@
-# type_info --------------------------------------------------------------------
-type_info <- function(x, as.character = FALSE)
-{
- #shorten <- function(x) kwb.utils::shorten(x, max_chars = 30L)
- shorten <- function(x) paste(substr(x, 1, 30), "...")
-
- text <- as.character(x)
-
- info <- list(
- type = typeof(x),
- mode = mode(x),
- class = class(x),
- length = length(x),
- text = shorten(paste0("[", seq_along(text), "]", text, collapse = "")),
- is = if (length(x) == 1L) is_what(x)
- )
-
- info <- c(info, list(
- n_modes = length(info$mode),
- n_classes = length(info$class)
- ))
-
- if (! as.character) {
- return(info)
- }
-
- info_to_text(info)
-}
-
-# info_to_text -----------------------------------------------------------------
-#' @importFrom kwb.utils commaCollapsed
-info_to_text <- function(info)
-{
- sprintf(
- paste0(#"type|mode|class|length|is: ",
- "%s|%s|%s|%d|%s"),
- info$type,
- kwb.utils::commaCollapsed(info$mode),
- kwb.utils::commaCollapsed(info$class),
- info$length,
- kwb.utils::commaCollapsed(info$is)
- )
-}
diff --git a/R/utils-pipe.R b/R/utils-pipe.R
new file mode 100644
index 0000000..fd0b1d1
--- /dev/null
+++ b/R/utils-pipe.R
@@ -0,0 +1,14 @@
+#' Pipe operator
+#'
+#' See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details.
+#'
+#' @name %>%
+#' @rdname pipe
+#' @keywords internal
+#' @export
+#' @importFrom magrittr %>%
+#' @usage lhs \%>\% rhs
+#' @param lhs A value or the magrittr placeholder.
+#' @param rhs A function call using the magrittr semantics.
+#' @return The result of calling `rhs(lhs)`.
+NULL
diff --git a/R/utils.R b/R/utils.R
index 66c28ba..3677ac2 100644
--- a/R/utils.R
+++ b/R/utils.R
@@ -14,6 +14,52 @@ arg_names <- function(x)
names(args_list[-length(args_list)])
}
+# backspace --------------------------------------------------------------------
+#' @importFrom kwb.utils backspace
+backspace <- kwb.utils::backspace
+
+# cat_and_run ------------------------------------------------------------------
+#' @importFrom kwb.utils catAndRun
+cat_and_run <- kwb.utils::catAndRun
+
+# cat_formatted ----------------------------------------------------------------
+cat_formatted <- function(fmt, ...)
+{
+ cat(sprintf(fmt, ...))
+}
+
+# cat_if -----------------------------------------------------------------------
+#' @importFrom kwb.utils catIf
+cat_if <- kwb.utils::catIf
+
+# check_for_missing_columns ----------------------------------------------------
+#' @importFrom kwb.utils checkForMissingColumns
+check_for_missing_columns <- kwb.utils::checkForMissingColumns
+
+# collapsed --------------------------------------------------------------------
+#' @importFrom kwb.utils collapsed
+collapsed <- kwb.utils::collapsed
+
+# comma_collapsed --------------------------------------------------------------
+#' @importFrom kwb.utils commaCollapsed
+comma_collapsed <- kwb.utils::commaCollapsed
+
+# create_directory -------------------------------------------------------------
+#' @importFrom kwb.utils createDirectory
+create_directory <- kwb.utils::createDirectory
+
+# default_if_null --------------------------------------------------------------
+#' @importFrom kwb.utils defaultIfNULL
+default_if_null <- kwb.utils::defaultIfNULL
+
+# exclude_null -----------------------------------------------------------------
+#' @importFrom kwb.utils excludeNULL
+exclude_null <- kwb.utils::excludeNULL
+
+# extract_substring ------------------------------------------------------------
+#' @importFrom kwb.utils extractSubstring
+extract_substring <- kwb.utils::extractSubstring
+
# filter_for -------------------------------------------------------------------
filter_for <- function(x, FUN.filter, ...)
{
@@ -22,38 +68,62 @@ filter_for <- function(x, FUN.filter, ...)
x[unlist(selected)]
}
+# get_attribute ----------------------------------------------------------------
+#' @importFrom kwb.utils getAttribute
+get_attribute <- kwb.utils::getAttribute
+
+# get_function_names_matching --------------------------------------------------
+get_function_names_matching <- function(pattern = NULL, package = "base")
+{
+ # Get names of functions within the package
+ function_names <- ls(getNamespace(package))
+
+ if (is.null(pattern)) {
+ return(function_names)
+ }
+
+ grep(pattern, function_names, value = TRUE)
+}
+
+# get_is_function_names --------------------------------------------------------
+get_is_function_names <- function()
+{
+ get_function_names_matching("^is\\.")
+}
+
+# is_try_error -----------------------------------------------------------------
+#' @importFrom kwb.utils isTryError
+is_try_error <- kwb.utils::isTryError
+
# is_what ----------------------------------------------------------------------
is_what <- function(
x,
exclude = c(
- "is.na.numeric_version",
- "is.na.POSIXlt",
- "is.single",
- # the following complain:
- # nicht implementierte Standardmethode für Typ 'expression'
- "is.finite",
- "is.infinite",
- "is.nan",
- # the following complain:
- # Argument zu 'which' ist nicht boolesch
- "is.na",
- "is.na.data.frame" # returns a matrix
+ # "is.na.numeric_version",
+ # "is.na.POSIXlt",
+ # "is.na.POSIXct",
+ # "is.single",
+ # # the following complain:
+ # # nicht implementierte Standardmethode für Typ 'expression'
+ # "is.finite",
+ # "is.infinite",
+ # "is.nan",
+ # # the following complain:
+ # # Argument zu 'which' ist nicht boolesch
+ # "is.na",
+ # "is.na.data.frame" # returns a matrix
),
- silent = FALSE
+ dbg = FALSE
)
{
# stopifnot(length(x) == 1L)
-
- # Get names of functions within the base package
- base_functions <- ls(getNamespace("base"))
-
- # Find is.* functions
- pattern_is <- "^is\\."
- is_functions <- grep(pattern_is, base_functions, value = TRUE)
+
+ # Get names of is.* functions within the base package
+ is_functions <- get_is_function_names()
# Which functions are not applicable, i.e. have not exactly one argument "x"
is_applicable <- sapply(lapply(is_functions, arg_names), identical, "x")
- non_applicable <- is_functions[which(! is_applicable)]
+ non_applicable <- is_functions[which(!is_applicable)]
# Exclude non-applicable functions and further functions given in "exclude"
is_functions <- setdiff(is_functions, c(non_applicable, exclude))
@@ -61,15 +131,26 @@ is_what <- function(
# Call all remaining is.* functions to x
is_results <- sapply(is_functions, function(f) {
- result <- try(do.call(f, list(x), quote = TRUE), silent = silent)
+ suppressWarnings(
+ result <- try(
+ expr = do.call(f, list(x), quote = TRUE),
+ silent = TRUE
+ )
+ )
+
+ cat_error <- function(what) {
+ if (dbg) {
+ cat_formatted("%s(x) returned %s. Returning FALSE.\n", f, what)
+ }
+ }
- if (inherits(result, "try-error")) {
- cat(sprintf("%s(x) returned an error. Returning FALSE.\n", f))
+ if (is_try_error(result)) {
+ cat_error("an error")
return(FALSE)
}
- if (! isTRUE(result) && ! isFALSE(result)) {
- cat(sprintf("%s(x) returned neither TRUE nor FALSE. Returning FALSE.\n", f))
+ if (!identical(result, TRUE) && !identical(result, FALSE)) {
+ cat_error("neither TRUE nor FALSE")
return(FALSE)
}
@@ -77,7 +158,105 @@ is_what <- function(
})
# Return the names (without "is.") of functions that returned TRUE
- gsub(pattern_is, "", names(which(is_results)))
+ gsub("^is\\.", "", names(which(is_results)))
+}
+
+# left -------------------------------------------------------------------------
+#' @importFrom kwb.utils left
+left <- kwb.utils::left
+
+# matches_criteria -------------------------------------------------------------
+#' @importFrom kwb.utils matchesCriteria
+matches_criteria <- kwb.utils::matchesCriteria
+
+# message_formatted ------------------------------------------------------------
+message_formatted <- function(fmt, ...)
+{
+ message(sprintf(fmt, ...))
+}
+
+# move_columns_to_front --------------------------------------------------------
+#' @importFrom kwb.utils moveColumnsToFront
+move_columns_to_front <- kwb.utils::moveColumnsToFront
+
+# multi_substitute -------------------------------------------------------------
+#' @importFrom kwb.utils multiSubstitute
+multi_substitute <- kwb.utils::multiSubstitute
+
+# no_factor_data_frame ---------------------------------------------------------
+#' @importFrom kwb.utils noFactorDataFrame
+no_factor_data_frame <- kwb.utils::noFactorDataFrame
+
+# open_windows_explorer --------------------------------------------------------
+#' @importFrom kwb.utils hsOpenWindowsExplorer
+open_windows_explorer <- kwb.utils::hsOpenWindowsExplorer
+
+# pairwise ---------------------------------------------------------------------
+#' @importFrom kwb.utils pairwise
+pairwise <- kwb.utils::pairwise
+
+# print_if ---------------------------------------------------------------------
+#' @importFrom kwb.utils printIf
+print_if <- kwb.utils::printIf
+
+# rbind_all --------------------------------------------------------------------
+#' @importFrom kwb.utils rbindAll
+rbind_all <- kwb.utils::rbindAll
+
+# remove_attributes ------------------------------------------------------------
+#' @importFrom kwb.utils removeAttributes
+remove_attributes <- kwb.utils::removeAttributes
+
+# remove_columns ---------------------------------------------------------------
+#' @importFrom kwb.utils removeColumns
+remove_columns <- kwb.utils::removeColumns
+
+# remove_empty_columns ---------------------------------------------------------
+#' @importFrom kwb.utils removeEmptyColumns
+remove_empty_columns <- kwb.utils::removeEmptyColumns
+
+# remove_first_and_last_slash --------------------------------------------------
+remove_first_and_last_slash <- function(x)
+{
+ gsub("^/+|/+$", "", x)
+}
+
+# rename_columns ---------------------------------------------------------------
+#' @importFrom kwb.utils renameColumns
+rename_columns <- kwb.utils::renameColumns
+
+# reset_row_names --------------------------------------------------------------
+#' @importFrom kwb.utils resetRowNames
+reset_row_names <- kwb.utils::resetRowNames
+
+# safe_row_bind_all ------------------------------------------------------------
+#' @importFrom kwb.utils safeRowBindAll
+safe_row_bind_all <- kwb.utils::safeRowBindAll
+
+# select_columns ---------------------------------------------------------------
+#' @importFrom kwb.utils selectColumns
+select_columns <- kwb.utils::selectColumns
+
+# select_elements --------------------------------------------------------------
+#' @importFrom kwb.utils selectElements
+select_elements <- kwb.utils::selectElements
+
+# shorten ----------------------------------------------------------------------
+#' @importFrom kwb.utils shorten
+shorten <- kwb.utils::shorten
+
+# stop_formatted ---------------------------------------------------------------
+#' @importFrom kwb.utils stopFormatted
+stop_formatted <- kwb.utils::stopFormatted
+
+# string_list ------------------------------------------------------------------
+#' @importFrom kwb.utils stringList
+string_list <- kwb.utils::stringList
+
+# warn_formatted ---------------------------------------------------------------
+warn_formatted <- function(fmt, ..., call. = FALSE)
+{
+ warning(sprintf(fmt, ...), call. = call.)
}
# vector_to_count_table --------------------------------------------------------
@@ -93,9 +272,9 @@ vector_to_count_table <- function(x)
unexpected <- ncol(frequency_data) != 2
- kwb.utils::printIf(unexpected, x)
- kwb.utils::printIf(unexpected, frequency)
- kwb.utils::printIf(unexpected, frequency_data)
+ print_if(unexpected, x)
+ print_if(unexpected, frequency)
+ print_if(unexpected, frequency_data)
stats::setNames(frequency_data, c("name", "count"))
}
diff --git a/R/walk_tree.R b/R/walk_tree.R
index 155bc27..b083a1a 100644
--- a/R/walk_tree.R
+++ b/R/walk_tree.R
@@ -22,12 +22,12 @@ walk_tree <- function(
stopOnMaxDepth(depth, max_depth)
stopOnUnexpectedProps(props <- get_properties(x))
- kwb.utils::printIf(dbg, path)
- kwb.utils::printIf(dbg, props)
+ print_if(dbg, path)
+ print_if(dbg, props)
if (length(config)) {
result <- evaluate_checks(x, config, path)
- if (kwb.utils::defaultIfNULL(result$matched, FALSE)) {
+ if (default_if_null(result$matched, FALSE)) {
cat("file:", context$file, "\n")
}
if (result$modified) {
@@ -36,7 +36,7 @@ walk_tree <- function(
}
if (! props$is_recursive) {
- kwb.utils::catIf(dbg, sprintf("Leaf reached: '%s'\n", props$text))
+ cat_if(dbg, sprintf("Leaf reached: '%s'\n", props$text))
return(x)
}
@@ -65,7 +65,7 @@ walk_tree <- function(
stopOnMaxDepth <- function(depth, max_depth)
{
if (depth > max_depth) {
- stop(call. = FALSE, sprintf("depth > max_depth (%d) reached", max_depth))
+ stop_formatted("depth > max_depth (%d) reached", max_depth)
}
}
@@ -79,7 +79,7 @@ stopOnUnexpectedProps <- function(props) {
# stopIfNonExpected ------------------------------------------------------------
stopIfNonExpected <- function(what, name, expected) {
if (!name %in% expected) {
- stop("Unexpected ", what, ": ", name, call. = FALSE)
+ stop_formatted("Unexpected %s: %s", what, name)
}
}
@@ -128,7 +128,7 @@ expected_classes <- function()
# get_properties ---------------------------------------------------------------
get_properties <- function(x)
{
- kwb.utils::noFactorDataFrame(
+ no_factor_data_frame(
is_atomic = is.atomic(x),
is_recursive = is.recursive(x),
is_call = is.call(x),
@@ -136,7 +136,7 @@ get_properties <- function(x)
mode = mode(x),
class = class(x),
length = length(x),
- text = kwb.utils::left(kwb.utils::collapsed(deparse(x)), 20)
+ text = left(collapsed(deparse(x)), 20)
)
}
@@ -150,7 +150,7 @@ evaluate_checks <- function(x, config, path)
modified = FALSE
)
- checks <- kwb.utils::selectElements(config, "checks")
+ checks <- select_elements(config, "checks")
if (!length(checks)) {
return(result)
@@ -161,7 +161,7 @@ evaluate_checks <- function(x, config, path)
for (check in checks) {
# Go to next check if this check is not passed
- if (!kwb.utils::selectElements(check, "check")(x)) {
+ if (!select_elements(check, "check")(x)) {
next
}
@@ -191,6 +191,6 @@ evaluate_checks <- function(x, config, path)
# is_check ---------------------------------------------------------------------
is_check <- function(check)
{
- is.function(kwb.utils::selectElements(check, "check")) &&
+ is.function(select_elements(check, "check")) &&
(!is.null(check$modify) || !is.null(check$report))
}
diff --git a/R/writeContentsToFiles.R b/R/writeContentsToFiles.R
index 1c6477a..7159384 100644
--- a/R/writeContentsToFiles.R
+++ b/R/writeContentsToFiles.R
@@ -1,64 +1,71 @@
# writeContentsToLessFiles -----------------------------------------------------
writeContentsToLessFiles <- function(
- contents, targetDir, functionName, dbg = TRUE
+ contents,
+ targetDir,
+ functionName,
+ dbg = TRUE
)
{
- oneLineContents <- sapply(contents, paste, collapse = "\n")
-
- i <- 0L
-
- while (length(oneLineContents)) {
-
- i <- i + 1L
-
- # Get the first content out of the list
- content <- oneLineContents[1L]
-
- # Select this and identical contents
- selected <- (oneLineContents == content)
-
- # Write this content
- file <- targetFile(targetDir, paste0(functionName, "__v"), i)
-
- headerLines <- paste("# found in", names(oneLineContents[selected]))
-
- writeContentToFile(content, file, headerLines, dbg = dbg)
-
- # Remove this and the identical contents
- oneLineContents <- oneLineContents[! selected]
- }
-
- # Return the number of files written
- i
+ writeContentsToFiles(contents, targetDir, functionName, dbg, less = TRUE)
}
-# targetFile -------------------------------------------------------------------
-targetFile <- function(targetDir, functionName, i)
+# writeContentsToFiles ---------------------------------------------------------
+writeContentsToFiles <- function(
+ contents,
+ targetDir,
+ functionName,
+ dbg = TRUE,
+ less = FALSE
+)
{
- file.path(targetDir, sprintf("%s_%d.txt", functionName, i))
+ # Put each content into one line (a vector of length one)
+ all_contents <- sapply(contents, paste, collapse = "\n")
+
+ # Continue either with the unique contents or with all contents
+ contents <- if (less) {
+ unique(all_contents)
+ } else {
+ all_contents
+ }
+
+ # Create one file per content
+ unlist(lapply(seq_along(contents), function(i) {
+
+ # Select the corresponding content
+ content <- contents[i]
+
+ # Scripts where the content was found
+ scripts <- if (less) {
+ names(which(all_contents == content))
+ } else {
+ names(contents)[i]
+ }
+
+ # Compose base file name
+ base_name <- sprintf(
+ "%s__%s%d.txt",
+ functionName, ifelse(less, "unique-", ""), i
+ )
+
+ # Write the content to a text file in the target directory
+ writeContentToFile(
+ content = content,
+ file = file.path(targetDir, base_name),
+ headerLines = paste("# found in", scripts),
+ dbg = dbg
+ )
+
+ }))
}
# writeContentToFile -----------------------------------------------------------
-#' @importFrom kwb.utils catAndRun
writeContentToFile <- function(content, file, headerLines, dbg = TRUE)
{
- catAndRun(
+ cat_and_run(
paste("Writing function to", file), dbg = dbg,
writeLines(c(headerLines, content), file)
)
-}
-
-# writeContentsToFiles ---------------------------------------------------------
-writeContentsToFiles <- function(contents, targetDir, functionName, dbg = TRUE)
-{
- content_names <- names(contents)
-
- for (i in seq_along(contents)) {
-
- headerLines <- paste("# found in", content_names[i])
-
- file <- targetFile(targetDir, functionName, i)
-
- writeContentToFile(contents[[i]], file, headerLines, dbg = dbg)
- }
+
+ # Return the path to the file
+ file
}
diff --git a/inst/extdata/cleanCodeBasics.R b/inst/extdata/cleanCodeBasics.R
index 02a07bf..f0ebce0 100644
--- a/inst/extdata/cleanCodeBasics.R
+++ b/inst/extdata/cleanCodeBasics.R
@@ -2,11 +2,7 @@
config <- list(checks = list(
seq_1_n = list(
check = function(x) {
- if (!is.call(x)) return(FALSE)
- #str(as.list(x))
- #substr(deparse(x)[1L], 1L, 2L) == "1:"
- identical(x[[1]], as.name(":")) &&
- identical(x[[2]], 1) &&
+ kwb.code:::is_colon_seq_1_to_any(x) &&
(is.name(x[[3]]) || is.call(x[[3]]))
},
report = function(x) {
@@ -66,16 +62,18 @@ config <- list(checks = list(
if (FALSE)
{
#files <- dir_r_files("R")
- files <- dir_r_files("~/github-repos/K/kwb.misa")
+ files <- dir_r_files("C:/development/github-repos/K/kwb.misa")
files <- dir_r_files("~/R-Development/RScripts")
cat("\n ")
+ files <- files[1]
+
# Apply the configuration for all files
for (i in seq_along(files)) {
file <- files[i]
- #cat(sprintf("%3d: %s\n", i, file))
- cat(sprintf("%s%5d", kwb.utils::backspace(5L), i))
+ #cat_formatted("%3d: %s\n", i, file)
+ cat_formatted("%s%5d", backspace(5L), i)
tree <- parse(file, keep.source = TRUE)
new_tree <- try(kwb.code::walk_tree(
tree,
@@ -83,7 +81,7 @@ if (FALSE)
config = config,
context = list(file = file)
))
- if (!kwb.utils::isTryError(new_tree)) {
+ if (!is_try_error(new_tree)) {
try(stopifnot(identical(tree, new_tree)))
}
}
@@ -104,5 +102,5 @@ save_deparsed_for_comparison <- function(tree1, tree2)
{
writeLines(deparse(tree1), "parse-tree_1.txt")
writeLines(deparse(tree2), "parse-tree_2.txt")
- kwb.utils::hsOpenWindowsExplorer(getwd())
+ open_windows_explorer(getwd())
}
diff --git a/inst/extdata/codeUsage.R b/inst/extdata/codeUsage.R
index 263de1a..2e4c5e5 100644
--- a/inst/extdata/codeUsage.R
+++ b/inst/extdata/codeUsage.R
@@ -38,7 +38,7 @@ if (FALSE)
)
used <- merge(used1, used2, by = "name", all = TRUE)
- used <- used[, kwb.utils::pairwise(names(used), split = "[.]")]
+ used <- used[, pairwise(names(used), split = "[.]")]
View(used)
diff --git a/man/find_function_name_duplicates.Rd b/man/find_function_name_duplicates.Rd
new file mode 100644
index 0000000..d7592e7
--- /dev/null
+++ b/man/find_function_name_duplicates.Rd
@@ -0,0 +1,22 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/find_function_name_duplicates.R
+\name{find_function_name_duplicates}
+\alias{find_function_name_duplicates}
+\title{Find Duplicated Function Names}
+\usage{
+find_function_name_duplicates(
+ rscripts = dir("./R", pattern = "\\\\.R$", full.names = TRUE)
+)
+}
+\arguments{
+\item{rscripts}{full paths to R scripts. By default, the paths to all files
+with file name extension ".R" in the "R" subfolder of the current directory
+(if it exists) are used here}
+}
+\value{
+vector of character with the names of functions that were defined
+ at least twice
+}
+\description{
+Find Duplicated Function Names
+}
diff --git a/man/find_string_constants.Rd b/man/find_string_constants.Rd
index ad22a94..89ceff6 100644
--- a/man/find_string_constants.Rd
+++ b/man/find_string_constants.Rd
@@ -7,7 +7,7 @@
find_string_constants(root = "./R")
}
\arguments{
-\item{root}{path from which to look recursively for R scripts}
+\item{root}{path from which to look recursively for R scripts. Default: "./R"}
}
\description{
Show String Constants Used in R Scripts
diff --git a/man/get_full_function_info.Rd b/man/get_full_function_info.Rd
index 01cffe3..91d71a1 100644
--- a/man/get_full_function_info.Rd
+++ b/man/get_full_function_info.Rd
@@ -1,5 +1,5 @@
% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/main.R
+% Please edit documentation in R/get_full_function_info.R
\name{get_full_function_info}
\alias{get_full_function_info}
\title{Get information on function definitions in parsed R scripts}
diff --git a/man/get_function_assignments.Rd b/man/get_function_assignments.Rd
new file mode 100644
index 0000000..8598117
--- /dev/null
+++ b/man/get_function_assignments.Rd
@@ -0,0 +1,21 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/get_function_assignments.R
+\name{get_function_assignments}
+\alias{get_function_assignments}
+\title{Extract the function assignments from an R script}
+\usage{
+get_function_assignments(file, ...)
+}
+\arguments{
+\item{file}{path to R script from which function definitions are to be
+extracted}
+
+\item{\dots}{further arguments passed to \code{\link{parse}}}
+}
+\value{
+named list of expressions. The names of the list elements represent
+ the names of the functions that are defined by the expressions in the list.
+}
+\description{
+Extract the function assignments from an R script
+}
diff --git a/man/normalise_expression.Rd b/man/normalise_expression.Rd
new file mode 100644
index 0000000..a20fcae
--- /dev/null
+++ b/man/normalise_expression.Rd
@@ -0,0 +1,30 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/normalise_expression.R
+\name{normalise_expression}
+\alias{normalise_expression}
+\title{Get the Normalised Structure of an Expression}
+\usage{
+normalise_expression(x, collapse = " ")
+}
+\arguments{
+\item{x}{an expression as returned by \code{\link{parse}} or a vector of
+character representing the text to be parsed}
+
+\item{collapse}{separator string to be put between the single tokens into
+which the expression is split. The default is the space character " ".}
+}
+\value{
+vector of character of length one with attribute "text"
+}
+\description{
+All the different elements of an expression are replaced with nomalised names
+that represent their types, such as: "SYMBOL", "NUM_CONST"
+}
+\examples{
+normalised_1 <- normalise_expression("x + 1")
+normalised_2 <- normalise_expression("y + 2")
+
+# Use c() to remove the attributes
+identical(c(normalised_1), c(normalised_2))
+
+}
diff --git a/man/parse_scripts.Rd b/man/parse_scripts.Rd
index 6decc98..1bba8be 100644
--- a/man/parse_scripts.Rd
+++ b/man/parse_scripts.Rd
@@ -1,5 +1,5 @@
% Generated by roxygen2: do not edit by hand
-% Please edit documentation in R/main.R
+% Please edit documentation in R/parse_scripts.R
\name{parse_scripts}
\alias{parse_scripts}
\title{Parse all given R scripts into a tree structure}
@@ -7,7 +7,8 @@
parse_scripts(
root,
scripts = dir(root, "\\\\.R$", ignore.case = TRUE, recursive = TRUE),
- dbg = TRUE
+ dbg = TRUE,
+ ...
)
}
\arguments{
@@ -18,6 +19,8 @@ parse_scripts(
with ".R" or ".r" below the \code{root} folder (recursively) are parsed.}
\item{dbg}{if \code{TRUE} debug messages are shown}
+
+\item{\dots}{further arguments passed to \code{\link{parse}}}
}
\description{
Parse all given R scripts into a tree structure
@@ -35,7 +38,7 @@ for (url in urls) {
download.file(url, file.path(targetdir, basename(url)))
}
-# By default, all R scripts below the root are parse
+# By default, all R scripts below the root are parsed
trees <- parse_scripts(root = targetdir)
# All elements of trees are expressions
diff --git a/man/pipe.Rd b/man/pipe.Rd
new file mode 100644
index 0000000..1f8f237
--- /dev/null
+++ b/man/pipe.Rd
@@ -0,0 +1,20 @@
+% Generated by roxygen2: do not edit by hand
+% Please edit documentation in R/utils-pipe.R
+\name{\%>\%}
+\alias{\%>\%}
+\title{Pipe operator}
+\usage{
+lhs \%>\% rhs
+}
+\arguments{
+\item{lhs}{A value or the magrittr placeholder.}
+
+\item{rhs}{A function call using the magrittr semantics.}
+}
+\value{
+The result of calling `rhs(lhs)`.
+}
+\description{
+See \code{magrittr::\link[magrittr:pipe]{\%>\%}} for details.
+}
+\keyword{internal}
diff --git a/tests/testthat.R b/tests/testthat.R
index 22a5778..5d90233 100644
--- a/tests/testthat.R
+++ b/tests/testthat.R
@@ -1,3 +1,11 @@
+# This file is part of the standard setup for testthat.
+# It is recommended that you do not modify it.
+#
+# Where should you do additional test configuration?
+# Learn more about the roles of various files in:
+# * https://r-pkgs.org/tests.html
+# * https://testthat.r-lib.org/reference/test_package.html#special-files
+
library(testthat)
library(kwb.code)
diff --git a/tests/testthat/test-function-cat_formatted.R b/tests/testthat/test-function-cat_formatted.R
new file mode 100644
index 0000000..a311056
--- /dev/null
+++ b/tests/testthat/test-function-cat_formatted.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:40.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("cat_formatted() works", {
+
+ f <- kwb.code:::cat_formatted
+
+ expect_error(
+ f()
+ # Argument "fmt" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-deparsed_logical_values.R b/tests/testthat/test-function-deparsed_logical_values.R
new file mode 100644
index 0000000..45a6ead
--- /dev/null
+++ b/tests/testthat/test-function-deparsed_logical_values.R
@@ -0,0 +1,9 @@
+#library(testthat)
+
+test_that("deparsed_logical_values() works", {
+
+ f <- kwb.code:::deparsed_logical_values
+
+ expect_identical(f(), c("F", "T", "FALSE", "TRUE"))
+
+})
diff --git a/tests/testthat/test-function-duplicatesToFiles.R b/tests/testthat/test-function-duplicatesToFiles.R
index 9bcea7d..a0ef307 100644
--- a/tests/testthat/test-function-duplicatesToFiles.R
+++ b/tests/testthat/test-function-duplicatesToFiles.R
@@ -22,6 +22,6 @@ test_that("duplicatesToFiles() works", {
capture.output(path <- f(trees, fun_duplicates, function_name = "f1"))
expect_true(file.exists(path))
- expect_true(length(dir(path, "^f1")) > 0L)
+ expect_true(any(grepl("^f1__", basename(path))))
})
diff --git a/tests/testthat/test-function-evaluate_checks.R b/tests/testthat/test-function-evaluate_checks.R
new file mode 100644
index 0000000..ff74e6b
--- /dev/null
+++ b/tests/testthat/test-function-evaluate_checks.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:41.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("evaluate_checks() works", {
+
+ f <- kwb.code:::evaluate_checks
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-expected_classes.R b/tests/testthat/test-function-expected_classes.R
new file mode 100644
index 0000000..510f909
--- /dev/null
+++ b/tests/testthat/test-function-expected_classes.R
@@ -0,0 +1,11 @@
+#library(testthat)
+
+test_that("expected_classes() works", {
+
+ f <- kwb.code:::expected_classes
+
+ result <- f()
+
+ expect_type(result, "character")
+ expect_true("<-" %in% result)
+})
diff --git a/tests/testthat/test-function-expected_types.R b/tests/testthat/test-function-expected_types.R
new file mode 100644
index 0000000..15e7ce4
--- /dev/null
+++ b/tests/testthat/test-function-expected_types.R
@@ -0,0 +1,11 @@
+#library(testthat)
+
+test_that("expected_types() works", {
+
+ f <- kwb.code:::expected_types
+
+ result <- f()
+
+ expect_type(result, "character")
+ expect_true("logical" %in% result)
+})
diff --git a/tests/testthat/test-function-extract_by_path.R b/tests/testthat/test-function-extract_by_path.R
index b1a5922..aae0ce8 100644
--- a/tests/testthat/test-function-extract_by_path.R
+++ b/tests/testthat/test-function-extract_by_path.R
@@ -1,16 +1,28 @@
-#
-# This test file has been generated by kwb.test::create_test_files()
-# launched by user hauke on 2021-11-27 17:51:42.
-# Your are strongly encouraged to modify the dummy functions
-# so that real cases are tested. You should then delete this comment.
-#
+#library(testthat)
test_that("extract_by_path() works", {
- expect_error(
- kwb.code:::extract_by_path()
- # Argument "paths" fehlt (ohne Standardwert)
+ f <- kwb.code:::extract_by_path
+
+ expect_error(f())
+ expect_error(f("a"))
+
+ x <- list(
+ list( # [[1]]
+ 11,
+ 12
+ ),
+ list( # [[2]]
+ 21,
+ 22,
+ list(
+ 231,
+ 232
+ )
+ )
)
-
+
+ expect_identical(f(x, "1"), x[1L])
+ expect_identical(f(x, c("1", "2")), x[c(1, 2)])
+ expect_identical(f(x, c("/1/1", "2/2", "/2/3/2")), list(11, 22, 232))
})
-
diff --git a/tests/testthat/test-function-find_code_snippets.R b/tests/testthat/test-function-find_code_snippets.R
new file mode 100644
index 0000000..11ae4c8
--- /dev/null
+++ b/tests/testthat/test-function-find_code_snippets.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:38.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("find_code_snippets() works", {
+
+ f <- kwb.code:::find_code_snippets
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-find_function_name_duplicates.R b/tests/testthat/test-function-find_function_name_duplicates.R
new file mode 100644
index 0000000..ee58cbc
--- /dev/null
+++ b/tests/testthat/test-function-find_function_name_duplicates.R
@@ -0,0 +1,15 @@
+#library(testthat)
+
+test_that("find_function_name_duplicates() works", {
+
+ f <- kwb.code::find_function_name_duplicates
+
+ file <- tempfile("test_", fileext = ".R")
+
+ writeLines(con = file, c(
+ "f1 <- function(x) x + 1",
+ "f1 <- function(y) y + 2"
+ ))
+
+ expect_identical(f(file), "f1")
+})
diff --git a/tests/testthat/test-function-find_weaknesses_in_scripts.R b/tests/testthat/test-function-find_weaknesses_in_scripts.R
new file mode 100644
index 0000000..da60203
--- /dev/null
+++ b/tests/testthat/test-function-find_weaknesses_in_scripts.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:38.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("find_weaknesses_in_scripts() works", {
+
+ f <- kwb.code::find_weaknesses_in_scripts
+
+ expect_error(
+ f()
+ # ungültiges 'path' Argument
+ )
+
+})
diff --git a/tests/testthat/test-function-get_elements_by_type.R b/tests/testthat/test-function-get_elements_by_type.R
index a5fa1e6..b03ce08 100644
--- a/tests/testthat/test-function-get_elements_by_type.R
+++ b/tests/testthat/test-function-get_elements_by_type.R
@@ -1,6 +1,8 @@
test_that("get_elements_by_type() works", {
- f <- function(...) kwb.code:::get_elements_by_type(..., dbg = FALSE)
+ f <- function(...) {
+ kwb.code:::get_elements_by_type(..., dbg = FALSE)
+ }
expect_error(f())
@@ -9,5 +11,7 @@ test_that("get_elements_by_type() works", {
result <- f(x)
expect_type(result, "list")
- expect_true("language|call|<-|3|" %in% names(result))
+
+ name <- "language|call|<-|3|call,language,recursive"
+ expect_true(name %in% names(result))
})
diff --git a/tests/testthat/test-function-get_function_assignments.R b/tests/testthat/test-function-get_function_assignments.R
new file mode 100644
index 0000000..e9c03b9
--- /dev/null
+++ b/tests/testthat/test-function-get_function_assignments.R
@@ -0,0 +1,20 @@
+test_that("get_function_assignments() works", {
+
+ f <- kwb.code::get_function_assignments
+
+ expect_error(f())
+
+ file <- tempfile("test-", fileext = ".R")
+
+ writeLines(
+ text = c(
+ "id <- function(x) x",
+ "plus <- function(x, y) x + y"
+ ),
+ con = file
+ )
+
+ result <- f(file)
+
+ expect_identical(names(result), c("id", "plus"))
+})
diff --git a/tests/testthat/test-function-get_function_names_matching.R b/tests/testthat/test-function-get_function_names_matching.R
new file mode 100644
index 0000000..2d49b39
--- /dev/null
+++ b/tests/testthat/test-function-get_function_names_matching.R
@@ -0,0 +1,11 @@
+#library(testthat)
+
+test_that("get_function_names_matching() works", {
+
+ f <- kwb.code:::get_function_names_matching
+
+ result <- f()
+
+ expect_type(result, "character")
+ expect_true(length(result) > 1000L)
+})
diff --git a/tests/testthat/test-function-get_info_on_duplicated_function_names.R b/tests/testthat/test-function-get_info_on_duplicated_function_names.R
new file mode 100644
index 0000000..006a650
--- /dev/null
+++ b/tests/testthat/test-function-get_info_on_duplicated_function_names.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:37.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("get_info_on_duplicated_function_names() works", {
+
+ f <- kwb.code:::get_info_on_duplicated_function_names
+
+ expect_error(
+ f()
+ # Argument "trees" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-get_is_function_names.R b/tests/testthat/test-function-get_is_function_names.R
new file mode 100644
index 0000000..76f1ad0
--- /dev/null
+++ b/tests/testthat/test-function-get_is_function_names.R
@@ -0,0 +1,11 @@
+#library(testthat)
+
+test_that("get_is_function_names() works", {
+
+ f <- kwb.code:::get_is_function_names
+
+ result <- f()
+
+ expect_type(result, "character")
+ expect_true(all(startsWith(result, "is.")))
+})
diff --git a/tests/testthat/test-function-get_parse_info.R b/tests/testthat/test-function-get_parse_info.R
new file mode 100644
index 0000000..9f256a5
--- /dev/null
+++ b/tests/testthat/test-function-get_parse_info.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("get_parse_info() works", {
+
+ f <- kwb.code:::get_parse_info
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-get_properties.R b/tests/testthat/test-function-get_properties.R
new file mode 100644
index 0000000..5a04498
--- /dev/null
+++ b/tests/testthat/test-function-get_properties.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:41.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("get_properties() works", {
+
+ f <- kwb.code:::get_properties
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_bad_function_name.R b/tests/testthat/test-function-is_bad_function_name.R
new file mode 100644
index 0000000..48b385a
--- /dev/null
+++ b/tests/testthat/test-function-is_bad_function_name.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_bad_function_name() works", {
+
+ f <- kwb.code:::is_bad_function_name
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_check.R b/tests/testthat/test-function-is_check.R
new file mode 100644
index 0000000..3c5dbb7
--- /dev/null
+++ b/tests/testthat/test-function-is_check.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:41.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_check() works", {
+
+ f <- kwb.code:::is_check
+
+ expect_error(
+ f()
+ # Argument "check" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_colon_seq.R b/tests/testthat/test-function-is_colon_seq.R
new file mode 100644
index 0000000..9e2a46a
--- /dev/null
+++ b/tests/testthat/test-function-is_colon_seq.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_colon_seq() works", {
+
+ f <- kwb.code:::is_colon_seq
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_colon_seq_1_to_any.R b/tests/testthat/test-function-is_colon_seq_1_to_any.R
new file mode 100644
index 0000000..73e4811
--- /dev/null
+++ b/tests/testthat/test-function-is_colon_seq_1_to_any.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_colon_seq_1_to_any() works", {
+
+ f <- kwb.code:::is_colon_seq_1_to_any
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_colon_seq_1_to_length.R b/tests/testthat/test-function-is_colon_seq_1_to_length.R
new file mode 100644
index 0000000..59cb145
--- /dev/null
+++ b/tests/testthat/test-function-is_colon_seq_1_to_length.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_colon_seq_1_to_length() works", {
+
+ f <- kwb.code:::is_colon_seq_1_to_length
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_colon_seq_1_to_variable.R b/tests/testthat/test-function-is_colon_seq_1_to_variable.R
new file mode 100644
index 0000000..1670018
--- /dev/null
+++ b/tests/testthat/test-function-is_colon_seq_1_to_variable.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_colon_seq_1_to_variable() works", {
+
+ f <- kwb.code:::is_colon_seq_1_to_variable
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_comparison_with_false.R b/tests/testthat/test-function-is_comparison_with_false.R
new file mode 100644
index 0000000..db7c134
--- /dev/null
+++ b/tests/testthat/test-function-is_comparison_with_false.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_comparison_with_false() works", {
+
+ f <- kwb.code:::is_comparison_with_false
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_comparison_with_logical.R b/tests/testthat/test-function-is_comparison_with_logical.R
new file mode 100644
index 0000000..a2bc76e
--- /dev/null
+++ b/tests/testthat/test-function-is_comparison_with_logical.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_comparison_with_logical() works", {
+
+ f <- kwb.code:::is_comparison_with_logical
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_comparison_with_true.R b/tests/testthat/test-function-is_comparison_with_true.R
new file mode 100644
index 0000000..5486405
--- /dev/null
+++ b/tests/testthat/test-function-is_comparison_with_true.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_comparison_with_true() works", {
+
+ f <- kwb.code:::is_comparison_with_true
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_index_path.R b/tests/testthat/test-function-is_index_path.R
new file mode 100644
index 0000000..f66a9c2
--- /dev/null
+++ b/tests/testthat/test-function-is_index_path.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:38.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_index_path() works", {
+
+ f <- kwb.code:::is_index_path
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_logical_constant.R b/tests/testthat/test-function-is_logical_constant.R
new file mode 100644
index 0000000..27fdc1b
--- /dev/null
+++ b/tests/testthat/test-function-is_logical_constant.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_logical_constant() works", {
+
+ f <- kwb.code:::is_logical_constant
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_logical_constant_false.R b/tests/testthat/test-function-is_logical_constant_false.R
new file mode 100644
index 0000000..811b08d
--- /dev/null
+++ b/tests/testthat/test-function-is_logical_constant_false.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_logical_constant_false() works", {
+
+ f <- kwb.code:::is_logical_constant_false
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_logical_constant_true.R b/tests/testthat/test-function-is_logical_constant_true.R
new file mode 100644
index 0000000..44a6074
--- /dev/null
+++ b/tests/testthat/test-function-is_logical_constant_true.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("is_logical_constant_true() works", {
+
+ f <- kwb.code:::is_logical_constant_true
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-is_what.R b/tests/testthat/test-function-is_what.R
index 8ac98ed..0366e02 100644
--- a/tests/testthat/test-function-is_what.R
+++ b/tests/testthat/test-function-is_what.R
@@ -1,17 +1,17 @@
test_that("is_what() works", {
-
- f <- function(...) {
- capture.output(result <- kwb.code:::is_what(..., silent = TRUE))
- result
- }
+
+ f <- kwb.code:::is_what
check <- function(x) {
- result <- f(x)
- expect_true(all(
- sapply(paste0("is.", result), function(name) do.call(name, list(x)))
- ))
+ result_1 <- f(x, dbg = FALSE)
+ expect_output(result_2 <- f(x, dbg = TRUE))
+ expect_identical(result_1, result_2)
+ expect_true(all(sapply(
+ X = paste0("is.", result_1),
+ FUN = function(name) do.call(name, list(x))
+ )))
}
-
+
check(1L)
check(1)
check("a")
diff --git a/tests/testthat/test-function-message_formatted.R b/tests/testthat/test-function-message_formatted.R
new file mode 100644
index 0000000..c5eeb43
--- /dev/null
+++ b/tests/testthat/test-function-message_formatted.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:40.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("message_formatted() works", {
+
+ f <- kwb.code:::message_formatted
+
+ expect_error(
+ f()
+ # Argument "fmt" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-name_parts.R b/tests/testthat/test-function-name_parts.R
new file mode 100644
index 0000000..2186436
--- /dev/null
+++ b/tests/testthat/test-function-name_parts.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("name_parts() works", {
+
+ f <- kwb.code:::name_parts
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-normalise_expression.R b/tests/testthat/test-function-normalise_expression.R
new file mode 100644
index 0000000..c6dbf97
--- /dev/null
+++ b/tests/testthat/test-function-normalise_expression.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:39.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("normalise_expression() works", {
+
+ f <- kwb.code::normalise_expression
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-remove_first_and_last_slash.R b/tests/testthat/test-function-remove_first_and_last_slash.R
new file mode 100644
index 0000000..5fac5f0
--- /dev/null
+++ b/tests/testthat/test-function-remove_first_and_last_slash.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:40.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("remove_first_and_last_slash() works", {
+
+ f <- kwb.code:::remove_first_and_last_slash
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-split_index_path.R b/tests/testthat/test-function-split_index_path.R
new file mode 100644
index 0000000..2350cea
--- /dev/null
+++ b/tests/testthat/test-function-split_index_path.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:38.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("split_index_path() works", {
+
+ f <- kwb.code:::split_index_path
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-stopIfNonExpected.R b/tests/testthat/test-function-stopIfNonExpected.R
new file mode 100644
index 0000000..5c5b7ce
--- /dev/null
+++ b/tests/testthat/test-function-stopIfNonExpected.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:41.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("stopIfNonExpected() works", {
+
+ f <- kwb.code:::stopIfNonExpected
+
+ expect_error(
+ f()
+ # Argument "name" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-stopOnMaxDepth.R b/tests/testthat/test-function-stopOnMaxDepth.R
new file mode 100644
index 0000000..27eac22
--- /dev/null
+++ b/tests/testthat/test-function-stopOnMaxDepth.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:41.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("stopOnMaxDepth() works", {
+
+ f <- kwb.code:::stopOnMaxDepth
+
+ expect_error(
+ f()
+ # Argument "depth" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-stopOnUnexpectedProps.R b/tests/testthat/test-function-stopOnUnexpectedProps.R
new file mode 100644
index 0000000..2db76fa
--- /dev/null
+++ b/tests/testthat/test-function-stopOnUnexpectedProps.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:41.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("stopOnUnexpectedProps() works", {
+
+ f <- kwb.code:::stopOnUnexpectedProps
+
+ expect_error(
+ f()
+ # Argument "props" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-summarise_extracted_matches.R b/tests/testthat/test-function-summarise_extracted_matches.R
new file mode 100644
index 0000000..96d4640
--- /dev/null
+++ b/tests/testthat/test-function-summarise_extracted_matches.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:38.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("summarise_extracted_matches() works", {
+
+ f <- kwb.code:::summarise_extracted_matches
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-to_matches_function.R b/tests/testthat/test-function-to_matches_function.R
new file mode 100644
index 0000000..ac76b86
--- /dev/null
+++ b/tests/testthat/test-function-to_matches_function.R
@@ -0,0 +1,16 @@
+#library(testthat)
+
+test_that("to_matches_function() works", {
+
+ f <- kwb.code:::to_matches_function
+
+ result <- f()
+
+ expect_type(result, "closure")
+
+ checker <- f(check_function = is.logical)
+
+ result <- checker(TRUE)
+ expect_true(result)
+ expect_true(identical(attr(result, "name"), "TRUE"))
+})
diff --git a/tests/testthat/test-function-type_info.R b/tests/testthat/test-function-type_info.R
index 30d12f4..f24bde7 100644
--- a/tests/testthat/test-function-type_info.R
+++ b/tests/testthat/test-function-type_info.R
@@ -1,16 +1,26 @@
-#
-# This test file has been generated by kwb.test::create_test_files()
-# launched by user hauke on 2021-11-27 17:51:46.
-# Your are strongly encouraged to modify the dummy functions
-# so that real cases are tested. You should then delete this comment.
-#
-
+#library(testthat)
test_that("type_info() works", {
- expect_error(
- kwb.code:::type_info()
- # Argument "x" fehlt (ohne Standardwert)
- )
+ f <- kwb.code:::type_info
+
+ expect_error(f())
-})
+ check_result <- function(x) {
+ expect_type(x, "list")
+ expect_identical(names(x), c(
+ "type",
+ "mode",
+ "class",
+ "length",
+ "text",
+ "is",
+ "n_modes",
+ "n_classes"
+ ))
+ }
+
+ check_result(result <- f(1))
+ check_result(result <- f(list(a = 1, b = 2)))
+ expect_identical(result$length, 2L)
+})
diff --git a/tests/testthat/test-function-walk_tree.R b/tests/testthat/test-function-walk_tree.R
new file mode 100644
index 0000000..3adf348
--- /dev/null
+++ b/tests/testthat/test-function-walk_tree.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:41.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("walk_tree() works", {
+
+ f <- kwb.code::walk_tree
+
+ expect_error(
+ f()
+ # Argument "x" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-warn_formatted.R b/tests/testthat/test-function-warn_formatted.R
new file mode 100644
index 0000000..c31fe0a
--- /dev/null
+++ b/tests/testthat/test-function-warn_formatted.R
@@ -0,0 +1,17 @@
+#
+# This file was generated by kwb.test::create_test_files(),
+# launched by hsonne on 2024-04-30 07:16:40.
+# Please modify the dummy functions so that real cases are
+# tested. Then, delete this comment.
+#
+
+test_that("warn_formatted() works", {
+
+ f <- kwb.code:::warn_formatted
+
+ expect_error(
+ f()
+ # Argument "fmt" fehlt (ohne Standardwert)
+ )
+
+})
diff --git a/tests/testthat/test-function-writeContentsToFiles.R b/tests/testthat/test-function-writeContentsToFiles.R
index 26b42cf..18a1e44 100644
--- a/tests/testthat/test-function-writeContentsToFiles.R
+++ b/tests/testthat/test-function-writeContentsToFiles.R
@@ -8,5 +8,5 @@ test_that("writeContentsToFiles() works", {
capture.output(f(list("a", "b"), target_dir, "f"))
- expect_true(all(c("f_1.txt", "f_2.txt") %in% dir(target_dir)))
+ expect_true(all(c("f__1.txt", "f__2.txt") %in% dir(target_dir)))
})
diff --git a/tests/testthat/test-function-writeContentsToLessFiles.R b/tests/testthat/test-function-writeContentsToLessFiles.R
index d0e9493..382aac0 100644
--- a/tests/testthat/test-function-writeContentsToLessFiles.R
+++ b/tests/testthat/test-function-writeContentsToLessFiles.R
@@ -8,5 +8,5 @@ test_that("writeContentsToLessFiles() works", {
capture.output(f(list("a", "b"), target_dir, "f"))
- expect_true(all(c("f__v_1.txt", "f__v_2.txt") %in% dir(target_dir)))
+ expect_true(all(c("f__unique-1.txt", "f__unique-2.txt") %in% dir(target_dir)))
})
diff --git a/vignettes/usage.Rmd b/vignettes/usage.Rmd
index 2125b18..e508fd3 100644
--- a/vignettes/usage.Rmd
+++ b/vignettes/usage.Rmd
@@ -22,34 +22,29 @@ In order to test the functions of this package some R scripts are downloaded
from GitHub and provided locally:
```{r}
-# Define URLs to some example scripts
-urls <- kwb.utils::resolve(list(
- kwb = "https://raw.githubusercontent.com/KWB-R",
- utils = "/kwb.utils/master/R",
- log = "/log.R",
- main = "/main.R",
- fakin = "/kwb.fakin/master/R/plot_file_distribution.R"
-))
+`%>%` <- magrittr::`%>%`
# Create a temporary folder
-root <- kwb.utils::createDirectory(
- kwb.utils::tempSubdirectory("test"),
- dbg = FALSE
-)
-
-# Helper function to download a text file to the temporary folder
-download_script <- function(url) {
- download.file(
- url,
- destfile = file.path(root, basename(url)),
- mode = "wt"
+root <- kwb.utils::tempSubdirectory("test")
+
+# Function to download a script file from a KWB package on GitHub
+download_kwb_script <- function(repo, script)
+{
+ url <- sprintf(
+ "https://raw.githubusercontent.com/%s/master/R/%s",
+ repo, script
)
+ destfile <- file.path(root, basename(url))
+ download.file(url, destfile = destfile, mode = "wt")
+ destfile
}
# Download three scripts to the temporary folder
-download_script(urls$fakin)
-download_script(urls$log)
-download_script(urls$main)
+scripts <- c(
+ download_kwb_script("KWB-R/kwb.utils", "log.R"),
+ download_kwb_script("KWB-R/kwb.utils", "main.R"),
+ download_kwb_script("KWB-R/kwb.fakin", "plot_file_distribution.R")
+)
```
## Exported functions
@@ -74,7 +69,7 @@ The idea probably was to use these information to extract objects of special
interest from the parse tree (see below: get_elements_by_type())
```{r}
-x <- parse(urls$log)
+x <- parse(scripts[1L])
result <- kwb.code::analyse(x)
```
@@ -125,7 +120,7 @@ This function groups similar elements that are found in a parse tree.
```{r}
# Parse an R script file (here, a file from kwb.utils)
-x <- parse(urls$log)
+x <- parse(scripts[1L])
# For each "type" of code segment, extract all occurrences
elements <- kwb.code::get_elements_by_type(x, result = result)
@@ -169,7 +164,7 @@ reveals:
```{r}
pattern <- "[^A-Za-z_.]([A-Za-z_.]+::[A-Za-z_.]+)[^A-Za-z_.]"
-text <- grep(pattern, readLines(urls$fakin), value = TRUE)
+text <- grep(pattern, readLines(scripts[3L]), value = TRUE)
unique(kwb.utils::extractSubstring(pattern, text, index = 1))
```
@@ -233,7 +228,21 @@ knitr::kable(script_statistics)
This function walks along a parse tree.
```{r}
-x <- parse(urls$log)
+x <- parse(scripts[1L])
result <- kwb.code::walk_tree(x, dbg = FALSE)
```
+
+# Interesting base functions
+
+## getParseData()
+
+```{r}
+"sum(kwb.utils::selectColumns(df, col))" %>%
+ parse(text = ., keep.source = TRUE) %>%
+ getParseData()
+
+"do.call(kwb.utils::selectColumns, list(df, col))" %>%
+ parse(text = ., keep.source = TRUE) %>%
+ getParseData()
+```