Skip to content

Instantly share code, notes, and snippets.

@jmbarbone
Last active November 17, 2023 16:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jmbarbone/72a62689b6e159866c3f98b64fe0d180 to your computer and use it in GitHub Desktop.
Save jmbarbone/72a62689b6e159866c3f98b64fe0d180 to your computer and use it in GitHub Desktop.
`include()` R function for attaching objects
include <- function(
    package, 
    exports = NULL, 
    lib.loc = .libPaths(), 
    envir = parent.frame(),
    pos = 2,
    warn.conflicts = TRUE
) {
  loadNamespace(package, lib.loc = lib.loc)
  
  if (is.null(exports)) {
    attach_name <- paste0("include:", package)
    
    if (attach_name %in% search()) {
      detach(attach_name, character.only = TRUE)
    }
    
    attach(
      what = asNamespace(package), 
      pos = pos,
      name = attach_name,
      warn.conflicts = warn.conflicts
    )
    return(invisible())
  }
  
  nm <- names(exports)
  
  if (is.null(nm)) {
    nm <- exports
  }
  
  attach_name <- paste0("include:", package)
  m <- match(attach_name, search())
  
  if (is.na(m)) {
    attach_env <- new.env()
    on.exit({
      attach(
        what = attach_env, 
        pos = pos,
        name = attach_name, 
        warn.conflicts = warn.conflicts
      )
    })
  } else {
    attach_env <- as.environment(m)
  }
  
  package <- asNamespace(package)
  
  for (i in seq_along(exports)) {
    assign(nm[i], getExportedValue(package, exports[i]), attach_env)
  }
  
  invisible()
}

include("fuj")
head(ls("include:fuj"), 20)
#>  [1] "%::%"                       "%:::%"                     
#>  [3] "%||%"                       "%|||%"                     
#>  [5] "%attr%"                     "%colons%"                  
#>  [7] "%len%"                      "%names%"                   
#>  [9] "%out%"                      "%wi%"                      
#> [11] "%wo%"                       "add"                       
#> [13] "any_match"                  "collapse"                  
#> [15] "colons_check"               "colons_example"            
#> [17] "cond_colons"                "cond_muffle"               
#> [19] "cond_namespace"             "cond_new_conditional_class"
detach("include:fuj", character.only = TRUE)

include("fuj", "collapse")
ls("include:fuj")
#> [1] "collapse"
include("fuj", c(
  no_names = "remove_names",
  match_any = "any_match"
))
ls("include:fuj")
#> [1] "collapse"  "match_any" "no_names"

Created on 2023-11-17 with reprex v2.0.2.9000

#' Include exports
#'
#' Include (attach) a package and specific exports
#'
#' @description [include()] checks whether or not the namespace has been loaded
#' to the [search()] path. It uses the naming convention `include:{package}`
#' to denote the differences from loading via [library()] or [require()]. When
#' `exports` is `NULL`, the environment is detached from the search path if
#' found. When `exports` is not `NULL`,
#'
#' @param exports A character vector of exports. When named, these exports will
#' be aliases as such.
#' @inheritParams base::loadNamespace
#' @inheritParams base::attach
#' @returns Nothing, called for its side-effects
#' @examples
#' # include(package) will ensure that the entire package is attached
#' include("fuj")
#' head(ls("include:fuj"), 20)
#' detach("include:fuj", character.only = TRUE)
#'
#' # include a single export
#' include("fuj", "collapse")
#'
#' # include multiple exports, and alias
#' include("fuj", c(
#' no_names = "remove_names",
#' match_any = "any_match"
#' ))
#'
#' # include an export where the alias has a warn conflict
#' include("fuj", c(attr = "exattr"))
#'
#' # note that all 4 exports are included
#' ls("include:fuj")
#'
#' # all exports are the same
#' identical(collapse, fuj::collapse)
#' identical(no_names, fuj::remove_names)
#' identical(match_any, fuj::any_match)
#' identical(attr, fuj::exattr)
#' @export
include <- function(
package,
exports = NULL,
lib.loc = .libPaths(),
pos = 2,
warn.conflicts = TRUE
) {
loadNamespace(package, lib.loc = lib.loc)
if (is.null(exports)) {
attach_name <- paste0("include:", package)
if (attach_name %in% search()) {
detach(attach_name, character.only = TRUE)
}
attach(
what = asNamespace(package),
pos = pos,
name = attach_name,
warn.conflicts = warn.conflicts
)
return(invisible())
}
nm <- names(exports)
if (is.null(nm)) {
nm <- exports
}
attach_name <- paste0("include:", package)
m <- match(attach_name, search())
if (is.na(m)) {
attach_env <- new.env(parent = baseenv())
on.exit({
attach(
what = attach_env,
pos = pos,
name = attach_name,
warn.conflicts = warn.conflicts
)
})
} else {
attach_env <- as.environment(m)
}
package <- asNamespace(package)
for (i in seq_along(exports)) {
assign(nm[i], getExportedValue(package, exports[i]), attach_env)
}
invisible()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment