How to check platform in .onLoad in the R package - r

I am trying to check if the package is run on Windows during the loading of the package and load some additional files. For some reason this doesn't work (added to my zzz.R):
.onLoad <- function(libname, pkgname){
if(.Platform$OS.type == "windows") {
# do specific task here
}
}
How to make it work, is there a better way to do it?

EDIT to correct a wrong previous answer
After loading, loadNamespace looks for a hook function named .onLoad and calls it. The functions loadNamespace is usually called implicitly when library is used to load a package. However you can be useful at times to call these functions directly. So the following(essentially your code) works for me under windows platform.
.onLoad <- function(libname, pkgname ) {
if(.Platform$OS.type == "windows") print("windows")
else print("others")
}
Then you test it using:
loadNamespace("loadpkg")
[1] "windows"
<environment: namespace:loadpkg>
Note also you can have the same thing using library, but you should unload the namespace before (I guess it checks if the package is already loaded and don't call all hooks):
unloadNamespace("loadpkg")
library("loadpkg")
[1] "windows"
don't use this , it is a wrong but accepted solution
You should initialize function parameters:
.onLoad <- function(libname = find.package(pkg_name), pkgname = pkg_name){
if(.Platform$OS.type == "windows") {
# do specific task here
}
}

Related

R CMD check Warning: "Undefined global functions or variables"

I am hopeful I can get advise on proper R packaging techniques. When I run R CMD check packagename I get these messages in reference to my zzz.R file:
File ‘packagename/R/zzz.R’:
.onLoad calls:
packageStartupMessage("my message.")
packageStartupMessage("another message.")
packageStartupMessage("and another message)
See section ‘Good practice’ in '?.onAttach'.
.onLoad: no visible global function definition for ‘unzip’
.onLoad: no visible global function definition for ‘file.move’
Undefined global functions or variables:
file.move unzip
Consider adding
importFrom("utils", "unzip")
to your NAMESPACE file.
I'm not entirely clear on what this means.
Per the first message, See section ‘Good practice’ in '?.onAttach'. I don't have an .onAttach() function. I just have an .onLoad() function. My package works fine without .onAttach(), so I am not sure what is being implied here.
I am not sure why I am shown .onLoad: no visible global function definition for ‘unzip’ and .onLoad: no visible global function definition for ‘file.move’ because I use unzip and file.move like this: utils::unzip(), ff::file.move().
How would I add importFrom("utils", "unzip") to my NAMESPACE file? I have not firsthand edited this file because when I open it I get a warning not to edit it by hand.
This is what my zzz.R file looks like:
.onLoad <- function(libname, pkgname) {
quiet <- function(x) {
sink(tempfile())
on.exit(sink())
invisible(force(x))
}
path <- paste0(.libPaths(), "/packagename/")[1]
if(file.exists(paste0(path, "data/"))) { invisible()
} else {
url <- "urlpath"
fname <- paste0(path, "data.zip")
packageStartupMessage("message.")
tryCatch({
utils::download.file(url, fname, mode = "wb")
zip_file <- paste0(path, "data.zip")
utils::unzip(zip_file, exdir = paste0(path, "uncompressed_data"))
from <- paste0(path, "uncompressed_data/data/")
to <- paste0(path, "data/")
quiet(ff::file.move(from, to))
quiet(file.remove(paste0(path, "data.zip")))
quiet(file.remove(paste0(path, "uncompressed_data"))) },
warning = function(cond) {
packageStartupMessage("message.")
packageStartupMessage("message") } )
}
}
My NAMESPACE file just says this:
# Generated by roxygen2: do not edit by hand
Thanks so much for your input.

How to write unit tests for zzz.R file in R package

I am currently developing an R package and used a zzz.R file to set an option value when the package is loaded and also to return a load message. The content of my zzz.R file is as follows:
.onLoad <- function(libname, pkgname) {
op <- options()
op.mypackage <- list(
mypackage.small_neg_threshold = -1e-6
)
toset <- !(names(op.mypackage) %in% names(op))
if (any(toset)) options(op.mypackage[toset])
}
.onAttach <- function(libname, pkgname) {
packageStartupMessage(
"
Hello World!!!
"
)
}
I wondering how one could write a test case in such that entire zzz.R file would be captured as being covered (after running something like devtools::test_coverage()

When creating an R package how do I include warnings that display upon installation? Is there a convenient roxygen2 tag?

I am packaging up some of the functions used by my company regularly. I would like to include warnings in the package that display upon installation/update notifying colleagues of changes that may have downstream effects on their code? Is there a roxgen2 tag I could use in the package documentation?
As far as I know, there is no such tag for package:roxygen2.
But you can edit the function(s) directly. Here is what RPushBullet does (in the context of parsing a config file).
.onLoad <- function(libname, pkgname) {
dotfile <- .getDotfile()
if (file.exists(dotfile)) .parseResourceFile(dotfile)
}
.onAttach <- function(libname, pkgname) {
packageStartupMessage("Attaching RPushbullet version ",
packageDescription("RPushbullet")$Version, ".")
dotfile <- .getDotfile()
if (file.exists(dotfile)) {
packageStartupMessage("Reading ", dotfile)
.parseResourceFile(dotfile)
} else {
txt <- paste("No file", dotfile, "found. Consider placing the",
"Pushbullet API key and your device id(s) there.")
txt <- paste(strwrap(txt), collapse="\n")
packageStartupMessage(txt)
.pkgenv[["pb"]] <- NULL
}
}
So .onLoad() is actually not allowed to print messages, but .onAttach(). As it is more polite to display them in a way that is also suppressable you should not use cat() or warning() directly but packageStartupMessage().
These are commonly placed in a file R/init.R or R/zzz.R.

tryCatch() Vs if else

I have recently started exploring R programming and have a very trivial doubt. I want to write a function which would try to load the required packages and install the same in case its not installed already.
I have written it using if else logic. My question is will it be more efficient if I use tryCatch()? Is there any other advantage than the ability to handle errors as it is not important to handle errors in this context.
Below is the code I am currently using:
Inst.Pkgs=function(){
if (!require(tm))
{install.packages("tm")
require(tm)}
if (!require(SnowballC))
{install.packages("SnowballC")
require(SnowballC)}
if (!require(wordcloud))
{install.packages("wordcloud")
require(wordcloud)}
if (!require(RWeka))
{install.packages("RWeka")
require(RWeka)}
if (!require(qdap))
{install.packages("qdap")
require(qdap)}
if (!require(timeDate))
{install.packages("timeDate")
require(timeDate)}
if (!require(googleVis))
{install.packages("googleVis")
require(googleVis)}
if (!require(rCharts))
{
if (!require(downloader))
{install.packages("downloader")
require(downloader)}
download("https://github.com/ramnathv/rCharts/archive/master.tar.gz", "rCharts.tar.gz")
install.packages("rCharts.tar.gz", repos = NULL, type = "source")
require(rCharts)
}
}
You can check at once and install missing packages.
# Definition of function out, the opposite of in
"%out%" <- function(x, table) match(x, table, nomatch = 0) == 0
# Storing target packages
pkgs <- c("tm", "SnowballC", "wordcloud", "RWeka", "qdap",
"timeDate", "googleVis")
# Finding which target packages are already installed using
# function installed.packages(). Names of packages are stored
# in the first column
idx <- pkgs %out% as.vector(installed.packages()[,1])
# Installing missing target packages
install.packages(pkgs[idx])
We can in fact use tryCatch for this. If the program tries to load a library that is not installed, it will throw an error - an error that can be caught and resolved with a function called by tryCatch().
Here's how I would do it:
needed_libs <- c("tm", "SnowballC", "wordcloud", "RWeka", "qdap", "timeDate", "googleVis")
install_missing <- function(lib){install.packages(lib,repos="https://cran.r-project.org/", dependencies = TRUE); library(lib, character.only = TRUE)}
for (lib in needed_libs) tryCatch(library(lib, character.only=TRUE), error = function(e) install_missing(lib))
This will install the missing packages and load the required libraries, as requested in the OP.

R namespace problems with 'logging' package

I'm writing an R package that uses the logging package from CRAN. In my code, I initialize logging when my package is loaded:
#' #importFrom logging basicConfig
.onAttach <- function(libname, pkgname) {
logging::basicConfig()
}
#' #importFrom logging setLevel
#' #export
setLogLevel <- function(level) {
setLevel(level)
}
And in my DESCRIPTION file I declare the dependency:
Depends:
R (>= 3.0.2),
Rcpp (>= 0.11.2)
Imports:
FNN,
plyr,
geosphere,
logging
However, it looks like R CMD check (which I invoke via "Check Package" in RStudio) doesn't like something about the namespaces:
* checking whether the package can be loaded with stated dependencies ... WARNING
Loading required package: Rcpp
Error : .onAttach failed in attachNamespace() for ‘ABC’, details:
call: UseMethod("updateOptions")
error: no applicable method for ‘updateOptions’ applied to an object of class "Logger"
Error: package or namespace load failed for ‘ABC’
Execution halted
It looks like this package (or one of its dependent packages) has an
unstated dependence on a standard package. All dependencies must be
declared in DESCRIPTION.
See the information on DESCRIPTION files in the chapter ‘Creating R
packages’ of the ‘Writing R Extensions’ manual.
...
* checking for missing documentation entries ... ERROR
Error: package or namespace load failed for ‘ABC’
Call sequence:
2: stop(gettextf("package or namespace load failed for %s", sQuote(package)),
call. = FALSE, domain = NA)
1: library(package, lib.loc = lib.loc, character.only = TRUE, verbose = FALSE)
Execution halted
Exited with status 1.
The updateOptions() method it's complaining about is part of the logging::basicConfig() function I call in my initialization:
> logging::basicConfig
function (level = 20)
{
rootLogger <- getLogger()
updateOptions(rootLogger, level = namedLevel(level))
rootLogger$addHandler("basic.stdout", writeToConsole, level = namedLevel(level))
invisible()
}
<environment: namespace:logging>
d> logging::updateOptions
function (container, ...)
UseMethod("updateOptions")
<environment: namespace:logging>
Thanks for any insight anyone can provide.

Resources