diff --git a/DESCRIPTION b/DESCRIPTION index ed701f2d2..51a728f2a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -56,7 +56,6 @@ Collate: 'with.r' 'install-bitbucket.r' 'path.r' - 'namespace.r' 'reload-devtools.r' 'run-loadhooks.r' 'env-utils.r' @@ -68,3 +67,5 @@ Collate: 'compile.r' 'load-dll.r' 'utils.r' + 'imports-env.r' + 'namespace-env.r' diff --git a/R/imports-env.r b/R/imports-env.r new file mode 100644 index 000000000..8cb1697e2 --- /dev/null +++ b/R/imports-env.r @@ -0,0 +1,86 @@ +#' Return imports environment for a package +#' +#' Contains objects imported from other packages. Is the parent of the +#' package namespace environment, and is a child of , +#' which is a child of R_GlobalEnv. +#' @keywords programming +#' @seealso \code{\link{ns_env}} for the namespace environment that +#' all the objects (exported and not exported). +#' @seealso \code{\link{pkg_env}} for the attached environment that contains +#' the exported objects. +#' @export +imports_env <- function(pkg = NULL) { + pkg <- as.package(pkg) + + if (!is_loaded(pkg)) { + stop("Namespace environment must be created before accessing imports environment.") + } + + env <- parent.env(ns_env(pkg)) + + if (attr(env, 'name') != imports_env_name(pkg)) { + stop("Imports environment does not have attribute 'name' with value ", + imports_env_name(pkg), + ". This probably means that the namespace environment was not created correctly.") + } + + env +} + + +# Generate name of package imports environment +# Contains exported objects +imports_env_name <- function(pkg = NULL) { + pkg <- as.package(pkg) + paste("imports:", pkg$package, sep = "") +} + + +#' Load all of the imports for a package +#' +#' The imported objects are copied to the imports environment, and are not +#' visible from R_GlobalEnv. This will automatically load (but not attach) +#' the dependency packages. +#' +#' @keywords internal +load_imports <- function(pkg = NULL, deps = c("depends", "imports")) { + pkg <- as.package(pkg) + + # Get data frame of dependency names and versions + deps <- lapply(pkg[deps], parse_deps) + deps <- Reduce(rbind, deps) + + if (is.null(deps) || nrow(deps) == 0) return(invisible()) + + # If we've already loaded imports, don't load again (until load_all + # is run with reset=TRUE). This is to avoid warnings when running + # process_imports() + if (length(ls(imports_env(pkg))) > 0) return(invisible(deps)) + + mapply(check_dep_version, deps$name, deps$version, deps$compare) + + process_imports(pkg) + + invisible(deps) +} + + +# Load imported objects +# The code in this function is taken from base::loadNamespace +process_imports <- function(pkg) { + nsInfo <- parse_ns_file(pkg) + ns <- ns_env(pkg) + lib.loc <- NULL + + ## process imports + for (i in nsInfo$imports) { + if (is.character(i)) + namespaceImport(ns, loadNamespace(i)) + else + namespaceImportFrom(ns, loadNamespace(i[[1L]]), i[[2L]]) + } + for(imp in nsInfo$importClasses) + namespaceImportClasses(ns, loadNamespace(imp[[1L]]), imp[[2L]]) + for(imp in nsInfo$importMethods) + namespaceImportMethods(ns, loadNamespace(imp[[1L]]), imp[[2L]]) +} diff --git a/R/load.r b/R/load.r index ea0fbaa49..5a8845e54 100644 --- a/R/load.r +++ b/R/load.r @@ -85,7 +85,7 @@ load_all <- function(pkg = NULL, reset = FALSE, recompile = FALSE, } # If installed version of package loaded, unload it - if (is.loaded_ns(pkg) && is.null(dev_meta(pkg$package))) { + if (is_loaded(pkg) && is.null(dev_meta(pkg$package))) { unload(pkg) } @@ -94,7 +94,7 @@ load_all <- function(pkg = NULL, reset = FALSE, recompile = FALSE, if (reset) { clear_cache() - clear_pkg_env(pkg) + if (is_loaded(pkg)) unload(pkg) } if (recompile) clean_dll(pkg) @@ -104,9 +104,11 @@ load_all <- function(pkg = NULL, reset = FALSE, recompile = FALSE, # Set up the namespace environment ---------------------------------- - nsenv <- ns_env(pkg, create = TRUE) + # This mimics the procedure in loadNamespace - out <- list(env = nsenv) + if (!is_loaded(pkg)) create_ns_env(pkg) + + out <- list(env = ns_env(pkg)) # Load dependencies into the imports environment load_imports(pkg) @@ -118,21 +120,18 @@ load_all <- function(pkg = NULL, reset = FALSE, recompile = FALSE, # Set up the exports in the namespace metadata (this must happen after # the objects are loaded) - setup_ns_exports(pkg) + setup_ns_exports(pkg, export_all) run_onload(pkg) # Set up the package environment ------------------------------------ - # Create the package environment and copy over objects from the - # namespace environment. - attach_ns(pkg, export_all) + # Create the package environment if needed + if (!is_attached(pkg)) attach_ns(pkg) + + # Copy over objects from the namespace environment + export_ns(pkg) run_onattach(pkg) invisible(out) } - - -is.locked <- function(pkg = NULL) { - environmentIsLocked(as.environment(env_pkg_name(pkg))) -} diff --git a/R/metadata.r b/R/metadata.r index acdb9efa1..f5885810b 100644 --- a/R/metadata.r +++ b/R/metadata.r @@ -3,8 +3,6 @@ #' If the package was not loaded with devtools, returns \code{NULL}. #' #' @param name The name of a loaded package -#' @param create If the metadata environment does not exist, create it? -#' For internal use only. #' @examples #' dev_meta("stats") # NULL #' @@ -19,19 +17,30 @@ #' # Clean up. #' unload(devtest("load-hooks")) #' @export -dev_meta <- function(name, create = FALSE) { +dev_meta <- function(name) { ns <- .Internal(getRegisteredNamespace(as.name(name))) if (is.null(ns)) { stop("Namespace not found for ", name, ". Is it loaded?") } if (is.null(ns$.__DEVTOOLS__)) { - if (create) { - ns$.__DEVTOOLS__ <- new.env(parent = ns) - } else { - return(NULL) - } + return(NULL) } ns$.__DEVTOOLS__ } + + +# Create the devtools metadata environment for a package. +# This should be run when packages are loaded by devtools. +create_dev_meta <- function(name) { + ns <- .Internal(getRegisteredNamespace(as.name(name))) + + if (!is.null(ns$.__DEVTOOLS__)) { + stop("devtools metadata for package ", name, " already exists.") + } + + ns$.__DEVTOOLS__ <- new.env(parent = ns) + + ns$.__DEVTOOLS__ +} diff --git a/R/namespace.r b/R/namespace-env.r similarity index 54% rename from R/namespace.r rename to R/namespace-env.r index fd0e84fea..a25f22328 100644 --- a/R/namespace.r +++ b/R/namespace-env.r @@ -1,3 +1,48 @@ +#' Return the namespace environment for a package. +#' +#' Contains all (exported and non-exported) objects, and is a descendent of +#' \code{R_GlobalEnv}. The hieararchy is \code{}, +#' \code{}, \code{}, and then +#' \code{R_GlobalEnv}. +#' +#' If the package is not loaded, this function returns \code{NULL}. +#' +#' @param pkg package description, can be path or package name. See +#' \code{\link{as.package}} for more information +#' @keywords programming +#' @seealso \code{\link{pkg_env}} for the attached environment that +#' contains the exported objects. +#' @seealso \code{\link{imports_env}} for the environment that contains +#' imported objects for the package. +#' @export +ns_env <- function(pkg = NULL) { + pkg <- as.package(pkg) + + if (!is_loaded(pkg)) return(NULL) + + asNamespace(pkg$package) +} + + +# Create the namespace environment for a package +create_ns_env <- function(pkg = NULL) { + pkg <- as.package(pkg) + + if (is_loaded(pkg)) { + stop("Namespace for ", pkg$package, " already exists.") + } + + env <- makeNamespace(pkg$package) + setPackageName(pkg$package, env) + # Create devtools metadata in namespace + create_dev_meta(pkg$package) + + setNamespaceInfo(env, "path", pkg$path) + setup_ns_imports(pkg) + + env +} + # This is taken directly from base::loadNamespace() in R 2.15.1 makeNamespace <- function(name, version = NULL, lib = NULL) { impenv <- new.env(parent = .BaseNamespaceEnv, hash = TRUE) @@ -33,14 +78,26 @@ setup_ns_imports <- function(pkg) { # Read the NAMESPACE file and set up the exports metdata. This must be # run after all the objects are loaded into the namespace because # namespaceExport throw errors if the objects are not present. -setup_ns_exports <- function(pkg) { +setup_ns_exports <- function(pkg, export_all = FALSE) { nsInfo <- parse_ns_file(pkg) - # This code is from base::loadNamespace - exports <- nsInfo$exports - for (p in nsInfo$exportPatterns) - exports <- c(ls(env, pattern = p, all.names = TRUE), exports) + if (export_all) { + exports <- ls(ns_env(pkg), all.names = TRUE) + # List of things to ignore is from loadNamespace. There are also a + # couple things to ignore from devtools. + ignoreidx <- exports %in% c( ".__NAMESPACE__.", + ".__S3MethodsTable__.", ".packageName", ".First.lib", ".onLoad", + ".onAttach", ".conflicts.OK", ".noGenerics", + ".__DEVTOOLS__", ".cache") + exports <- exports[!ignoreidx] + + } else { + # This code is from base::loadNamespace + exports <- nsInfo$exports + for (p in nsInfo$exportPatterns) + exports <- c(ls(env, pattern = p, all.names = TRUE), exports) + } # Update the exports metadata for the namespace with base::namespaceExport # It will throw warnings if objects are already listed in the exports # metadata, so catch those warnings and ignore them. @@ -65,29 +122,7 @@ parse_ns_file <- function(pkg) { } -# Create the package environment and copy over objects from the -# namespace environment -attach_ns <- function(pkg, export_all = TRUE) { - pkg <- as.package(pkg) - nsenv <- ns_env(pkg) - pkgenv <- pkg_env(pkg, create = TRUE) - - if (export_all) { - # Copy all the objects from namespace env to package env, so that they - # are visible in global env. - copy_env(nsenv, pkgenv, - ignore = c(".__NAMESPACE__.", ".__S3MethodsTable__.", - ".packageName", ".First.lib", ".onLoad", ".onAttach", - ".conflicts.OK", ".noGenerics")) - - } else { - # Export only the objects specified in NAMESPACE - # This code from base::attachNamespace - exports <- getNamespaceExports(nsenv) - importIntoEnv(pkgenv, exports, nsenv, exports) - } -} - +# Register the S3 methods for this package register_s3 <- function(pkg) { pkg <- as.package(pkg) nsInfo <- parse_ns_file(pkg) @@ -95,3 +130,11 @@ register_s3 <- function(pkg) { # Adapted from loadNamespace registerS3methods(nsInfo$S3methods, pkg$package, ns_env(pkg)) } + + +# Reports whether a package is loaded into a namespace. It may be +# attached or not attached. +is_loaded <- function(pkg = NULL) { + pkg <- as.package(pkg) + pkg$package %in% loadedNamespaces() +} diff --git a/R/package-deps.r b/R/package-deps.r index 415042b77..9d56f6ac8 100644 --- a/R/package-deps.r +++ b/R/package-deps.r @@ -35,33 +35,6 @@ parse_deps <- function(string) { deps[names != "R", ] } -#' Load all of the imports for a package -#' -#' The imported objects are copied to the imports environment, and are not -#' visible from R_GlobalEnv. This will automatically load (but not attach) -#' the dependency packages. -#' -#' @keywords internal -load_imports <- function(pkg = NULL, deps = c("depends", "imports")) { - pkg <- as.package(pkg) - - # Get data frame of dependency names and versions - deps <- lapply(pkg[deps], parse_deps) - deps <- Reduce(rbind, deps) - - if (is.null(deps) || nrow(deps) == 0) return(invisible()) - - # If we've already loaded imports, don't load again (until load_all - # is run with reset=TRUE). This is to avoid warnings when running - # process_imports() - if (length(ls(imports_env(pkg))) > 0) return(invisible(deps)) - - mapply(check_dep_version, deps$name, deps$version, deps$compare) - - process_imports(pkg) - - invisible(deps) -} #' Check that the version of an imported package satisfies the requirements #' @@ -91,25 +64,3 @@ check_dep_version <- function(dep_name, dep_ver = NA, dep_compare = NA) { } return(TRUE) } - - - -# Load imported objects -# The code in this function is taken from base::loadNamespace -process_imports <- function(pkg) { - nsInfo <- parse_ns_file(pkg) - ns <- ns_env(pkg) - lib.loc <- NULL - - ## process imports - for (i in nsInfo$imports) { - if (is.character(i)) - namespaceImport(ns, loadNamespace(i)) - else - namespaceImportFrom(ns, loadNamespace(i[[1L]]), i[[2L]]) - } - for(imp in nsInfo$importClasses) - namespaceImportClasses(ns, loadNamespace(imp[[1L]]), imp[[2L]]) - for(imp in nsInfo$importMethods) - namespaceImportMethods(ns, loadNamespace(imp[[1L]]), imp[[2L]]) -} diff --git a/R/package-env.r b/R/package-env.r index 8f09e6809..dd5bc6995 100644 --- a/R/package-env.r +++ b/R/package-env.r @@ -1,117 +1,70 @@ -#' Generate a namespace environment for a package. -#' -#' Contains all (exported and non-exported) objects, and is a descendent of -#' \code{R_GlobalEnv}. The hieararchy is \code{}, -#' \code{}, \code{}, and then -#' \code{R_GlobalEnv}. -#' -#' @param pkg package description, can be path or package name. See -#' \code{\link{as.package}} for more information -#' @param create if namespace environment doesn't already exist, -#' create it? -#' @keywords programming -#' @export -ns_env <- function(pkg = NULL, create = FALSE) { +# Create the package environment where exported objects will be copied to +attach_ns <- function(pkg) { pkg <- as.package(pkg) + nsenv <- ns_env(pkg) - if (!is.loaded_ns(pkg)) { - if (create) { - env <- makeNamespace(pkg$package) - setPackageName(pkg$package, env) - # Create devtools metadata in namespace - dev_meta(pkg$package, create = TRUE) - - setNamespaceInfo(env, "path", pkg$path) - setup_ns_imports(pkg) - } else { - return(NULL) - } - } else { - env <- asNamespace(pkg$package) + if (is_attached(pkg)) { + stop("Package ", pkg$package, " is already attached.") } - env + # This should be similar to attachNamespace + pkgenv <- attach(NULL, name = pkg_env_name(pkg)) + attr(pkgenv, "path") <- getNamespaceInfo(nsenv, "path") } -#' Generate a package environment +# Copy over the objects from the namespace env to the package env +export_ns <- function(pkg) { + pkg <- as.package(pkg) + nsenv <- ns_env(pkg) + pkgenv <- pkg_env(pkg) + + exports <- getNamespaceExports(nsenv) + importIntoEnv(pkgenv, exports, nsenv, exports) +} + + +#' Return package environment #' -#' This is an environment like \code{}. It is attached, -#' so it is an ancestor of \code{R_GlobalEnv}. +#' This is an environment like \code{}. The package +#' environment contains the exported objects from a package. It is +#' attached, so it is an ancestor of \code{R_GlobalEnv}. #' #' When a package is loaded the normal way, using \code{\link{library}}, #' this environment contains only the exported objects from the #' namespace. However, when loaded with \code{\link{load_all}}, this -#' environment will contain all the objects from the namespace. +#' environment will contain all the objects from the namespace, unless +#' \code{load_all} is used with \code{export_all=FALSE}. +#' +#' If the package is not attached, this function returns \code{NULL}. #' #' @param pkg package description, can be path or package name. See #' \code{\link{as.package}} for more information -#' @param create if package environment doesn't already exist, -#' create it? +#' @keywords programming +#' @seealso \code{\link{ns_env}} for the namespace environment that +#' all the objects (exported and not exported). +#' @seealso \code{\link{imports_env}} for the environment that contains +#' imported objects for the package. #' @export -pkg_env <- function(pkg = NULL, create = FALSE) { +pkg_env <- function(pkg = NULL) { pkg <- as.package(pkg) - name <- env_pkg_name(pkg) + name <- pkg_env_name(pkg) - if (!is.loaded_pkg(pkg)) { - if (create) { - # This should be similar to attachNamespace - pkgenv <- attach(new.env(parent = emptyenv()), name = name) - attr(pkgenv, "path") <- pkg$path - } else { - return(NULL) - } - } + if (!is_attached(pkg)) return(NULL) as.environment(name) } -#' Package imports environment -#' Contains objects imported from other packages. Is the parent of the -#' package namespace environment, and is a child of , -#' which is a child of R_GlobalEnv, -#' @export -imports_env <- function(pkg = NULL) { - pkg <- as.package(pkg) - - if (!is.loaded_ns(pkg)) { - stop("Namespace environment must be created before accessing imports environment.") - } - - env <- parent.env(ns_env(pkg)) - - if (attr(env, 'name') != env_imports_name(pkg)) { - stop("Imports environment does not have attribute 'name' with value ", - env_imports_name(pkg), - ". This probably means that the namespace environment was not created correctly.") - } - - env -} - -#' Detach development environment -#' @keywords internal -clear_pkg_env <- function(pkg = NULL) { - - if (is.loaded_pkg(pkg)) { - unload(pkg) - } -} # Generate name of package environment # Contains exported objects -env_pkg_name <- function(pkg = NULL) { +pkg_env_name <- function(pkg = NULL) { pkg <- as.package(pkg) paste("package:", pkg$package, sep = "") } -# Generate name of package imports environment -# Contains exported objects -env_imports_name <- function(pkg = NULL) { - pkg <- as.package(pkg) - paste("imports:", pkg$package, sep = "") -} -base_env <- function(pkg) { - new.env(parent = emptyenv()) +# Reports whether a package is loaded and attached +is_attached <- function(pkg = NULL) { + pkg_env_name(pkg) %in% search() } diff --git a/R/reload.r b/R/reload.r index 5ea4c1e5c..008f99fa1 100644 --- a/R/reload.r +++ b/R/reload.r @@ -1,4 +1,4 @@ -#' Detach and reload package. +#' Unload and reload package. #' #' If the package is not loaded already, this does nothing. #' @@ -23,25 +23,13 @@ reload <- function(pkg = NULL) { pkg <- as.package(pkg) - if (is.loaded_pkg(pkg)) { + if (is_attached(pkg)) { message("Reloading installed ", pkg$package) unload(pkg) require(pkg$package, character.only = TRUE, quietly = TRUE) } } -# Reports whether a package is loaded and attached -is.loaded_pkg <- function(pkg = NULL) { - env_pkg_name(pkg) %in% search() -} - -# Reports whether a package is loaded into a namespace. It may be -# attached or not attached. -is.loaded_ns <- function(pkg = NULL) { - pkg <- as.package(pkg) - pkg$package %in% loadedNamespaces() -} - #' Unload a package #' #' @param pkg package description, can be path or package name. See diff --git a/inst/tests/load-hooks/R/a.r b/inst/tests/load-hooks/R/a.r index 18c8388d9..b260133c4 100644 --- a/inst/tests/load-hooks/R/a.r +++ b/inst/tests/load-hooks/R/a.r @@ -18,5 +18,8 @@ c <- 1 } .onUnload <- function(libpath) { - .GlobalEnv$.__loadhooks__ <- .GlobalEnv$.__loadhooks__ + 1 + # Increment this variable if it exists in the global env + if (exists(".__loadhooks__", .GlobalEnv)) { + .GlobalEnv$.__loadhooks__ <- .GlobalEnv$.__loadhooks__ + 1 + } } diff --git a/inst/tests/test-attribute.r b/inst/tests/test-attribute.r deleted file mode 100644 index 4939b2236..000000000 --- a/inst/tests/test-attribute.r +++ /dev/null @@ -1,12 +0,0 @@ -context("Attribute") - -test_that("Package environment has correct 'path' attribute", { - load_all("namespace") - pkgenv <- as.environment("package:namespace") - - wd <- normalizePath(devtest("namespace")) - pkg_path <- attr(pkgenv, "path") - - expect_identical(wd, pkg_path) - unload("namespace") -}) diff --git a/inst/tests/test-depend.r b/inst/tests/test-depend.r index bdeb3674d..b526bd953 100644 --- a/inst/tests/test-depend.r +++ b/inst/tests/test-depend.r @@ -13,6 +13,9 @@ test_that("Warned about dependency versions", { test_that("Error on missing dependencies", { # Should give a warning about grid version expect_error(load_all("depend-missing"), "missingpackage not available") + + # Loading process will be partially done; unload it + unload("depend-missing") }) diff --git a/inst/tests/test-dll.r b/inst/tests/test-dll.r index 226bb2c77..fe99bfc84 100644 --- a/inst/tests/test-dll.r +++ b/inst/tests/test-dll.r @@ -55,16 +55,17 @@ test_that("load_all() compiles and loads DLLs", { # Loading again, and reloading - # Should not re-compile (don't have a proper test for it) + # Should not re-compile (don't have a proper test for this) load_all("dll-unload") expect_true(is.null(nulltest())) - # Should not re-compile (don't have a proper test for it) + # load_all when already loaded + # Should not re-compile (don't have a proper test for this) load_all("dll-unload") expect_true(is.null(nulltest())) - # Should re-compile (don't have a proper test for it) - load_all("dll-unload", reset = TRUE) + # Should re-compile (don't have a proper test for this) + load_all("dll-unload", recompile = TRUE) expect_true(is.null(nulltest())) unload("dll-unload") diff --git a/inst/tests/test-metadata.r b/inst/tests/test-metadata.r index 1701dbf97..e7c0ac244 100644 --- a/inst/tests/test-metadata.r +++ b/inst/tests/test-metadata.r @@ -22,3 +22,29 @@ test_that("devtools metadata for load hooks", { test_that("NULL metadata for non-devtools-loaded packages", { expect_true(is.null(dev_meta("stats"))) }) + + +test_that("dev_packages() lists devtools-loaded packages", { + expect_false(any(c("namespace", "loadhooks") %in% dev_packages())) + expect_false("namespace" %in% dev_packages()) + expect_false("loadhooks" %in% dev_packages()) + + load_all("namespace") + expect_true("namespace" %in% dev_packages()) + expect_false("loadhooks" %in% dev_packages()) + + load_all("load-hooks") + expect_true("namespace" %in% dev_packages()) + expect_true("loadhooks" %in% dev_packages()) + + unload("namespace") + expect_false("namespace" %in% dev_packages()) + expect_true("loadhooks" %in% dev_packages()) + + unload("load-hooks") + expect_false("namespace" %in% dev_packages()) + expect_false("loadhooks" %in% dev_packages()) + + + expect_false("stats" %in% dev_packages()) +}) diff --git a/inst/tests/test-namespace.r b/inst/tests/test-namespace.r index c6836d829..b4e48bcba 100644 --- a/inst/tests/test-namespace.r +++ b/inst/tests/test-namespace.r @@ -12,17 +12,17 @@ is_ancestor_env <- function(e, x) { } -test_that("Package objects are visible from global environment", { +test_that("Exported objects are visible from global environment", { - # a is exported, b is not. With load_all(), they should by default - # both be visible in the global env. + # a is listed as an export in NAMESPACE, b is not. But with load_all(), + # they should both be visible in the global env. load_all("namespace") expect_equal(a, 1) expect_equal(b, 2) unload("namespace") - # With export_all = FALSE, only the exported object should be visible + # With export_all = FALSE, only the listed export should be visible # in the global env. load_all("namespace", export_all = FALSE) expect_equal(a, 1) @@ -30,7 +30,7 @@ test_that("Package objects are visible from global environment", { unload("namespace") }) -test_that("All package objects are loaded into namespace environment", { +test_that("All objects are loaded into namespace environment", { load_all("namespace") nsenv <- ns_env("namespace") expect_equal(nsenv$a, 1) @@ -39,14 +39,22 @@ test_that("All package objects are loaded into namespace environment", { }) -test_that("All package objects are copied to package environment", { +test_that("All objects are copied to package environment", { load_all("namespace") pkgenv <- pkg_env("namespace") expect_equal(pkgenv$a, 1) expect_equal(pkgenv$b, 2) unload("namespace") + + # With export_all = FALSE, only the listed export should be copied + load_all("namespace", export_all = FALSE) + pkgenv <- pkg_env("namespace") + expect_equal(pkgenv$a, 1) + expect_false(exists("b", envir = pkgenv)) + unload("namespace") }) + test_that("Unloading and reloading a package works", { load_all("namespace") expect_equal(a, 1) @@ -74,20 +82,16 @@ test_that("Namespace, imports, and package environments have correct hierarchy", load_all("namespace") pkgenv <- pkg_env("namespace") - nsenv <- ns_env("namespace") - imp_env <- imports_env("namespace") - + nsenv <- ns_env("namespace") + impenv <- imports_env("namespace") - expect_identical(parent_envs(nsenv)[[2]], imp_env) + expect_identical(parent_envs(nsenv)[[2]], impenv) expect_identical(parent_envs(nsenv)[[3]], .BaseNamespaceEnv) expect_identical(parent_envs(nsenv)[[4]], .GlobalEnv) # pkgenv should be an ancestor of the global environment expect_true(is_ancestor_env(pkgenv, .GlobalEnv)) - # Import environment should have name attribute - expect_equal(attr(imp_env, "name"), "imports:namespace") - unload("namespace") }) @@ -96,14 +100,13 @@ test_that("unload() removes package environments from search", { load_all("namespace") pkgenv <- pkg_env("namespace") nsenv <- ns_env("namespace") - imp_env <- imports_env("namespace") unload("namespace") unload(inst("compiler")) unload(inst("MASS")) # Should report not loaded for package and namespace environments - expect_false(is.loaded_pkg("namespace")) - expect_false(is.loaded_ns("namespace")) + expect_false(is_attached("namespace")) + expect_false(is_loaded("namespace")) # R's asNamespace function should error expect_error(asNamespace("namespace")) @@ -112,6 +115,28 @@ test_that("unload() removes package environments from search", { # This is what makes the objects inaccessible from global env expect_false(is_ancestor_env(pkgenv, .GlobalEnv)) # Another check of same thing - expect_false(env_pkg_name("namespace") %in% search()) + expect_false(pkg_env_name("namespace") %in% search()) + +}) + + +test_that("Environments have the correct attributes", { + load_all("namespace") + pkgenv <- pkg_env("namespace") + impenv <- imports_env("namespace") + # as.environment finds the same package environment + expect_identical(pkgenv, as.environment("package:namespace")) + + # Check name attribute of package environment + expect_identical(attr(pkgenv, "name"), "package:namespace") + + # Check path attribute of package environment + wd <- normalizePath(devtest("namespace")) + expect_identical(wd, attr(pkgenv, "path")) + + # Check name attribute of imports environment + expect_identical(attr(impenv, "name"), "imports:namespace") + + unload("namespace") }) diff --git a/man/clear_pkg_env.Rd b/man/clear_pkg_env.Rd deleted file mode 100644 index 90580529e..000000000 --- a/man/clear_pkg_env.Rd +++ /dev/null @@ -1,11 +0,0 @@ -\name{clear_pkg_env} -\alias{clear_pkg_env} -\title{Detach development environment} -\usage{ - clear_pkg_env(pkg = NULL) -} -\description{ - Detach development environment -} -\keyword{internal} - diff --git a/man/dev_meta.Rd b/man/dev_meta.Rd index c8f315af0..4fe29646f 100644 --- a/man/dev_meta.Rd +++ b/man/dev_meta.Rd @@ -2,13 +2,10 @@ \alias{dev_meta} \title{Return devtools metadata environment} \usage{ - dev_meta(name, create = FALSE) + dev_meta(name) } \arguments{ \item{name}{The name of a loaded package} - - \item{create}{If the metadata environment does not exist, - create it? For internal use only.} } \description{ If the package was not loaded with devtools, returns diff --git a/man/import_dep.Rd b/man/import_dep.Rd deleted file mode 100644 index 5ae2f76fb..000000000 --- a/man/import_dep.Rd +++ /dev/null @@ -1,25 +0,0 @@ -\name{import_dep} -\alias{import_dep} -\title{Load a package in an "imports" environment.} -\usage{ - import_dep(pkg, dep_name, dep_ver = NA, dep_compare = NA) -} -\arguments{ - \item{pkg}{The package that is doing the importing} - - \item{dep_name}{The name of the package with objects to - import} - - \item{dep_ver}{The version of the package} - - \item{dep_compare}{The comparison operator to use to - check the version} -} -\description{ - All of the exported objects from the imported package are - copied to the imports environment for the development - package. This will automatically load (but not attach) - the imported package. -} -\keyword{internal} - diff --git a/man/imports_env.Rd b/man/imports_env.Rd index 203bb6b7f..383b36962 100644 --- a/man/imports_env.Rd +++ b/man/imports_env.Rd @@ -1,16 +1,21 @@ \name{imports_env} \alias{imports_env} -\title{Package imports environment -Contains objects imported from other packages. Is the parent of the -package namespace environment, and is a child of , -which is a child of R_GlobalEnv,} +\title{Return imports environment for a package} \usage{ imports_env(pkg = NULL) } \description{ - Package imports environment Contains objects imported - from other packages. Is the parent of the package - namespace environment, and is a child of - , which is a child of R_GlobalEnv, + Contains objects imported from other packages. Is the + parent of the package namespace environment, and is a + child of , which is a child of + R_GlobalEnv. } +\seealso{ + \code{\link{ns_env}} for the namespace environment that + all the objects (exported and not exported). + + \code{\link{pkg_env}} for the attached environment that + contains the exported objects. +} +\keyword{programming} diff --git a/man/ns_env.Rd b/man/ns_env.Rd index 0311e5fb0..a1a42848a 100644 --- a/man/ns_env.Rd +++ b/man/ns_env.Rd @@ -1,15 +1,12 @@ \name{ns_env} \alias{ns_env} -\title{Generate a namespace environment for a package.} +\title{Return the namespace environment for a package.} \usage{ - ns_env(pkg = NULL, create = FALSE) + ns_env(pkg = NULL) } \arguments{ \item{pkg}{package description, can be path or package name. See \code{\link{as.package}} for more information} - - \item{create}{if namespace environment doesn't already - exist, create it?} } \description{ Contains all (exported and non-exported) objects, and is @@ -17,5 +14,16 @@ \code{}, \code{}, \code{}, and then \code{R_GlobalEnv}. } +\details{ + If the package is not loaded, this function returns + \code{NULL}. +} +\seealso{ + \code{\link{pkg_env}} for the attached environment that + contains the exported objects. + + \code{\link{imports_env}} for the environment that + contains imported objects for the package. +} \keyword{programming} diff --git a/man/pkg_env.Rd b/man/pkg_env.Rd index e20ca32f5..7e11198b7 100644 --- a/man/pkg_env.Rd +++ b/man/pkg_env.Rd @@ -1,25 +1,36 @@ \name{pkg_env} \alias{pkg_env} -\title{Generate a package environment} +\title{Return package environment} \usage{ - pkg_env(pkg = NULL, create = FALSE) + pkg_env(pkg = NULL) } \arguments{ \item{pkg}{package description, can be path or package name. See \code{\link{as.package}} for more information} - - \item{create}{if package environment doesn't already - exist, create it?} } \description{ - This is an environment like \code{}. It is - attached, so it is an ancestor of \code{R_GlobalEnv}. + This is an environment like \code{}. The + package environment contains the exported objects from a + package. It is attached, so it is an ancestor of + \code{R_GlobalEnv}. } \details{ When a package is loaded the normal way, using \code{\link{library}}, this environment contains only the exported objects from the namespace. However, when loaded with \code{\link{load_all}}, this environment will - contain all the objects from the namespace. + contain all the objects from the namespace, unless + \code{load_all} is used with \code{export_all=FALSE}. + + If the package is not attached, this function returns + \code{NULL}. +} +\seealso{ + \code{\link{ns_env}} for the namespace environment that + all the objects (exported and not exported). + + \code{\link{imports_env}} for the environment that + contains imported objects for the package. } +\keyword{programming} diff --git a/man/reload.Rd b/man/reload.Rd index 662efc635..fd46543c4 100644 --- a/man/reload.Rd +++ b/man/reload.Rd @@ -1,6 +1,6 @@ \name{reload} \alias{reload} -\title{Detach and reload package.} +\title{Unload and reload package.} \usage{ reload(pkg = NULL) }