The purpose of `@examplesIf`
Hello,
The "rd"" vignette claims that the code of the example is not executed during the check when the If condition is FALSE.
However it seems to me that this is not what happens in reality.
This tag includes some \dontshow in the generated Rd code, and according to Writing R Extensions, the \dontshow macro never prevents the execution of the code, it just hides the code to the user, but during R CMD CHECK, this code is executed.
Here is the WRE illustration:
x <- runif(10) # Shown and run.
\dontrun{plot(x)} # Only shown.
\dontshow{log(x)} # Only run.
And I also found the following claim when I googled:
Examples displayed and executed during checks/example runs: as is Examples displayed but NOT executed during checks/example runs: \dontrun{} Examples NOT displayed but executed during checks/example runs: \dontshow{} Examples NOT displayed and NOT executed during checks/example runs: simply don't type them anywhere ;-)
Best, Uwe Ligges
Here to be precise. Note this is an old thread (2005).
Consider this example:
#' Foo
#' @examplesIf FALSE
#' stop("You can't run this.")
#' @name foo
NULL
The generated .Rd is:
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/foo.R
\name{foo}
\alias{foo}
\title{Foo}
\description{
Foo
}
\examples{
\dontshow{if (FALSE) withAutoprint(\{ # examplesIf}
stop("You can't run this.")
\dontshow{\}) # examplesIf}
}
You'll notice that the \dontshow macros are wrapping an if statement enclosing the entire examples section. That if statement is not shown but is present in the code that R CMD check runs, disabling the block from being executed.
@stla would you mind pointing to the documentation you're seeing from {roxygen2}? It looks like there's a misunderstanding about @examplesIf, which might be resolved by improving the documentation.
\dontshow{} is basically just an implementation detail of how @examplesIf operates -- the more core purpose is to skip evaluation in some circumstances.
I work with a package that a very simple function get_bbox_vector returning a vector from a bounding box. This function will fail (obviously) if package sf is not installed - which is why the example requires it. Now, this may be a silly example because sf is a dependency of the package and is almost definitely installed if a user is using this package. However, it illustrates what might be a misunderstanding of the purpose of this.
The function get_bbox_vector has the following as part of documentation.
#' @examplesIf require("sf")
#' nc <- st_read(system.file("shape/nc.shp", package="sf"))
#' get_bbox_vector(nc)
after running document(), it has this in the .Rd file
\examples{
\dontshow{if (require("sf")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf}
nc <- st_read(system.file("shape/nc.shp", package="sf"))
get_bbox_vector(nc)
\dontshow{\}) # examplesIf}
}
If a user is looking at the documentation in their Help window in RStudio, the example looks quite nice - roxygen hides the if statement.
And, if a user has sf installed and runs the example, it works.
However, if a user does not have sf installed, the example still tried to run and fails. You get an error that the system file cannot be found. Which is means that the require does not do anything.
Please provide the full Rd file and/or roxygen2 mark-up for this function (it's not on GitHub), that looks fishy to me.
Sure. It is on github, but private. This function is quite simple. The full R with roxygen2 looks like:
#' Get Bounding Box Vector
#'
#' Extracts the bounding box from an [sf::sf] object and returns it as a vector
#' of the form xmin, ymin, xmax, and ymax.
#'
#' @param sf_object An `sf` object
#' @returns string representing a bounding box of format `c(min_longitude,
#' min_latitude, max_longitude, max_latitude)`
#' @importFrom sf st_transform st_bbox
#' @export
#'
#' @examplesIf require("sf")
#' nc <- st_read(system.file("shape/nc.shp", package="sf"))
#' get_bbox_vector(nc)
get_bbox_vector <- function(sf_object) {
sf_object |>
sf::st_transform(4326) |>
sf::st_bbox() |>
as.vector() |>
paste0(collapse = ",")
}
The full Rd looks like:
% Generated by roxygen2: do not edit by hand
% Please edit documentation in R/geocode.R
\name{get_bbox_vector}
\alias{get_bbox_vector}
\title{Get Bounding Box Vector}
\usage{
get_bbox_vector(sf_object)
}
\arguments{
\item{sf_object}{An \code{sf} object}
}
\value{
vector representing a bounding box of format \code{c(min_longitude, min_latitude, max_longitude, max_latitude)}
}
\description{
Extracts the bounding box from an \link[sf:sf]{sf::sf} object and returns it as a vector
of the form xmin, ymin, xmax, and ymax.
}
\examples{
\dontshow{if (require("sf")) (if (getRversion() >= "3.4") withAutoprint else force)(\{ # examplesIf}
nc <- st_read(system.file("shape/nc.shp", package="sf"))
get_bbox_vector(nc)
\dontshow{\}) # examplesIf}
}
Thanks, nothing unusual there.
However, if a user does not have sf installed, the example still tried to run and fails.
Could you be specific about how the example is run?
example("get_bbox_vector")? Is the user copy-pasting from the help pane in the IDE? Is there a "run" button in the IDE that might be responsible?
yeah.if you see my screenshot earlier from R Studio. The Run Examples is a link .
If you put "Run Examples" and you have sf installed, it works like so:
If you uninstall 'sf' and push "Run Examples", you get:
As a naive observer, I would expect it to warn or to say "can't run example because condition not met or whatever "
thanks! does examples("get_bbox_vector") work as intended without sf? (i.e. no inscrutable error)
huh. I feel like most savvy users would quickly understand that an error where it is looking for a file in a package and failed to be an error of the package not existing. But also - no . The error is "Error: dsn must point to a source, not an empty string. " and that might be inscrutable.
What would you expect to happen if you put #' @examplesIf require('package') ?
In my case, since require() returns a logical, I would expect the example NOT to run. if the require returns FALSE.
Maybe, though, the examplesIf is examined at a different time than at 'Run Examples' time? Maybe it is only to skip the examples for CRAN and not intended to do anything for user documentation?
I think your expectation is incorrect, I don't think there's anything wrong with your mental model as I understand it.
Could you do examples("get_bbox_vector") on a machine lacking {sf} and copy/paste the output?
The behavior in the console is the same as if you click on "Run Examples" in the Help/Documentation in RStudio.
I pasted images above for what you get if you "Run Example" in the Help/Documentation
Here is what it looks like in the console:
With sf installed
> library(ruralfunx)
> example("get_bbox_vector")
gt_bb_> ## Don't show:
gt_bb_> if (require("sf")) (if (getRversion() >= "3.4") withAutoprint else force)({ # examplesIf
gt_bb_+ ## End(Don't show)
gt_bb_+ nc <- st_read(system.file("shape/nc.shp", package="sf"))
gt_bb_+ get_bbox_vector(nc)
gt_bb_+ ## Don't show:
gt_bb_+ }) # examplesIf
Loading required package: sf
Linking to GEOS 3.13.0, GDAL 3.10.1, PROJ 9.5.1; sf_use_s2() is TRUE
> nc <- st_read(system.file("shape/nc.shp", package="sf"))
Reading layer `nc' from data source `C:\Users\user.name\AppData\Local\R\win-library\4.4\sf\shape\nc.shp' using driver `ESRI Shapefile'
Simple feature collection with 100 features and 14 fields
Geometry type: MULTIPOLYGON
Dimension: XY
Bounding box: xmin: -84.32385 ymin: 33.88199 xmax: -75.45698 ymax: 36.58965
Geodetic CRS: NAD27
> get_bbox_vector(nc)
[1] "-84.3237664040026,33.8821229602902,-75.4566198458629,36.589729047258"
gt_bb_> ## End(Don't show)
gt_bb_>
gt_bb_>
gt_bb_>
Warning message:
package ‘sf’ was built under R version 4.4.3
If you remove sf, you get the broken pointer to the file (just like in the screenshot above)
> remove.packages("sf")
Removing package from ‘C:/Users/user.name/AppData/Local/R/win-library/4.4’
(as ‘lib’ is unspecified)
> example("get_bbox_vector")
gt_bb_> ## Don't show:
gt_bb_> if (require("sf")) (if (getRversion() >= "3.4") withAutoprint else force)({ # examplesIf
gt_bb_+ ## End(Don't show)
gt_bb_+ nc <- st_read(system.file("shape/nc.shp", package="sf"))
gt_bb_+ get_bbox_vector(nc)
gt_bb_+ ## Don't show:
gt_bb_+ }) # examplesIf
> nc <- st_read(system.file("shape/nc.shp", package="sf"))
Error: `dsn` must point to a source, not an empty string.
In addition: Warning message:
In read.dcf(file.path(p, "DESCRIPTION"), c("Package", "Version")) :
cannot open compressed file 'C:/Users/user.name/AppData/Local/R/win-library/4.4/sf/DESCRIPTION', probable reason 'No such file or directory'
Thanks. Something seems broken about your installation. AFAICT this:
read.dcf(file.path(p, "DESCRIPTION"), c("Package", "Version"))
Is coming from find.package() itself:
https://github.com/r-devel/r-svn/blob/15598ed5a91070b38046b6093ab92da851b063ee/src/library/base/R/library.R#L818-L819
Can you try setting options(warn=2) before running example()? That should make it clearer when the warning is thrown, I suspect it's coming from require() itself. But then it's possibly still going on to find {sf} installed somewhere else 🤔
(PS, you mentioned "sf is a dependency", so this whole exercise does seem a bit odd, your package should assume it's available; anyway, it looks like you're treating it like a Suggests dependency, in which case, WRE explicitly states you should prefer use requireNamespace(), not require(), in examples, you might try @examplesIf requireNamespace("sf", quietly=TRUE) instead and then sf::st_read)
Yes. I agree that this example that I am giving is a bit of a silly one. I was just trying to expand on the 'what is the purpose of @examplesIf' -- and this was a function that I knew had an examplesIf.
@jc-usda you'll notice if you remove sf and then restart your R session the example won't be executed if you try to run it again.
That's because in the session where you had previously loaded sf and then uninstalled it, you'll still have require("sf") return TRUE because the namespace remains loaded until you restart. Once you restart, require("sf") will return FALSE and the example won't run, as expected.
So it sounds to me the problem you're seeing is in fact with how require() interacts with already-loaded packages being removed, rather than @examplesIf.