Open DavZim opened 1 year ago
Great package Konrad! I love it and find it very useful for complicated projects.
One thing that I was missing every now and then was a way to extract and maybe visualize dependencies of a file/function.
Do you think something like this is worth adding to box? I'd be happy to create a proper draft PR (with less dependencies, cleaner code, tests, etc).
box
A quick-and-dirty function I threw together looks like this: get_box_dependencies which either takes a file or a text and reports its dependencies:
get_box_dependencies
library(stringr) # extracts the box dependencies from a file or a text string get_box_dependencies <- function(file = NULL, text = NULL) { stopifnot( "Either file or text must be provided but not both" = xor(is.null(file), is.null(text))) if (!is.null(file)) text <- paste(readLines(file), collapse = "\n") # remove commented code x <- text |> str_replace_all("#[^\\n]+", "") # extract box dependencies box_txt <- str_extract_all(x, "(?<=box::use\\()[^\\)]*") |> unlist() |> paste(collapse = "\n") |> str_replace_all("\\n", " ") if (nchar(box_txt) == 0) { return(tibble::tibble( type = character(0), dependency = character(0), exports = list(), exports_agg = character(0) )) } # [a-zA-Z0-9\\.\\/]+ Name regex for the packages/files # (\\[[^\\]]+\\])? Maybe followed by text in [] deps <- str_extract_all(box_txt, "[a-zA-Z0-9_\\.\\/]+(\\[[^\\]]+\\])?")[[1]] is_file <- str_detect(deps, "\\/") reps_res <- deps |> str_replace_all("\\[[^\\]]+\\]", "") export_names <- deps |> str_extract_all("(?<=\\[)[^\\]]+(?=\\])") |> sapply(str_split, pattern = ", *") tibble::tibble( type = ifelse(is_file, "file", "package"), dependency = ifelse(!endsWith(reps_res, ".R") & is_file, paste0(reps_res, ".R"), reps_res), exports = export_names, exports_agg = sapply(export_names, \(x) paste(unlist(x), collapse = " ")) ) }
An example of this function is this
test_string <- " box::use( pkg1[fun1, fun2, fun3, fun4], pkg2[...], pkg3 # pkg4[fun5] not used ) box::use( ./file1 , ./file2[ffun1, ffun2, ffun3], folder/file3[...] ) " get_box_dependencies(text = test_string) #> # A tibble: 6 × 4 #> type dependency exports exports_agg #> <chr> <chr> <list> <chr> #> 1 package pkg1 <list [1]> "fun1 fun2 fun3 fun4" #> 2 package pkg2 <list [1]> "..." #> 3 package pkg3 <list [0]> "" #> 4 file ./file1.R <list [0]> "" #> 5 file ./file2.R <list [1]> "ffun1 ffun2 ffun3" #> 6 file folder/file3.R <list [1]> "..."
A larger (but non-reproducible) example output is this code which lists all dependencies and its connections in a directory app/
app/
files <- list.files("app", pattern = "\\.R$", full.names = TRUE, recursive = TRUE) > res <- purrr::map_dfr(files, get_box_dependencies, .id = "file") |> + dplyr::mutate(file = files[as.numeric(file)]) > res # A tibble: 116 × 5 file type dependency exports exports_agg <chr> <chr> <chr> <list> <chr> 1 app/logic/misc.R package shiny <chr [1]> div 2 app/logic/misc.R package shinyWidgets <chr [1]> downloadBttn 3 app/logic/misc.R package data.table <chr [1]> ... 4 app/logic/misc.R package dplyr <chr [1]> group_by 5 app/main.R package shiny <list [1]> div h1 NS tagList moduleServer sliderInput i…
Caveats to the solution above:
bar
foo
#' @export foo <- function(...) { box::use(bar[baz]) }
stringr
tibble
One advantage of having this, is that it would also enable box to warn the user if a function is imported using box::use() but not actually used.
box::use()
Please describe your feature request
Great package Konrad! I love it and find it very useful for complicated projects.
One thing that I was missing every now and then was a way to extract and maybe visualize dependencies of a file/function.
Do you think something like this is worth adding to
box
? I'd be happy to create a proper draft PR (with less dependencies, cleaner code, tests, etc).Quick Example
A quick-and-dirty function I threw together looks like this:
get_box_dependencies
which either takes a file or a text and reports its dependencies:An example of this function is this
A larger (but non-reproducible) example output is this code which lists all dependencies and its connections in a directory
app/
Caveats to the solution above:
box
is used within a function. Eg the followingbar
dependency is picked up but is not reported to belong tofoo
stringr
andtibble
(to a lesser degree) and lots of regex. This can be brought down if needed.