Environmental variable causes loop in pkgdown::build_suite() - r

This is a continuation from an earlier post (Include Shiny app in R package: Transfer an input parameter) that successfully resolved my question but that led to another problem.
Basically, I am running a Shiny app as part of an R package. To do this, I have an environmental variable PKGENVIR. As can be seen in the previous post, I accomplished this using:
### runExample.R
PKGENVIR <- new.env(parent=emptyenv()) # package level envir
#' #export
runExample <- function(data) {
appDir <- system.file("shiny-examples", "myapp", package = "mypackage")
if (appDir == "") {
stop("Could not find example directory. Try re-installing `mypackage`.", call. = FALSE)
}
PKGENVIR$DATA <- data # put the data into envir
shiny::runApp(appDir, display.mode = "normal")
}
and in server.R:
### inside shiny app
data <- PACKAGE_NAME:::PKGENVIR$DATA ## read the data from envir
However, I am also trying to morph this into a pkgdown site. As a result, I run:
pkgdown::build_site()
However, this seems to create an infinite loop because the process freezes at the step:
Reading 'man/PKGENVIR.Rd'
Any ideas on how to approach this issue would be very helpful. I had been running pkgdown::build_site() before this and had not had issues. Hence, I am almost certain it is due to this new environmental variable.

Related

Check if package installation is required while running code via source()?

I am running several scripts in RStudio and checking syntax errors. I am using source() in a loop to perform those tasks. In some scripts, install.packages("packagename") occurs. My problem is that when i have the required packages already installed in my computer, a message pops up asking me to update the library. In these cases, I would like to be able to "ignore" install.packages("packagename") call and running code to continue without showing any message.
So, how can i check if package installation is required or not while running code via source()?
Bit of a hack, but given the location file, this will list all the packages inside the script:
require(readr)
require(stringr)
listPackages <- function(file)
{
r <- readr::read_file(file)
r = str_replace_all(r, '\\"', "") # remove all quote marks
packages <- str_extract_all(r, regex("(install.packages|library|require|p_load)\\([:alnum:]*\\)*", multiline = TRUE))[[1]]
return(unique(gsub("\\(", "", str_extract(packages, regex("\\([:alnum:]*", multiline = F)))))
}
Example
test.R:
library("ggplot2")
library(stats)
require("cowplot")
require(MASS)
add <- function(x,y) {x+y}
install.packages("cowplot")
p_load(dplyr)
p_load("dplyr")
listPackages("test.R")
# [1] "ggplot2" "stats" "cowplot" "MASS" "cowplot" "dplyr"

What's the most simple approach to name-spacing R files with `file::function`

Criteria for answer to this question
Given the following function (within its own script)
# something.R
hello <- function(x){
paste0("hello ", x)
}
What is the most minimal amount of setup which will enable the following
library(something)
x <- something::hello('Sue')
# x now has value: "hello Sue"
Context
In python it's very simple to have a directory containing some code, and utilise it as
# here foo is a directory
from foo import bar
bar( ... )
I'm not sure how to do something similar in R though.
I'm aware there's source(file.R), but this puts everything into the global namespace. I'm also aware that there's library(package) which provides package::function. What I'm not sure about is whether there's a simple approach to using this namespacing within R. The packaging tutorials that I've searched for seem to be quite involved (in comparison to Python).
I don't know if there is a real benefit in creating a namespace just for one quick function. It is just not the way it is supposed to be (I think).
But anyway here is a rather minimalistic solution:
First install once: install.packages("namespace")
The function you wanted to call in the namespace:
hello <- function(x){
paste0("hello ", x)
}
Creating your namespace, assigning the function and exporting
ns <- namespace::makeNamespace("newspace")
assign("hello",hello ,env = ns)
base::namespaceExport(ns, ls(ns))
Now you can call your function with your new namespace
newspace::hello("you")
Here's the quickest workflow I know to produce a package, using RStudio. The default package already contains a hello function, that I overwrote with your code.
Notice there was also a box "create package based on source files", which I didn't use but you might.
A package done this way will contain exported undocumented untested functions.
If you want to learn how to document, export or not, write tests and run checks, include other objects than functions, include compiled code, share on github, share on CRAN.. This book describes the workflow used by thousands of users, and is designed so you can usually read sections independently.
If you don't want to do it from GUI you can useutils::package.skeleton() to build a package folder, and remotes::install_local() to install it :
Reproducible setup
# create a file containing function definition
# where your current function is located
function_path <- tempfile(fileext = ".R")
cat('
hello <- function(x){
paste0("hello ", x)
}
', file = function_path)
# where you store your package code
package_path <- tempdir()
Solution :
# create package directory at given location
package.skeleton("something", code_file = file_path, path = package_path)
# remove sample doc to make remotes::install_local happy
unlink(file.path(package_path, "something", "man/"), TRUE)
# install package
remotes::install_local(file.path(package_path, "something"))

Suppress static code inspection in R (future package)

I have a long calculation which I am trying to parallelize using future package (specifically within an R shiny application).
I have used dplyr package for all data manipulations and there are a lot of column names that are not referred with quotation marks. When I try to run this function that I know to be working when non parallelized, I get the following error:
Warning: Error in : Identified global objects via static code inspection ({if (i > maxProgress) {; maxProgress <- i; shinyWidgets::updateProgressBar(session = session, id = "pb",; value = 100 * i/length(scanList)); ...; }; return(resultInstance); }). Failed to locate global object in the relevant environments: ‘Months in Service’
because static code inspection thinks ‘Months in Service’ is a global variable and fails to find it (it is in fact a column name of a dplyr tibble), so it never runs my code.
If I do the following globally before calling the function:
`Months in Service` <- NULL
it gives the same error for another column name. So one solution is to define each of those names as global variables and hope dplyr will work the same. However is there another simple way to get around this such as telling R to evaluate everything as it would have done without parallelization (each iteration is completely independent)
Edit 1: I simplified the operation and tested if NULL would actually work. It doesnt, it would complain because it thinks column name is NULL, for example:
no applicable method for 'rename_' applied to an object of class "NULL"
Edit 2: example reproduction
library("dplyr")
library("listenv")
exampleTibb <- tibble(`col 1`=c(1,2,3))
exampleFuture <- listenv()
exampleFuture[[1]] %<-% future({ rename(exampleTibb, `col 2` = `col 1`) })
exampleFuture <- as.list(exampleFuture)
Author of the future package here: This is due to a bug that has been fixed for future 1.8.0. I'm preparing to submit this to CRAN, but in the meanwhile you can either do:
options(future.globals.onMissing = "ignore")
or, better, install the develop version:
remotes::install_github("HenrikBengtsson/future#develop")
UPDATE 2018-04-08: future 1.8.0 is now on CRAN.
UPDATE 2018-04-07: This error only occurs when using nested futures. Note that you introduce nested futures by mistake when you use both %<-% and future(). That is a clearly a mistake. You want to use, either:
exampleFuture[[1]] %<-% { rename(exampleTibb, `col 2` = `col 1`) }
or
exampleFuture[[1]] <- future({ rename(exampleTibb, `col 2` = `col 1`) })
and certainly not both.

Erroneous code diagnostics report in RStudio when sourcing functions via source

I'm working in RStudio on a simple analysis where I source some files via the source command. For example, I have this file with some simple analysis:
analysis.R
# Settings ----------------------------------------------------------------
data("mtcars")
source("Generic Functions.R")
# Some work ---------------------------------------------------------------
# Makes no sense
mtcars$mpg <- CleanPostcode(mtcars$mpg)
The generic functions file has some simple functions that I use to derive graphs and do repetitive tasks. For example the used CleanPostcode function would look like that:
Generic Functions.R
#' The file provides a set of generic functions
# String manipulations ----------------------------------------------------
# Create a clean Postcode for matching
CleanPostcode <- function(MessyPostcode) {
MessyPostcode <- as.character(MessyPostcode)
MessyPostcode <- gsub("[[:space:]]", "", MessyPostcode)
MessyPostcode <- gsub("[[:punct:]]", "", MessyPostcode)
MessyPostcode <- toupper(MessyPostcode)
cln_str <- MessyPostcode
return(cln_str)
}
When I run the first file, the objects are available in the global environment:
There are some other function in the file but they are not relevant to the described problem.
Nevertheless the RStudio sees the object as not available in scope, as illustrated by the yellow triangle next to the code:
Question
Is there a way to make RStudio stop doing that. Maybe changing something to the source command? I tried local = TRUE and got the same thing. The code works with no problems, I just find it annoying.
The report was generated on the version 0.99.491 of RStudio.

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.

Resources