diff --git a/DESCRIPTION b/DESCRIPTION index da5f301..df46657 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: attachment Title: Deal with Dependencies -Version: 0.4.2 +Version: 0.4.2.9000 Authors@R: c( person("Sébastien", "Rochette", , "sebastien@thinkr.fr", role = c("cre", "aut"), comment = c(ORCID = "0000-0002-1565-9313")), @@ -31,7 +31,7 @@ Config/Needs/website: ThinkR-open/thinkrtemplate Config/testthat/edition: 3 Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.0 +RoxygenNote: 7.3.1 Language: en-US Depends: R (>= 3.4) diff --git a/NAMESPACE b/NAMESPACE index 93eb18b..e5a41fe 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,6 +3,7 @@ export("%>%") export(att_amend_desc) export(att_from_description) +export(att_from_examples) export(att_from_namespace) export(att_from_qmd) export(att_from_qmds) diff --git a/NEWS.md b/NEWS.md index d399da2..ec33ddd 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,14 @@ +# attachment (development version) + +## New features + +- Add `att_from_examples()` to get all packages called in examples from R files +- `att_amend_desc` amend package DESCRIPTION file (Suggests) with the list of dependencies extracted from examples in R files. + +## Patch + +- Adding an example using a suggest package to the dummypackage + # attachment 0.4.2 ## New features @@ -182,7 +193,7 @@ Minor * New function `install_from_description` to install all missing packages listed in the description file * Add an hex by @statnmap ! * Allow for absence of vignette folder in `att_to_description` -* Add `create_dependencies_file` to create a file listing all packages dependencies to install before your package +* Add `create_dependencies_file` to create a file listing all packages dependencies to dinstall before your package * Allow for `pkg::fun` calls in R scripts with `att_from_functions` * Add option to run `devtools::document()` before `att_from_description` diff --git a/R/add_from_examples.R b/R/add_from_examples.R new file mode 100644 index 0000000..32e9b74 --- /dev/null +++ b/R/add_from_examples.R @@ -0,0 +1,34 @@ +#' Get all packages called in examples from R files +#' +#' @param dir.r path to directory with R scripts. +#' +#' @return Character vector of packages called with library or require. +#' +#' @examples +#' dummypackage <- system.file("dummypackage",package = "attachment") +#' +#' # browseURL(dummypackage) +#' att_from_examples(dir.r = file.path(dummypackage,"R")) + +#' @export +att_from_examples <- function(dir.r = "R") { + rfiles <- list.files(dir.r, full.names = TRUE) + + roxy_file <- tempfile("roxy.examples", fileext = ".R") + + all_examples <- unlist(lapply(rfiles, function(the_file) { + file_roxytags <- roxygen2::parse_file(the_file) + res <- unlist( + lapply(file_roxytags, + function(x) roxygen2::block_get_tag_value(block = x, tag = "examples")) + ) + res + })) + # Clean \dontrun and \donttest, and replace with '{' on next line + all_examples_clean <- + gsub(pattern = "\\\\dontrun\\s*\\{|\\\\donttest\\s*\\{", replacement = "#ICI\n{", x = all_examples) + cat(all_examples_clean, file = roxy_file, sep = "\n") + all_deps_examples <- attachment::att_from_rscript(roxy_file) + file.remove(roxy_file) + return(all_deps_examples) +} diff --git a/R/att_to_description.R b/R/att_to_description.R index 1bc5131..3c3804d 100644 --- a/R/att_to_description.R +++ b/R/att_to_description.R @@ -1,7 +1,7 @@ #' Amend DESCRIPTION with dependencies read from package code parsing #' #' Amend package DESCRIPTION file with the list of dependencies extracted from -#' R, tests, vignettes files. +#' R, examples, tests, vignettes files. #' att_to_desc_from_pkg() is an alias of att_amend_desc(), #' for the correspondence with [att_to_desc_from_is()]. #' @@ -19,6 +19,7 @@ #' @inheritParams att_from_namespace #' @inheritParams att_to_desc_from_is #' @inheritParams att_from_rmds +#' @inheritParams att_from_examples #' #' @importFrom desc description #' @@ -88,6 +89,8 @@ att_amend_desc <- function(path = ".", on.exit(setwd(old)) } + + path <- normalizePath(path) # decide whether to use or update config file ---- @@ -196,6 +199,13 @@ att_amend_desc <- function(path = ".", # Suggests ---- suggests <- NULL + + # Get suggests in examples and remove if already in imports + if (dir.r != "") { + ex <- att_from_examples(dir.r = dir.r) + suggests <- c(suggests, ex[!ex %in% imports]) + } + # Get suggests in vignettes and remove if already in imports if (!grepl("^$|^\\s+$$", dir.v)) { vg <- att_from_rmds(dir.v, inside_rmd = inside_rmd) diff --git a/inst/dummypackage/R/my_mean.R b/inst/dummypackage/R/my_mean.R index 1f2d3ae..df18239 100644 --- a/inst/dummypackage/R/my_mean.R +++ b/inst/dummypackage/R/my_mean.R @@ -4,6 +4,9 @@ #' #' @export #' @importFrom magrittr %>% +#' @examples +#' # example code +#' library(utils) my_mean <- function(x){ x <- x %>% stats::na.omit() 1+1 diff --git a/man/att_amend_desc.Rd b/man/att_amend_desc.Rd index b39f39f..6ddc9e6 100644 --- a/man/att_amend_desc.Rd +++ b/man/att_amend_desc.Rd @@ -83,7 +83,7 @@ Update DESCRIPTION file. } \description{ Amend package DESCRIPTION file with the list of dependencies extracted from -R, tests, vignettes files. +R, examples, tests, vignettes files. att_to_desc_from_pkg() is an alias of att_amend_desc(), for the correspondence with \code{\link[=att_to_desc_from_is]{att_to_desc_from_is()}}. } diff --git a/man/att_from_examples.Rd b/man/att_from_examples.Rd new file mode 100644 index 0000000..473c463 --- /dev/null +++ b/man/att_from_examples.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/add_from_examples.R +\name{att_from_examples} +\alias{att_from_examples} +\title{Get all packages called in examples from R files} +\usage{ +att_from_examples(dir.r = "R") +} +\arguments{ +\item{dir.r}{path to directory with R scripts.} +} +\value{ +Character vector of packages called with library or require. +} +\description{ +Get all packages called in examples from R files +} +\examples{ +dummypackage <- system.file("dummypackage",package = "attachment") + +# browseURL(dummypackage) +att_from_examples(dir.r = file.path(dummypackage,"R")) +} diff --git a/man/attachment-package.Rd b/man/attachment-package.Rd index f2a2f28..5c11039 100644 --- a/man/attachment-package.Rd +++ b/man/attachment-package.Rd @@ -20,12 +20,12 @@ Useful links: } \author{ -\strong{Maintainer}: Murielle Delmotte \email{murielle@thinkr.fr} (\href{https://orcid.org/0000-0002-1339-2424}{ORCID}) +\strong{Maintainer}: Sébastien Rochette \email{sebastien@thinkr.fr} (\href{https://orcid.org/0000-0002-1565-9313}{ORCID}) Authors: \itemize{ - \item Sébastien Rochette \email{sebastien@thinkr.fr} (\href{https://orcid.org/0000-0002-1565-9313}{ORCID}) \item Vincent Guyader \email{vincent@thinkr.fr} (\href{https://orcid.org/0000-0003-0671-9270}{ORCID}) (previous maintainer) + \item Murielle Delmotte \email{murielle@thinkr.fr} (\href{https://orcid.org/0000-0002-1339-2424}{ORCID}) \item Swann Floc'hlay \email{swann@thinkr.fr} (\href{https://orcid.org/0000-0003-1477-830X}{ORCID}) } diff --git a/tests/testthat/test-amend-description.R b/tests/testthat/test-amend-description.R index 3ce263e..413408b 100644 --- a/tests/testthat/test-amend-description.R +++ b/tests/testthat/test-amend-description.R @@ -40,9 +40,10 @@ test_that("att_amend_desc updates description", { expect_equal(desc_file[w.depends + 6], " glue,") expect_equal(desc_file[w.depends + 7], " knitr,") expect_equal(desc_file[w.depends + 8], " rmarkdown,") - expect_equal(desc_file[w.depends + 9], " testthat") - expect_equal(desc_file[w.depends + 10], "LinkingTo:" ) - expect_equal(desc_file[w.depends + 11], " Rcpp") + expect_equal(desc_file[w.depends + 9], " testthat,") + expect_equal(desc_file[w.depends + 10], " utils") + expect_equal(desc_file[w.depends + 11], "LinkingTo:" ) + expect_equal(desc_file[w.depends + 12], " Rcpp") # base does not appear expect_false(all(grepl("base", desc_file))) # utils is removed @@ -485,12 +486,105 @@ library(ggplot3) expect_equal(desc_file[w.depends + 7], " glue,") expect_equal(desc_file[w.depends + 8], " knitr,") expect_equal(desc_file[w.depends + 9], " rmarkdown,") - expect_equal(desc_file[w.depends + 10], " testthat") - expect_equal(desc_file[w.depends + 11], "LinkingTo:" ) - expect_equal(desc_file[w.depends + 12], " Rcpp") + expect_equal(desc_file[w.depends + 10], " testthat,") + expect_equal(desc_file[w.depends + 11], " utils") + expect_equal(desc_file[w.depends + 12], "LinkingTo:" ) + expect_equal(desc_file[w.depends + 13], " Rcpp") # Clean after unlink(dummypackage, recursive = TRUE) }) + +# Test update desc when packages in examples ---- +test_that("if a package is used in an example, it is added to Suggests packages", { + # Copy package in a temporary directory + tmpdir <- tempfile("dummysuggestexamples") + dir.create(tmpdir) + file.copy(system.file("dummypackage",package = "attachment"), tmpdir, recursive = TRUE) + dummypackage <- file.path(tmpdir, "dummypackage") + + r_file <- file.path(dummypackage, "R", "fun_manual.R") + file.create(r_file) + #> [1] TRUE + writeLines( + text = "#' @importFrom magrittr %>% +#' @examples +#' library(pkgfake) +#' fakepkg::fun() +#' @export +my_length <- function(x) { + x %>% length() +}", + con = r_file + ) + + attachment::att_amend_desc(path = dummypackage, check_if_suggests_is_installed = FALSE) + + + desc_file <- readLines(file.path(dummypackage, "DESCRIPTION")) + + w.depends <- grep("Depends:", desc_file) + expect_length(w.depends, 1) + expect_equal(desc_file[w.depends + 5], "Suggests: ") + expect_equal(desc_file[w.depends + 6], " fakepkg,") + expect_equal(desc_file[w.depends + 7], " glue,") + expect_equal(desc_file[w.depends + 8], " knitr,") + expect_equal(desc_file[w.depends + 9], " pkgfake,") + expect_equal(desc_file[w.depends + 10], " rmarkdown,") + expect_equal(desc_file[w.depends + 11], " testthat,") + expect_equal(desc_file[w.depends + 12], " utils") + # Clean after + unlink(dummypackage, recursive = TRUE) + +}) + + +test_that("if a package is used in an example has already been added to IMPORTS, it is not added to the suggests, it is added to Suggests packages", { + # Copy package in a temporary directory + tmpdir <- tempfile("dummysuggestexamples") + dir.create(tmpdir) + file.copy(system.file("dummypackage",package = "attachment"), tmpdir, recursive = TRUE) + dummypackage <- file.path(tmpdir, "dummypackage") + + r_file <- file.path(dummypackage, "R", "fun_manual.R") + file.create(r_file) + #> [1] TRUE + writeLines( + text = "#' @importFrom magrittr %>% +#' @examples +#' library(magrittr) +#' fakepkg::fun() +#' @export +my_length <- function(x) { + x %>% length() +}", + con = r_file + ) + + attachment::att_amend_desc(path = dummypackage, check_if_suggests_is_installed = FALSE) + + + desc_file <- readLines(file.path(dummypackage, "DESCRIPTION")) + + w.depends <- grep("Depends:", desc_file) + expect_length(w.depends, 1) + expect_equal(desc_file[w.depends + 1], " R (>= 3.5.0)") + expect_equal(desc_file[w.depends + 2], "Imports: ") + expect_equal(desc_file[w.depends + 3], " magrittr,") + expect_equal(desc_file[w.depends + 4], " stats") + expect_equal(desc_file[w.depends + 5], "Suggests: ") + expect_equal(desc_file[w.depends + 6], " fakepkg,") + expect_equal(desc_file[w.depends + 7], " glue,") + expect_equal(desc_file[w.depends + 8], " knitr,") + expect_equal(desc_file[w.depends + 9], " rmarkdown,") + expect_equal(desc_file[w.depends + 10], " testthat,") + expect_equal(desc_file[w.depends + 11], " utils") + expect_equal(desc_file[w.depends + 12], "LinkingTo:" ) + expect_equal(desc_file[w.depends + 13], " Rcpp") + + # Clean after + unlink(dummypackage, recursive = TRUE) + +}) diff --git a/tests/testthat/test-att_from_examples.R b/tests/testthat/test-att_from_examples.R new file mode 100644 index 0000000..4242b27 --- /dev/null +++ b/tests/testthat/test-att_from_examples.R @@ -0,0 +1,24 @@ +test_that("att_from_examples works", { + tmpdir <- tempfile("suggestexamples") + + dir.create(file.path(tmpdir, "R"), recursive = TRUE) + + r_file <- file.path(tmpdir, "R", "fun_manual.R") + file.create(r_file) + + writeLines( + text = "#' @importFrom magrittr %>% +#' @examples +#' library(magrittr) +#' fakepkg::fun() +#' @export +my_length <- function(x) { + x %>% length() +}", + con = r_file + ) + + expect_equal(att_from_examples(dir.r = file.path(tmpdir, "R")), + c("magrittr", "fakepkg")) + +}) diff --git a/vignettes/a-fill-pkg-description.Rmd b/vignettes/a-fill-pkg-description.Rmd index 21b33d5..3bf26a7 100644 --- a/vignettes/a-fill-pkg-description.Rmd +++ b/vignettes/a-fill-pkg-description.Rmd @@ -221,13 +221,14 @@ for (i in to_install) { ## Other possibilities -Of course, you can also use {attachment} out of a package to list all package dependencies of R scripts using `att_from_rscripts()` or Rmd files using `att_from_rmds()`. +Of course, you can also use {attachment} out of a package to list all package dependencies of R scripts using `att_from_rscripts()`, Rmd files using `att_from_rmds()` or examples from R scripts using `att_from_examples()`. ```{r, eval=TRUE} dummypackage <- system.file("dummypackage", package = "attachment") att_from_rscripts(path = file.path(dummypackage, "R")) att_from_rmds(path = file.path(dummypackage, "vignettes"), inside_rmd = TRUE) +att_from_examples(dir.r = file.path(dummypackage, "R")) ``` diff --git a/vignettes/b-bookdown-and-scripts.Rmd b/vignettes/b-bookdown-and-scripts.Rmd index 5d75433..a7e2779 100644 --- a/vignettes/b-bookdown-and-scripts.Rmd +++ b/vignettes/b-bookdown-and-scripts.Rmd @@ -106,6 +106,12 @@ This reads all files in directories of R scripts (default to `R` directory of a att_from_rscripts() ``` +Called in examples from R scripts: + +```{r, eval=FALSE} +att_from_examples() +``` + ## Get all packages called in your Rmd If you have vignette, you may want to list extra libraries, not listed in your "Depends" list. This function applies to any Rmd file, of course.