Allowing user to change R package global variable - r

I want to make an R package called my_package with the following with the following behavior:
library(my_package)
my_package::get_username() # should throw error "no username set"
my_package::set_username("john doe")
my_package::get_username() # should print "john doe"
I'm not sure how to do this. I tried with the following inside an R file test.R and using source('test.R') it works. But I don't know what would be the proper way to do this when creating a package.
pkg_env <- new.env()
pkg_env$username <- NULL
set_username <- function(username) {
pkg_env$username <- username
}
get_username <- function() {
if (is.null(pkg_env$username)) {
print("ERROR")
} else {
print(pkg_env$username)
}
}

The easiest way of doing what you want is to use options. For example, in devtools, you can set a variety of options using this technique - package?devtools
If you want to use environments, then you need to create the environment when the package is loaded, using the .onLoad function

Related

R: Understand the ".call" function in R

I am using R. I am working with a library called "mco" : https://cran.r-project.org/web/packages/mco/index.html
I was looking over some of the function definitions used in this library at the github repository, for example: https://github.com/olafmersmann/mco/blob/master/R/nsga2.R
Over here, I came across the following lines of code:
res <- .Call(do_nsga2,
ff, cf, sys.frame(),
as.integer(odim),
as.integer(cdim),
as.integer(idim),
lower.bounds, upper.bounds,
as.integer(popsize), as.integer(generations),
cprob, as.integer(cdist),
mprob, as.integer(mdist))
if (1 == length(res)) {
res <- res[[1]]
names(res) <- c("par", "value", "pareto.optimal")
class(res) <- c("nsga2", "mco")
} else {
for (i in 1:length(res)) {
names(res[[i]]) <- c("par", "value", "pareto.optimal")
class(res[[i]]) <- c("nsga2", "mco")
}
class(res) <- "nsga2.collection"
}
return (res)
}
In the very first line of this code, it makes reference to some object called "do_nsga2". But apart from this function, I can't find any reference to "do_nsga2" within the entire package.
Does anyone know what exactly is being "called"?
Thanks
Note: I am trying to copy/paste all the functions from the github repository into my R session, since I am working with an older computer in which directly installing libraries from CRAN is not possible. When I tried to copy/paste all these functions, I got the following error:
Error in nsga2....
object 'do_nsga2' not found

Adding additional documentation to a package in R

Aside from a vignette, I wish to add an additional document as PDF to my package. I can, of course, copy it to the inst/doc directory and it will then be included in the package documentation.
However, I would like to make it easy for the user to display this file. The authors of the edgeR package decided to do the following: the main users manual is distributed as PDF (and is not a regular vignette), and the authors include a function called edgeRUsersGuide() which shows the PDF by means of the following code:
edgeRUsersGuide <- function (view = TRUE) {
f <- system.file("doc", "edgeRUsersGuide.pdf", package = "edgeR")
if (view) {
if (.Platform$OS.type == "windows")
shell.exec(f)
else system(paste(Sys.getenv("R_PDFVIEWER"), f, "&"))
}
return(f)
}
It appears to work. Do you think it is a reasonable approach?
Or should one use something else? Potentially, the following code would also work and be more robust:
z <- list(PDF="edgeR.pdf", Dir=system.file(package="edgeR"))
class(z) <- "vignette"
return(z)
My solution was to ape the code in utils:::print.vignette():
function(docfile) {
## code inspired by tools:::print.vignette
pdfviewer <- getOption("pdfviewer")
f <- system.file("doc", docfile, package = "tmod")
if(identical(pdfviewer, "false"))
stop(sprintf("Cannot display the file %s", f))
if (.Platform$OS.type == "windows" &&
identical(pdfviewer, file.path(R.home("bin"), "open.exe"))) {
shell.exec(f)
} else {
system2(pdfviewer, shQuote(f), wait = FALSE)
}
return(invisible(f))
}

Importing a library inside a function

I am using tensorflow with Rstudio, and trying to make it as simple and as functionalized as possible. I was wondering if there is a way to call a library inside a function, without having to do this :
library(tensorflow)
myFunction(args)
Is there a way to embed the first command in the function, so that I don't have to call it each time before using the function ?
I tried something like that :
Lamdadou <- function(R) {
library(tensorflow)
sess =tf$Session()
K <- sess$run(R)
print(K)
}
But an error rises when I call it :
Error: Python module tensorflow was not found.
Within functions you should use require and not library to load packages.
So your function should look more like this:
Lamdadou <- function(R) {
if (!require(tensorflow)) {
stop("tensorflow not installed")
} else {
sess <- tf$Session()
K <- sess$run(R)
print(K)
}
}

Using external data in a package

In a package I am working on, I would like to use data from another package (say, "pckg"). That package is imported ("Imports: pckg" in DESCRIPTION and import(pckg) in NAMESPACE). In one of the functions, I have the following:
someFunc <- function() {
data(pckgdata)
foo <- pckgdata$whatever
}
This results in the following error message when checking the package:
someFunc: no visible binding for global variable ‘pckgdata’
someFunc : <anonymous>: no visible binding for global variable
‘pckgdata’
Undefined global functions or variables:
pckgdata
How should I correctly use data sets from other packages in my own package?
Here is the description of the answer from #hrbmstr (see comments to the question). In short: first, create a global variable holding a new environment. Then, load the data into that environment. Then, access the data through the global variable:
.myenv <- new.env(parent=emptyenv())
someFunc <- function() {
data("pckgdata", package="pckg", envir=.myenv)
foo <- .myenv$pckgdata$whatever
}

How to create R functions with private variables?

How do I create a set of R functions that all access the same private variable?
Let's say I want to create readSetting(key) and writeSetting(key,value) functions that both operate on the same hidden list settings. If I try it like so...
local( {
settings <- list()
readSetting <<- function ( key ) settings[[key]]
writeSetting <<- function ( key, value ) settings[[key]] = value
} )
...then readSetting and writeSetting are not visible outside of the local call. If I want them to be visible there, I have to first assign
readSetting <- writeSetting <- NULL
outside the local call. There must be a better way, because my code isn't DRY if I have to say in two different ways which variables are public.
(The context of this work is that I'm developing an R package, and this code will be in an auxiliary file loaded into the main file via source.)
This question is related to How to limit the scope of the variables used in a script? but the answers there do not solve my problem.
You can simulate somthing like that using R6Class package and the following very rough code:
Privates <- R6Class("Privates",
public=list(
readSetting = function(key) {
private$settings[[key]]
},
writeSetting = function(key,value) {
private$settings[[key]] <<- value
}
),
private=list(
settings = list()
)
)
a <- Privates$new()
a$writeSetting("a",4)
a$readSetting("a")
Directly reading o setting the a$setting would not work.

Resources