Using library defined function in .Rprofile - r

I have a library foo that defines a function bar that I would like to use as a custom error handler. In order to replace the default error handler with bar, I would run options(stop = bar) so long as bar has been imported.
I would like bar to automatically be set as the default error handler whenever I begin an R session. To that end, I put the following code in my .Rprofile file:
options(defaultPackages=c(getOption("defaultPackages"), "foo"),
error = Bar)
Unfortunately, this won't work. During start up, R will first run everything in .Rprofile and then runs .First.sys in order to load the default packages. This means that foo will be loaded and bar imported after the options are set, meaning that an error will be thrown stating that bar could not be found.
One work around to this is to manually load foo by instead using the following:
if (require(foo))
options(error = Bar)
Is this a safe solution? It seems that automatically loading foo immediately when starting R might cause unforeseen issues when installing a library.
Are there any other solutions besides this? The documentation on the start-up of R says that .First.sys is the very last thing to be run, meaning the default packages will not be loaded until after all other start-up code has been run.

Related

Don't print the name of the directory to stdout when using here::set_here('path')

I'm using the R package 'here' to define my working directory using the following command at the start of my script:
here::set_here(path='/path/to/my_directory/', verbose = F)
Every time I run the script it prints this to the console:
here() starts at /path/to/my_directory
Is there a way to suppress this output? I tried using the invisible() function but that didn't work...
The message you’re seeing is printed when you’re attaching the ‹here› package. Simply don’t do that (it’s unnecessary anyway) to prevent it.
Otherwise, load it as follows:
suppressPackageStartupMessages(library(here))
… yeah, not exactly elegant.

R Hide internal objects in package from autocomplete

I am developing a package in Rstudio and I am trying to save object as internal to the package so that the user cannot see it. I make a default package project in Rstudio called "testpackage" and then execute:
library(devtools)
test.hidden.object <- 1:5
use_data(test.hidden.object,internal = T,overwrite = T)
Then I build the package, which saves it to my library. Then I restart Rstudio, and execute:
library(testpackage)
test.hidden.object
It prints out: [1] 1 2 3 4 5
The environment is empty, executing:
ls()
prints out "character(0)"
From what I understand, it is not possible to hide an object in a package from the user if the user knows the name of object, and I don't want to do that. But what worries me is that the autocomplete functionally is able to find these objects.
In both Rstudio and the R console, if I load the package and then type "test.hid" and then press TAB I can see the object "test.hidden.object" as an option. Should autocomplete be able to reveal internal objects? Am I building the package incorrectly?
To fix this problem I have so far updated R, Rstudio, devtools, and I have manually created the sysdata.rda file myself instead of using "use_data", but each time I am able to see the internal objects with autocomplete.
I think you are mistaken in your description. Autocompletion in RStudio and other R front ends will only show symbols that are visible in the current context. Your users can't make use of symbols that aren't exported, so autocompletion won't display them.
You may see hidden symbols while editing files in your own package, because your package code can see hidden symbols. But your users won't.
Edited to add: I've just followed your instructions more closely, and managed to duplicate what you saw. The problem is that by default the NAMESPACE file declares everything to be public, regardless of the setting for internal. This looks like a devtools misunderstanding or bug.
To fix it, manually edit your NAMESPACE file to make sure only public symbols are exported.
2nd edit: The docs for devtools::use_data have been updated on Github. They now say "If TRUE, stores all objects in a single R/sysdata.rda file. Objects in this file follow the usual export rules. Note that this means they will be exported if you are using the common exportPattern()
rule which exports all objects except for those that start with .."

Debugging package::function() although lazy evaluation is used

How can I debug efficiently in R if packages are unknown due to lazy evaluation. I would like to keep the basic browser() functionality as it works great - even with the testthat package. As explained in the following post, --with-keep.source is set for my project in "project options => Build Tools".
To reproduce the behavior, create a package TestDebug containing
myfun <- function(a,b) {return(a+b)}
and a script example.R
{
browser()
TestDebug::myfun(1,2)
}
Edit: The situation where TestDebug::myfun(1,2) calls otherpackage::myfun2(1,2) should be also covered. I think the situation should occur in every "real" package?
The following works for me.
I have my package TestDebug with my function
myfun <- function(a,b) {return(a+b)}
If I run the script
debug(TestDebug::myfun)
TestDebug::myfun(1,2)
The debugger steps right into the source of TestDebug::myfun() not into the :: function as it does when you place a browser() before the call to TestDebug::myfun(1,2).
As you mention in your question: in real-life situations TestDebug::myfun(1,2) often calls otherpackage::myfun2(1,2). If you try to step into otherpackage::myfun2(1,2) you will end up inside the :: function again.
To prevent this I add this functions called inside other functions to the debug index on the fly:
As soon as you are on the line inside TestDebug::myfun() where otherpackage::myfun2(1,2) is called I run debug(otherpackage::myfun2(1,2)) in the console. After that I can step into otherpackage::myfun2(1,2) without problems and end up in the source code of otherpackage::myfun2(1,2). (..and not in the source code of ::)
Don't forget to call undebug(otherpackage::myfun2(1,2)) after you're sure that your problem is not inside otherpackage::myfun2(1,2) to prevent the debugger to jump into otherpackage::myfun2(1,2) the next time it is called.
If you prefer you can also use debugonce(otherpackage::myfun(1,2)) (instead of debug(..)) to only debug a function once.

Startup script in Rprofile throws 'function not found' errors

I want R to load a certain file on initialization, so naturally I added a source command to my Rprofile so:
.First <- function()
{
cat("\n Welcome to R MotherFnorder!!!\n\n")
setwd("/home/username/Code/R/")
source("/home/username/Code/R/file.R")
}
But now when I start R it throws a 'function not found' error for default functions like runif or rnorm. When I load the same file manually into the workspace I get no errors.
You don't need (or, really, want) to create a .First . If you put those lines into your .Rprofile they'll execute just fine. -- With the proviso #Pascal pointed out, that any function called in your file.R must have its library loaded first. So,
near the bottom of your .Rprofile, just put
library(whatever_packages_needed)
cat("\n Welcome to R MotherFnorder!!!\n\n")
setwd("/home/username/Code/R/")
source("/home/username/Code/R/file.R")
EDIT: I cannot reproduce your problem. I added these lines to the end of my .Rprofile:
#testing SO problem with libloading
library(stats)
runif(10)
And the console returns ten nice numbers.
The reason for the error is that when .First() the packages are not yet loaded.
Although runif and rnorm might seem like default functions, they are actually part of the stats package. And as such, they are NOT available when .First() is called (unless you specifically call that package from within .First)
... which also explains this:
When I load the same file manually into the workspace I get no errors.
After .First() but before you have the chance to run anything manually, the default packages are attached. And hence available to your functions when you call it manually.
The solution is to create a file (if it does not already exist) called
"~/.Rprofile" and put in there the lines you currently have in .First()

"object not found" error when creating a new geom for a package

Full disclosure: this issue is duplicated on the ggplot2 google group
I'm developing a package that makes heavy use of ggplot2. I've created my own geom—geom_rug_alt—as a way of putting rug fringes on the top/right of the plot instead of the default locations.
My problem is that when geom_rug_alt() is defined and called within a single script, it seems to plot just fine. (Please try it yourself to verify that.) But, in my package geom_rug_alt() is defined in one file (CommonFunctions.R) and called in another (the Residuals() function of larger function foo.R). When I call foo.R on something, I get this error:
Error in geom_rug_alt(aes(x = NULL, y = within.group.residuals, color = factor(within.1.sd.of.the.mean.of.all.residuals)), :
object 'GeomRugAlt' not found
Now, I've done a couple of things (suggested by Hadley in this thread) to try to make sure that geom_rug_alt() should work properly within the package:
I define GeomRugAlt as a proto object in a file essentially called CommonFunctions.R within my package. CommonFunctions.R contains lines 3-42 of my example script.
In CommonFunctions.R, I was sure to include the build_accessor() line for geom_rug_alt (line 42 in my example script) after the definition of GeomRugAlt
In the package DESCRIPTION file, I have a collate: line where CommonFunctions.R appears first
In the package DESCRIPTION file, I have a LazyLoad: false line
In CommonFunctions.R, I included a require(ggplot2) call before defining GeomRugAlt as a proto object.
In foo.R, I included a require(ggplot2) call before calling geom_rug_alt() within Residuals().
I'm not sure what else I'm missing. Given that my example script runs just fine, I suspect the issue isn't that my geom doesn't work, but that I'm doing something wrong as part of the package development process.
Sorry for duplicating the issue, but I can't seem to find a thorough solution to the problem :-(
Put export(GeomRugAlt) in the NAMESPACE file.

Resources