Nothing
#' Select first existing folder from a list
#'
#' @param folders Character vector of folder paths to check
#' @param name Name of the folder type for error messages
#' @return List with folder path and id
#' @keywords internal
select_folder_that_exists <- function(folders, name) {
retval <- NA
id <- NA
for (i in seq_along(folders)) {
if (dir.exists(folders[i])) {
retval <- folders[i]
id <- i
break
}
}
# if multiple folders are provided, then they *must* exist
if (is.na(retval) & length(folders) > 1) {
stop(sprintf("Multiple folders provided to %s, but none exist", name))
} else if (is.na(retval) & length(folders) == 1) {
retval <- folders
id <- 1
}
return(list(
folder = retval,
id = id
))
}
#' Internal function to set results folder
#'
#' @param results Results folder path
#' @param proj Project environment
#' @keywords internal
set_results_internal <- function(results, proj){
if(is.null(results)) return()
proj$results <- strip_and_then_add_trailing_forwardslash(
select_folder_that_exists(results, "results")[["folder"]]
)
today <- format.Date(Sys.time(), "%Y-%m-%d")
# Add SHARED_TODAY to project
if (is.null(proj$results)) {
proj$results_today <- NULL
} else {
proj$results_today <- path(proj$results, today, "/")
}
for (i in names(proj)) {
if (i == "computer_id") next
if (!is.null(proj[[i]]) & !is.na(proj[[i]])) {
if (!dir.exists(proj[[i]])) dir.create(proj[[i]], showWarnings = FALSE, recursive = TRUE)
}
}
# Delete empty folders in results folder
if (!is.null(proj$results)) {
for (f in list.files(proj$results)) {
if (grepl("[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]", f)) {
if (f == today) next # don't want to delete today's folder
f2 <- file.path(proj$results, f)
if (file.exists(f2) && !dir.exists(f2)) next # dont delete files
if (length(list.files(f2)) == 0) {
unlink(f2, recursive = T)
}
}
}
}
}
#' Set results folder after project initialization
#'
#' Sets the results folder in the project environment and creates a date-based subfolder.
#' The date-based folder is accessible via `proj$results_today` and empty date folders
#' are automatically cleaned up when new results are added.
#'
#' @param results A character vector specifying one or more possible results folder paths.
#' The first existing path will be used.
#' @param proj The project environment. Default is `org::project`.
#' @return Nothing. Modifies the `proj` environment to include:
#' \describe{
#' \item{$results}{The base results folder path}
#' \item{$results_today}{Path to today's results folder (format: YYYY-MM-DD)}
#' }
#' @export
set_results <- function(results, proj = org::project) {
if (is.null(proj[["computer_id"]])) stop("not initialized")
if(!identical(proj, project)){
set_results_internal(results, proj)
}
set_results_internal(results, project)
}
#' Initialize project folder structure
#'
#' @param env Environment to source code into
#' @param home Home directory path
#' @param results Results directory path
#' @param encode_from Source encoding
#' @param encode_to Target encoding
#' @param proj Project environment
#' @param ... Additional folder arguments
#' @keywords internal
initialize_project_folders <- function(
env,
home,
results,
encode_from,
encode_to,
proj,
...
){
temp_env <- new.env()
temp_env$home <- strip_and_then_add_trailing_forwardslash(home, encode_from = encode_from, encode_to = encode_to)
if(!is.null(results)) temp_env$results <- strip_and_then_add_trailing_forwardslash(results, encode_from = encode_from, encode_to = encode_to)
today <- format.Date(Sys.time(), "%Y-%m-%d")
arguments <- list(...)
for (i in seq_along(arguments)) {
temp_env[[names(arguments)[i]]] <- strip_and_then_add_trailing_forwardslash(arguments[[i]], encode_from = encode_from, encode_to = encode_to)
}
# If multiple files were provided, then select the folder that exists
for (i in names(temp_env)) {
if (i == "computer_id") next
if (!is.null(temp_env[[i]])) {
if (i == "home") {
temp_env[["computer_id"]] <- select_folder_that_exists(temp_env[[i]], i)[["id"]]
}
temp_env[[i]] <- select_folder_that_exists(temp_env[[i]], i)[["folder"]]
}
}
# Add results_today to path
set_results_internal(results = results, proj = temp_env)
# copy temp_env to proj
for(i in names(temp_env)){
proj[[i]] <- temp_env[[i]]
}
}
#' Source R files into environment
#'
#' @param proj Project environment
#' @param env Target environment for sourcing
#' @param folders_to_be_sourced Folders containing R files
#' @param source_folders_absolute Whether folder paths are absolute
#' @keywords internal
source_to_environment <- function(
proj,
env,
folders_to_be_sourced,
source_folders_absolute
){
for (i in folders_to_be_sourced) {
if (source_folders_absolute) {
folder <- i
} else {
folder <- path(proj$home, i)
}
if (!dir.exists(folder)) {
warning(paste0("Folder ", folder, " does not exist. Creating it now."))
create_dir(folder)
}
message(paste0("Sourcing all code inside ", folder, " into ", environmentName(env)))
# fileSources <- file.path(folder, list.files(folder, pattern = "*.[rR]$"))
file_sources <- ls_files(folder, regexp = "*.[rR]$")
sapply(file_sources, source, env)
}
}
#' Initialize project environment and structure
#'
#' This function initializes a new R project by setting up folder locations and sourcing code files.
#' It creates a standardized project structure with separate locations for code, results, and data.
#' Results are automatically organized by date, and code can be sourced from specified directories.
#'
#' @param env The environment that the code will be sourced into. Use `.GlobalEnv` to source code
#' into the global environment. If a different environment is provided, all functions will
#' be sourced into that environment.
#' @param home The folder containing 'Run.R' and 'R/'. This is the main project directory.
#' @param results The base folder for storing results. A subfolder with today's date will be created
#' and accessible via `org::project$results_today`.
#' @param folders_to_be_sourced Character vector of folder names inside `home` containing .R files
#' to be sourced into the environment.
#' @param install_missing_packages If `TRUE`, scans `folders_to_be_sourced` for package
#' dependencies (via `library()`, `require()`, and `pkg::` usage) and installs any
#' missing packages using `pak` before sourcing. Falls back to `install.packages()`
#' if `pak` is not available. Default is `FALSE`.
#' @param source_folders_absolute If `TRUE`, `folders_to_be_sourced` is treated as absolute paths.
#' If `FALSE`, paths are relative to `home`.
#' @param encode_from Source encoding for file paths (only used on Windows)
#' @param encode_to Target encoding for file paths (only used on Windows)
#' @param ... Additional named arguments for other project folders (e.g., data, raw, etc.)
#' @return An environment containing:
#' - All folder locations as named elements
#' - `$env`: The environment where code was sourced
#' - `$results_today`: Path to today's results folder
#' @details
#' The function performs several key operations:
#' 1. Creates necessary directories if they don't exist
#' 2. Sets up date-based results organization
#' 3. Sources all .R files from specified directories
#' 4. Handles path encoding for cross-platform compatibility
#' 5. Maintains a mirror of settings in `org::project`
#' @examples
#' \dontrun{
#' # Initialize a new project
#' org::initialize_project(
#' home = paste0(tempdir(), "/git/analyses/2019/analysis3/"),
#' results = paste0(tempdir(), "/dropbox/analyses_results/2019/analysis3/"),
#' raw = paste0(tempdir(), "/data/analyses/2019/analysis3/")
#' )
#'
#' # Access project settings
#' org::project$results_today # Today's results folder
#' org::project$raw # Raw data folder
#' }
#' @export
initialize_project <- function(
env = new.env(),
home = NULL,
results = NULL,
folders_to_be_sourced = "R",
install_missing_packages = FALSE,
source_folders_absolute = FALSE,
encode_from = "UTF-8",
encode_to = "latin1",
...
) {
stopifnot(!is.null(home))
if(!identical(env, .GlobalEnv)){
message("You are NOT sourcing into .GlobalEnv. All functions will be sourced into an environment that is returned from this function.")
}
proj <- new.env()
for(p in c(project, proj)){
initialize_project_folders(
env = env,
home = home,
results = results,
encode_from = encode_from,
encode_to = encode_to,
proj = p,
...
)
}
source_folders <- if (source_folders_absolute) {
folders_to_be_sourced
} else {
path(proj$home, folders_to_be_sourced)
}
if (install_missing_packages) {
do_install_missing_packages(source_folders)
} else {
check_missing_packages(source_folders)
}
source_to_environment(
proj = proj,
env = env,
folders_to_be_sourced = folders_to_be_sourced,
source_folders_absolute = source_folders_absolute
)
proj$env <- env
project$env <- env
return(proj)
}
Any scripts or data that you put into this service are public.
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.