functions in .Rprofile are not found with are in .env - r

I have a .Rprofile I have copied from https://www.r-bloggers.com/fun-with-rprofile-and-customizing-r-startup/ However, when I load my R session the functions that are in env$ they don't work and the functions not in env works perfectly, here is an example:
sshhh <- function(a.package){
suppressWarnings(suppressPackageStartupMessages(
library(a.package, character.only=TRUE)))
}
auto.loads <-c("dplyr", "ggplot2")
if(interactive()){
invisible(sapply(auto.loads, sshhh))
}
.env <- new.env()
attach(.env)
.env$unrowname <- function(x) {
rownames(x) <- NULL
x
}
.env$unfactor <- function(df){
id <- sapply(df, is.factor)
df[id] <- lapply(df[id], as.character)
df
}
message("n*** Successfully loaded .Rprofile ***n")
Once R is loaded I can type sshhh and it shows the function, but if I type unfactor it shows object not found
Any help? Should I put all the functions on my workspace???

They functions created in a separate environment are intentionally hidden. This is to protect them from calls to rm(list=ls()).
From the original article:
[Lines 58-59]: This creates a new hidden namespace that we can store
some functions in. We need to do this in order for these functions to
survive a call to “rm(list=ls())” which will remove everything in the
current namespace. This is described wonderfully in this blog post [1].
To use the unfactor function, you would call .env$unfactor().
If you want to make those function available in the global namespace without having to refer to .env, you can simply leave out the whole .env part and just add the function the same way you did for the sshhh function.
[1] http://gettinggeneticsdone.blogspot.com.es/2013/07/customize-rprofile.html

Related

.onLoad to create a new environment in R

Within a package I intend to submit to CRAN, I am using .onload(...) to create a new environment in which needed variables will be stored without directly modifying the global environment.
.onLoad <- function(...) {
envr <- new.env() # when package is loaded, create new environment to store needed variables
}
This function is saved in a file called zzz.R.
I then use assign(...) to assign variables to the new environment:
assign("x", x, envir = envr)
To retrieve variables in the new environment within my created functions, I do
envr$x
However, on building, installing, loading my package, and running my main function, I receive an error that the object 'envr' cannot be found.
I'm wondering what's happening here.
Creating a new environment directly in R works fine:
envr <- new.env()
envr$a <- 5
envr$a
[1] 5
Any thoughts on resolving the issue?
Your code
envr <- new.env()
assigns the new environment to a local variable in the .onLoad function. When that function exits, the variable isn't visible anywhere else.
You can make your assignment outside the function using <<-, but you have to be careful. That makes R look up through enclosing environments until it finds the variable. If it never finds it, it will do the assignment in the global environment, and that's not yours to write in, so CRAN won't accept your package.
So the right way to do this is to create the variable outside any function as suggested in https://stackoverflow.com/a/12605694/2372064, or to create a variable outside the function but create the environment on loading, e.g.
envr <- NULL
.onLoad <- function(...) {
envr <<- new.env() # when package is loaded, create new environment to store needed variables
}

Creating S3 class in an R Package

I have written code that very simply creates an S3 class for a package. I seek to create a new S3 class so that I can develop, e.g., custom print() methods.
I have tested the code in a simple R script, but as soon as the function is wrapped into a package, the functionality breaks and the S3 class is no longer created. I cannot provide reproducible code for the creation of the package, but a simplified version of the function I would like to build into the package is introduced below.
My code works perfectly when written either raw or within a function.
x <- 1:10
class(x)
class(x) <- append(class(x),"newS3class")
class(x) will return c("integer", "newS3class")
Likewise, now, declare a function that does the same thing. This also works fine. In reality, my function foo() first performs some action on the input, and then returns the output with a new class.
foo <- function(y) {
y <- y + 3
class(y) <- append(class(y), "newS3class")
y
}
class(1:5) returns "integer". class(foo(1:5)) returns c("integer", "newS3class"). This is as expected.
But, when I develop a package, e.g., mypkg, and then run mypkg::foo(), the functionality is broken. I.e., (mypkg::foo(1:5)) returns "integer" rather than c("integer", "newS3class").
Is something happening regarding scoping, in the process of building the package from its constituent functions, that is preventing this from working?
The mistake I made here was that I did not properly export the class. To fix this I added the following codeblock, including the export line, before using the roxygen package to build my documentation and NAMESPACE.
#' #export summary.objectclass
makeobjectclass <- function(x) {
class(x) <- c("objectclass", class(x))
x
}

How to get roxygenise() to check for duplicate function definitions

I am compiling a package using roxygen2. I would like to be able to make sure that there no function is defined twice with the same name. However, currently roxygenise() builds the package without issuing a warning.
E.g.
library(roxygen2)
#' Real function
real_function <- function(){print("hello world")}
#' Fake function
real_function <- function(){}
Calling roxygenise() leads to the second definition being used.
I don't think roxygenise can or should do this. If you want to check yourself for duplicate names, you can e.g. run through the files in a directory and attach each file sequentially. The attach function has a warn.conflicts argument that is TRUE by default.
check_duplicate_names <- function(dir){
files <- list.files(dir)
for (file in file.path(dir, files)){
duplicate_test_env <- new.env()
sys.source(file, envir = duplicate_test_env)
attach(duplicate_test_env)
}
for (i in seq_along(files)){
detach(duplicate_test_env)
}
}
check_duplicate_names("path-to-package/R")
Note that if you have duplicate functions within one file this will not work.

Mask a function from `ls` in R

I want to put the following function in my .Rprofile to make installation of bioconductor packages easier:
install.bioconductor <- function(...) {
source("http://bioconductor.org/biocLite.R")
biocLite(...)
}
But when I load a new R session, this function is now listed when I call ls. Is there a way of masking the function from being shown?
You can put it in its own environment and attach that environment to the search path.
myFUNs <- new.env()
myFUNs$install.bioconductor <- function(...) {
source("http://bioconductor.org/biocLite.R")
biocLite(...)
}
attach(myFUNs) # attach to the search path
rm(myFUNs) # remove from .GlobalEnv
# it is still accessible via
# install.bioconductor(...)
Then it be accessible, but will not show up in ls(). (You can see what is attached to the search path with search(), and you can see what is in myFUNs with ls(myFUNs))
Alternatively, as #JoshuaO'Brien mentioned in a comment you can keep it in the .GlobalEnv but add a dot to the beginning of the name (i.e. name it .install.bioconductor) so that it will be "hidden" such that it won't show up with ls(), but will show up with ls(all.names=TRUE).

How do I load objects to the current environment from a function in R?

Instead of doing
a <- loadBigObject("a")
b <- loadBigObject("b")
I'd like to call a function like
loadBigObjects(list("a","b"))
And be able to access the a and b objects.
It is not clear what loadBigObjects() does or where it will look for a and b. How does it load the objects from file or sourcing code?
There are lots of options in general:
sys.source() allows an R file to be sourced to a given environment
load() which will load an .Rdata file to a given environment
assign() in combination with any object created by loadBigObjects() or a call to readRDS() can also load an object to a given environment.
From within your function, you'll want to specify the environment in which to load objects as the Global Environment by using globalenv(). If you don't do that then the object will only exist in the evaluation frame of the running loadBigObjects(). E.g.
loadBigObjects <- function(list) {
lapply(list, function(x) assign(x, readRDS(x), envir = globalenv()))
}
(as per your comment to #GSee's Answer, and assuming the list("a","b") is sufficient information for readRDS() to locate and open the object.
Without knowing anything about what loadBigObject is or does, you can use lapply to apply a function to a list of objects
lapply(list("a", "b"), loadBigObject)
If you provided the code for loadBigObject or at least describe what it is supposed to do, a better loadBigObjects function could probably be written.
The assign function can be used to define a variable in an environment other than the current one.
loadBigObjects <- function(lst) {
lapply(lst, function(l) {
assign(l, loadBigObject(l), envir=globalenv())
}
lst
}
(Not that this is necessarily a good idea.)

Resources