Lazy package dependency in R - r

I'd like to write a R package. A small part of its functionality would be to save data into xlsx file. But this functionality would require a big and heavy dependency: library(xlsx). So I'd like to make this dependency somehow optional and lazy-loaded.
What is the Best Practice for it?
I guess I could simply library(xlsx) in the code of the function that need it, and handle possible failures of this command.

I believe the most robust way to do this is the add the following line to the NAMESPACE of your package:
importFrom(xlsx, the_function_you_need)
along with
Depends: xlsx
in the DESCRIPTION file. As far as I understand, this will give your package access to the function you want without loading the entire library. There is some discussion of importFrom here: What is the benefit of import in a namespace in R?

Related

Read a package NAMESPACE file

I am looking for a fast R solution to read a package NAMESPACE file. The solution should contain already preprocessed (and aggregated) records and separated imports and exports.
Unfortunately I can’t use getNamespaceExports("dplyr")/getNamespaceImports("dplyr") as they need the package to be loaded to the R session, which is too slow.
I need a solution which simply process a text from the NAMESPACE file. Any solutions using external packages as well as partial solutions would still be welcome.
The raw data we could grabbed with a call like readLines("https://raw.githubusercontent.com/cran/dplyr/master/NAMESPACE"). roxygen2 generated files are formatted properly, but this will be not true for all manually generated files.
EDIT:
Thanks to Konrad R. answer I could develop such functionality in my new CRAN package - pacs. I recommended to check pacs::pac_namespace function. There is even one function which goes one step further, comparing NAMESPACE files between different package versions pacs::pac_comapre_namespace.
The function is included in R as base::parseNamespaceFile. Unfortunately the function does not directly take a path as an argument. Instead it constructs the path from a package name and the library location. However, armed with this knowledge you should be able to call it; e.g.:
parseNamespaceFile('dplyr', .libPaths()[1L])
EDIT
Somebody has to remember that the whole packages imports (like import(rlang)) have to be still invoked with the same function and the exports for them extracted. Two core elements are using parse on NAMESPACE code and then using the recursive extract function parseDirective.

Why library() or require() should not be used in a R package

My goal is to create R package which use other library such as grid and ggplot2.
According to
https://tinyheero.github.io/jekyll/update/2015/07/26/making-your-first-R-package.html, it is said that library() or require() should not be used in a R package.
My questions are:
1)Is there a reason? (because, although I put library("ggplot2") and library("grid") in my R script in my package, it still worked).
2)Do I have to delete library("ggplot2") and library("grid") in my code and put "::" such as ggplot2::geom.segment()?
Is there an efficient way to convert script to the one for package?
You should never use library() or require() in a package, because they affect the user's search list, possibly causing errors for the user.
For example, both the dplyr and stats packages export a function called filter. If a user had only library(stats), then filter would mean stats::filter, but if your package called library(dplyr), the user might suddenly find that filter means dplyr::filter, and things would break.
There are a couple of alternatives for your package. You can import functions from another package by listing it in the Imports: field in the DESCRIPTION file and specifying the imports in the NAMESPACE file. (The roxygen2 package can make these changes for you automatically if you put appropriate comments in your .R source files, e.g.
#' #importFrom jsonlite toJSON unbox
before a function that uses those to import toJSON() and unbox() from the jsonlite package.)
The other way to do it is using the :: notation. Then you can still list a package in the Imports: field of DESCRIPTION, but use code like
jsonlite::toJSON(...)
every time you want to call it. Alternatively, if you don't want a strong dependence on jsonlite, you can put jsonlite in Suggests:, and wrap any uses of it in code like
if (requireNamespace("jsonlite")) {
jsonlite::toJSON(...)
}
Then people who don't have that package will still be able to run your function, but it may skip some operations that require jsonlite.

Alternatives to placing package in "Depends" section

I'm writing a small package that builds some custom types of graphs using ggplot2. Naturally, my source files are going to be littered with ggplot2 functions. I'm somewhat new to package development, and my understanding is that it's generally better to disambiguate namespaces using :: within package sources. But putting ggplot2:: in front of everything seems like a great recipe for cluttering my code - I'd like to make it as readable and clear as possible to make it easier for my colleagues to work on my code as well.
Is there a way to give my source files access to the ggplot2 namespace? Using library within a package seems to be a big no-no. Putting ggplot2 under "Depends" in the package DESCRIPTION almost does it, but only attaches ggplot2 when I attach my package (thus causing problems if my package is loaded but not attached). Finding a way to automatically attach ggplot2 when my package is loaded would solve those problems, though intuition is telling me this is probably a bad practice somehow.
As mentioned here, you can do this in the roxygen comments:
If you are using many functions from another package, use #import package to import them all and make available without using ::.
Preferably you would put this in the R/packagename-package.R file, that has other standard roxygen tags, like so:
#' #docType package
#' #name packagename
#' #import ggplot2
NULL

I'm writing a package. How can make it such that when library(my_package) is called, other packages are loaded as well?

Title should be pretty clear I hope. I'm writing a package called forecasting, with imports for dplyr among other packages. With the imports written in to the DESCRIPTION file, I am able to force these other packages to be installed along with forecasting - is there an equivalent way to do this for the loading of the package? In other words, is there a way that when I load my package with library(forecasting), it automatically also loads dplyr and the other packages?
Thanks
Yes.
Re-read "Writing R Extensions". The Depends: forces both the initial installation as well as the loading of the depended-upon packages.
But these days you want Imports: along with importFrom() in the NAMESPACE file which is more fine-grained.
But first things first: get it working with Depends.
Edit:
Opps you're correct, the documentation I referenced is not a primary source. Perhaps this is better:
From the R documentation:
The ‘Depends’ field gives a comma-separated list of package names which this package depends on. Those packages will be attached before the current package when library or require is called.
and
The ‘Imports’ field lists packages whose namespaces are imported from (as specified in the NAMESPACE file) but which do not need to be attached. Namespaces accessed by the ‘::’ and ‘:::’ operators must be listed here, or in ‘Suggests’ or ‘Enhances’
Original:
From the R packages documentation:
Adding a package dependency here [the DESCRIPTION file] ensures that it’ll be installed. However, it does not mean that it will be attached along with your package (i.e., library(x)). The best practice is to explicitly refer to external functions using the syntax package::function(). This makes it very easy to identify which functions live outside of your package. This is especially useful when you read your code in the future.

R package namespace issue using data() -- data set not found

I've hit an issue trying to import a package (namely, 'robfilter') inside one of my own packages. One of its methods that I am trying to use, adore.filter, is failing at this line:
data(critvals)
With error 'data set 'critvals' not found'.
The function works fine if I load the library via require(robfilter). However, this means that in order to use my custom package which calls adore.filter, I will have to load my own package, and then load robfilter. Not a huge problem but slightly annoying.
I'm not sure if the problem is that there is an extra step I need to do in order to make critvals visible within my package, or if perhaps there is something the package author needed to do (and hasn't done) to add critvals to its package namespace; there is no sign of 'critvals' in the robfilter NAMESPACE file. I haven't encountered this issue before and don't really understand how the use of data() inside a package is supposed to work.
There are two solutions as far as I know:
Either ask the robfilter Maintainer to put the data needed by robfiler in the internal data file of robfilter. (R/sysdata.rda)
Or make your package Depends on robfilter
So it works if you put robfilter in the depends section of your description file. But in my case (both are my packages), I was trying to avoid the Depends solution as it loads the imported package and also any other package will need to depend ont its imported package... See my question is quite a duplicate of yours but not in the same context.

Resources