Skip to content

Latest commit

 

History

History
112 lines (63 loc) · 5.18 KB

README.md

File metadata and controls

112 lines (63 loc) · 5.18 KB

autoimport

Package-License Lifecycle: stable CRAN status Last Commit R-CMD-check

autoimport is a package designed to easily add @importFrom roxygen tags to all your functions.

Concept

When importing functions to use them in a package, you have the choice between @import pkg to import a whole package and @importFrom pkg fun1 fun2 to import only a few functions.

The @importFrom syntax is preferable, as it has been stressed out that importing whole packages "makes your code harder to read (you can't tell where a function is coming from), and if you @import many packages, it increases the chances of function name conflicts."

The R Packages (2e) guidelines say that here are two reasonable locations for @importFrom :

  • As close as possible to the usage of the external function. With this mindset, you would place @importFrom in the roxygen comment above the function in your package where you use the external function.

  • In a central location. This approach keeps all @importFrom tags together, in a dedicated section of the package-level documentation file (which can be created with usethis::use_package_doc()).

I find the first option much clearer, but, as they warn, it tends to get very tedious to keep track of all the function calls.

Therefore, autoimport will parse your code, detect all the functions you import, and then add the right @importFrom tags in the right place. Just like that!

Installation

For now, only the development version is available:

# Install development version on Github
pak::pak("DanChaltiel/autoimport")

Getting started

Simply load the package and run the function!

devtools::load_all(".")
autoimport::autoimport()

The first run will take some time, but a cache system is implemented so that next runs are faster.

Then, you can see the diff and accept the changes using the shiny widget:

autoimport::import_review()

Important notes

  • autoimport will guess the potential source of your functions based on (1) the packages currently loaded in your environment (e.g. via library()), and (2) the packages listed as dependencies in DESCRIPTION.

  • load_all(".") is required for autoimport to have access to the package's private functions, for example so that dplyr::filter() cannot mask yourpackage:::filter().

  • Some package guesses are bound to be wrong, in which case you should use usethis::use_import_from(). See "Limitations" below for more details.

Limitations

Autoimport is based on utils::getSrcref() and share the same limits. Therefore, some function syntaxes are not recognized and autoimport will try to remove their @importFrom from individual functions:

  • Operators (@importFrom dplyr %>%, @importFrom rlang :=, ...)
  • Functions called by name (e.g. sapply(x, my_fun))
  • Functions used inside strings (e.g. glue("my_fun={my_fun(x)}"))

To keep them imported, you should either use a prefix (pkg::my_fun) or import them in your package-level documentation, as this file is ignored by default (due to ignore_package=TRUE).

For that, usethis::use_import_from() and usethis::use_pipe() are your friends!

Also, note that R6 methods calls trigger a "not found" warning (WIP, see #21).

Cache system

As running autoimport() on a large package can take some time, a cache system is implemented, by default in file inst/autoimport_cache.rds.

Any function not modified since last run should be taken from the cache, resulting on a much faster run.

In some seldom cases, this can cause issues with modifications in DESCRIPTION or IMPORTLIST not being taken into account. Run clean_cache() to remove this file, or use use_cache="write".

Algorithm

When trying to figure out which package to import a function from, autoimport() follows this algorithm:

  • If the function is prefixed with the package, ignore
  • Else, if the function is already mentioned in NAMESPACE, use the package
  • Else, if the function is exported by only one package, use this package
  • Else, ask the user from which package to import the function
  • Else, warn that the function was not found

Note that this algorithm is still a bit experimental and that I could only test it on my few own packages. Any feedback is more than welcome!

Style

As I couldn't find any standardized guideline about the right order of roxygen2 tags, autoimport puts them:

  • in place of the first @importFrom tag if there is one
  • just before the function call otherwise