How to use a platform specific package in my R function - r

my R package has a function (my_func) that uses function(bar) from another package (foo) which only available on Unix. So I write my code this way, following the suggested packages in Writing R extension:
my_func = function(){
....
if (requireNamespace("foo", quietly = TRUE)) {
foo::bar(..) # also tried bar(...)
} else {
# do something else without `bar`
}
...
}
However, I keep getting such warning message when I run R CMD check:
'loadNamespace' or 'requireNamespace' call not declared from: foo
Is there any way to use platform specific packages without gives such warnings? I tried to include foo in the Description file and the warning disappeared, but then the package cannot be installed on windows because foo is not available for the win.

I think you misread that comment, though it is easy to do because the logic is not clear and incontrovertible.
In that first paragraph that talked about calling packages using require(package) they said it was OK for a test environment or vignette but not from inside a finished function to use library(package) or require(package).
This is considered bad form, because the packages you call inside a function will usurp the order of access your user has set up in her work environment when loading packages.
The method you use above:
package::function()
is the approved of way to use a function within a function without altering the current environment.
But in order to use that function you must still have that package installed on your current machine or in your current working environment (such as a virtualenv or ipython or jupytr..and yes R will work in all those environments).
You cannot run a function that R cannot see from the working environment...so you must have it installed, but not necessarily loaded, to call it.

Related

Creating R package using code from script file

I’ve written some R functions and dropped them into a script file using RStudio. These are bits of code that I use over and over, so I’m wondering how I might most easily create an R package out of them (for my own private use).
I’ve read various “how to” guides online but they’re quite complicated. Can anyone suggest an “idiot’s guide” to doing this please?
I've been involved in creating R packages recently, so I can help you with that. Before proceeding to the steps to be followed, there are some pre-requisites, which include:
RStudio
devtools package (for most of the functions involved in creation of a package)
roxygen2 package (for roxygen documentation)
In case you don't have the aforementioned packages, you can install them with these commands respectively:
install.packages("devtools")
install.packages("roxygen2")
Steps:
(1) Import devtools in RStudio by using library(devtools).
(devtools is a core package that makes creating R packages easier with its tools)
(2) Create your package by using:
create_package("~/directory/package_name") for a custom directory.
or
create_package("package_name") if you want your package to be created in current workspace directory.
(3) Soon after you execute this function, it will open a new RStudio session. You will observe that in the old session some lines will be auto-generated which basically tells R to create a new package with required components in the specified directory.
After this, we are done with this old instance of RStudio. We will continue our work on the new RStudio session window.
By far the package creation part is already over (yes, that simple) however, a package isn't directly functionable just by its creation plus the fact that you need to include a function in it requires some additional aspects of a package such as its documentation (where the function's title, parameters, return types, examples etc as mentioned using #param, #return etc - you would be familiar if you see roxygen documentation like in some github repositories) and R CMD checks to get it working.
I'll get to that in the subsequent steps, but just in case you want to verify that your package is created, you can look at:
The top right corner of the new RStudio session, where you can see the package name that you created.
The console, where you will see that R created a new directory/folder in the path that we specified in create_package() function.
The files panel of RStudio session, where you'll notice a bunch of new files and directories within your directory.
(4) As you mentioned in your words, you drop your functions in a script file - hence you will need to create the script first, which can be done using:
use_r("function_name")
A new R script will pop up in your working session, ready to be used.
Now go ahead and write your function(s) in it.
(5) After your done, you need to load the function(s) you have written for your package. This is accomplished by using the devtools::load_all() function.
When you execute load_all() in the console, you'll get to know that the functions have been loaded into your package when you'll see Loading package_name displayed in console.
You can try calling your functions after that in the console to verify that they work as a part of the package.
(6) Now that your function has been written and loaded into your package, it is time to move onto checks. It is a good practice to check the whole package as we make changes to our package. The function devtools::check() offers an easy way to do this.
Try executing check() in the console, it will go through a number of procedures checking your package for warnings/errors and give details for the same as messages on the screen (pertaining to what are the errors/warnings/notes). The R CMD check results at the end will contain the vital logs for you to see what are the errors and warnings you got along with their frequency.
If the functions in your package are written well, (with additional package dependencies taken care of) it will give you two warnings upon execution of check:
The first warning will be regarding the license that your package uses, which is not specified for a new pacakge.
The second should be the one for documentation, warning us that our code is not documented.
To resolve the first issue which is the license, use the use_mit_license("license_holder_name") command (or any other license which suits your package - but then for private use as you mentioned, it doesn't really matter what you specify if only your going to use it or not its to be distributed) with your name as in place of license_holder_name or anything which suits a license name.
This will add the license field in the .DESCRIPTION file (in your files panel) plus create additional files adding the license information.
Also you'll need to edit the .DESCRIPTION file, which have self-explanatory fields to fill-in or edit. Here is an example of how you can have it:
Package: Your_package_name
Title: Give a brief title
Version: 1.0.0.0
Authors#R:
person(given = "Your_first_name",
family = "Your_surname/family_name",
role = c("package_creator", "author"),
email = "youremailaddress#gmail.com",
comment = c(ORCID = "YOUR-ORCID-ID"))
Description: Give a brief description considering your package functionality.
License: will be updated with whatever license you provide, the above step will take care of this line.
Encoding: UTF-8
LazyData: true
To resolve the documentation warning, you'll need to document your function using roxygen documentation. An example:
#' #param a parameter one
#' #param b parameter two
#' #return sum of a and b
#' #export
#'
#' #examples
#' yourfunction(1,2)
yourfunction <- function(a,b)
{
sum <- a+b
return(sum)
}
Follow the roxygen syntax and add attributes as you desire, some may be optional such as #title for specifying title, while others such as #import are required (must) if your importing from other packages other than base R.
After your done documenting your function(s) using the Roxygen skeleton, we can tell our package that we have documented our functions by running devtools::document(). After you execute the document() command, perform check() again to see if you get any warnings. If you don't, then that means you're good to go. (you won't if you follow the steps)
Lastly, you'll need to install the package, for it to be accessible by R. Simply use the install() command (yes the same one you used at the beginning, except you don't need to specify the package here like install("package") since you are currently working in an instance where the package is loaded and is ready to be deployed/installed) and you'll see after a few lines of installation a statement like "Done (package_name)", which indicates the installation of our package is complete.
Now you can try your function by first importing your package using library("package_name") and then calling your desired function from the package. Thats it, congrats you did it!
I've tried to include the procedure in a lucid way (the way I create my R packages), but if you have any doubts feel free to ask.

"could not find function" error though function is in the package

In R, I'm getting an error "could not find function...". The function is present inside the package. Still when I run the package, getting the error.
I am getting this error in the ChainLadder package while running MackChainLadderFunctions.R. For example, the function checktriangle is present inside the package in Chainladder.R. Still, R is not able to recognize the function or call the function.
Two problems here.
function names are case-sensitive (checkTriangle, not checktriangle)
checkTriangle is not exported from the package (i.e., it's a private function intended for use within the package only), so you need ::: to access it ... try ChainLadder:::checkTriangle.
Using private functions is "at your own risk/programmer beware"; private functions are undocumented, may change in future versions, etc.. If you can find a way to do what you need to do with public functions, that is generally preferred.
AFAICT you're running into this problem because you're trying to source() (or cut-and-paste) package code in your R session. This shouldn't happen if you load the package with library("ChainLadder") and use the public functions (if it does, please edit your question to give a little more context about how you're using the package ...)

Using 'require' package code to obtain datapackages on the fly in R

I am writing an R package that uses a variety of bioconductor annotation data packages. The specific data packages vary with the use-case. As such, I have a function which does something like this:
if (!require(biocpack_name, character.only=T)) {
source("https://bioconductor.org/biocLite.R")
BiocInstaller::biocLite(biocpack_name)
require(biocpack_name , character.only=T)
}
biocpack_name can be several of ~30+ annotation data packages that are looked up based on the particular data being analysed. As such, I don't want to have to add each to 'Suggests' (Im not even sure that would work because the error is not for a package but rather a string specifying the package). R CMD CHK gives me this error:
'library' or 'require' call not declared from: ‘biocpack_name’
'library' or 'require' call to ‘biocpack_name’ in package code.
How do I get around this?
It's not an error, but a warning. It goes away if you use character.only = TRUE rather than T (I guess because the value of TRUE is known and cannot be re-assigned, but T is unknown and can be anything, including FALSE). But in addition follow the advice in the warning to use requireNamespace() (and not pollute the user search path); maybe db = get(biocpack_name, getNamespace(biocpack_name)) will allow you to use the annotation package the way you'd like, e.g., mapIds(db, ...).
If one were pedantic, adding the packages to the Enhances: field of the DESCRIPTION file would communicate that your package somehow works with the annotation packages, but does not result in installation of the package (e.g., for building the vignette) unless explicitly requested.

How do I ask R to run a specific function from a user defined package to run everytime I load that package?

I've created a package mypack with only one r script in the R directory of the project, hello.R which basically prints our Hello World when loaded and run. Now i need to add some lines of code to a script (ex- hide.R) so that the contents of the function hello.R is not easily visible to a not so experience user. I need this hide.R to run first each time the package mypack is loaded. Can somebody give me a full working example for this?
Note: outside a package, if I have a function foo, then the following
makes it a little difficult for a normal user to get the function
definition easily
srcfile <- srcfilecopy("", "Don't cheat")
srcref <- srcref(srcfile, c(1,1,1,12))
attr(foo, "srcref") <- srcref
Ultimately, once a user loads my package, he/she should not be easily able to get the contents of my function inside the package by typing out the function name. This is for educational purposes.
You can define a function called .onLoad inside your package. See docs here:
https://stat.ethz.ch/R-manual/R-devel/library/base/html/ns-hooks.html

Adding line to .First() during package installation

I'm developing R packages for my company of not so tech savy employees.
To facilitate the life of the users I'm thinking of having a set of scripts at a global location that can get sourced at startup in order to update and load relevant packages.
My idea is to have a script for each custom package that only gets sourced if that particalar package is installed. For this to work I need to modify the .First() function when the user installs the different packages, such that after packages A is installed:
.First() <- function(){
source('script_to_package_A')
}
and if package B is then installed:
.First() <- function(){
source('script_to_package_A')
source('script_to_package_B')
}
Thus i am interested to add a line inside the .Rprofile file if .First() is already defined and the line is not in there already or, if no .Rprofile exists, create it.
What would be the best way to achieve this?
best wishes
Thomas
EDIT: Just to clarify - what I am looking for is a safe way to modify the .First() function that gets called during startup. That means that if a user already has defined a .First() function the additions will just be appended instead of replacing the old .First(). Preferably this addition to first will happen when a specific package is installed but this is not necessary. I'm fairly confident in what to add to the .First() function so this is not in question.
I suspect that the easiest way to get what you want is to have a single package installed on all machines. If you can alter the .First function on everyones machine, then you can install a package.
Your .First function would be:
.First() <- function(){
library(mypkg)
run_mypkg_fun()
##Could also check for package updates
##update.packages("mypkg"...)
}
The function run_mypkg_fun can do all the checks you want, including:
installing packages
running different functions conditional on what's installed.

Resources