From 6b2d6c197b163e9949dfce98737eb3bae4bc9588 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Sun, 15 Mar 2020 13:41:15 -0500 Subject: [PATCH 1/6] Tweak roxygen2 workflow * New explicit roxygen argument to create_package(), use_description(), and use_namespace() * Defaults have been tweaked so that devtools::check() will run document() the first time you call it, and functions will only be exported after you've explicitly exported them Fixes #927. Fixes #963 --- NEWS.md | 6 ++++++ R/create.R | 8 +++++--- R/description.R | 6 +++++- R/namespace.R | 18 +++++++++++++----- man/create_package.Rd | 3 +++ man/use_description.Rd | 4 +++- man/use_namespace.Rd | 11 ++++++++--- tests/testthat/test-use-roxygen.R | 16 ---------------- tests/testthat/test-use-tidy.R | 1 - 9 files changed, 43 insertions(+), 30 deletions(-) diff --git a/NEWS.md b/NEWS.md index 9755d900a..4f4dfe37e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,11 @@ # usethis (development version) +* `create_package()` gains a `roxygen` argument. If `TRUE` (the default), + adds a `RoxygenNote` field to the `DESCRIPTION` (which means the first run + of `devtools::check()` will re-document the package, #963), and creates an + empty `NAMESPACE` (which means you'll need always need explicit `@export` + if you want to export functions, #927). + * In `use_travis()`, `use_travis_badge()` and `browse_travis()`, argument `ext` now defaults to `"com"` instead of `"ext"`, given travis-ci.com is now recommended over travis-ci.org (#1038, @riccardoporreca). diff --git a/R/create.R b/R/create.R index e43ce3174..86d1ca4c2 100644 --- a/R/create.R +++ b/R/create.R @@ -9,9 +9,10 @@ #' Both functions can be called on an existing project; you will be asked #' before any existing files are changed. #' +#' @inheritParams use_description #' @param path A path. If it exists, it is used. If it does not exist, it is #' created, provided that the parent path exists. -#' @inheritParams use_description +#' @param roxygen Are you planning on using roxygen to document your package? #' @param rstudio If `TRUE`, calls [use_rstudio()] to make the new package or #' project into an [RStudio #' Project](https://support.rstudio.com/hc/en-us/articles/200526207-Using-Projects). @@ -30,6 +31,7 @@ create_package <- function(path, fields = NULL, rstudio = rstudioapi::isAvailable(), + roxygen = TRUE, check_name = TRUE, open = interactive()) { path <- user_path_prep(path) @@ -46,8 +48,8 @@ create_package <- function(path, on.exit(proj_set(old_project), add = TRUE) use_directory("R") - use_description(fields, check_name = check_name) - use_namespace() + use_description(fields, check_name = check_name, roxygen = roxygen) + use_namespace(roxygen = roxygen) if (rstudio) { use_rstudio() diff --git a/R/description.R b/R/description.R index 5c043d851..5e860e8b7 100644 --- a/R/description.R +++ b/R/description.R @@ -40,6 +40,7 @@ #' personalized defaults using package options #' @param check_name Whether to check if the name is valid for CRAN and throw an #' error if not +#' @param roxygen If `TRUE`, sets `RoxygenNote` to current roxygen2 version. #' @seealso The [description chapter](https://r-pkgs.org/description.html#dependencies) #' of [R Packages](https://r-pkgs.org). #' @export @@ -51,7 +52,7 @@ #' #' use_description_defaults() #' } -use_description <- function(fields = NULL, check_name = TRUE) { +use_description <- function(fields = NULL, check_name = TRUE, roxygen = TRUE) { name <- project_name() if (check_name) { check_package_name(name) @@ -59,6 +60,9 @@ use_description <- function(fields = NULL, check_name = TRUE) { fields <- fields %||% list() check_is_named_list(fields) fields[["Package"]] <- name + if (roxygen) { + fields[["RoxygenNote"]] <- utils::packageVersion("roxygen2") + } desc <- build_description(fields) desc <- desc::description$new(text = desc) diff --git a/R/namespace.R b/R/namespace.R index 8040525aa..b4a603296 100644 --- a/R/namespace.R +++ b/R/namespace.R @@ -1,13 +1,21 @@ #' Use a basic `NAMESPACE` #' -#' This `NAMESPACE` exports everything, except functions that start -#' with a `.`. +#' If `roxygen` is `TRUE` generates a empty `NAMESPACE` that exports nothing; +#' you'll need to explicitly export functions with `@export`. If `roxygen` +#' is `FALSE`, generates a default `NAMESPACE` that exports all functions +#' except those that start with `.`. #' +#' @param roxygen Are you planning to use roxygen2? #' @seealso The [namespace chapter](https://r-pkgs.org/namespace.html) of #' [R Packages](https://r-pkgs.org). -#' #' @export -use_namespace <- function() { +use_namespace <- function(roxygen = TRUE) { check_is_package("use_namespace()") - use_template("NAMESPACE") + + path <- proj_path("NAMESPACE") + if (roxygen) { + write_over(path, c("# Generated by roxygen2: do not edit by hand", "")) + } else { + write_over(path, 'exportPattern("^[^\\.]")') + } } diff --git a/man/create_package.Rd b/man/create_package.Rd index dfbdbdc54..1d1da3065 100644 --- a/man/create_package.Rd +++ b/man/create_package.Rd @@ -9,6 +9,7 @@ create_package( path, fields = NULL, rstudio = rstudioapi::isAvailable(), + roxygen = TRUE, check_name = TRUE, open = interactive() ) @@ -30,6 +31,8 @@ that the directory can be recognized as a project by the \href{https://here.r-lib.org}{here} or \href{https://rprojroot.r-lib.org}{rprojroot} packages.} +\item{roxygen}{Are you planning on using roxygen to document your package?} + \item{check_name}{Whether to check if the name is valid for CRAN and throw an error if not} diff --git a/man/use_description.Rd b/man/use_description.Rd index bcfc88a57..ba9a362c8 100644 --- a/man/use_description.Rd +++ b/man/use_description.Rd @@ -5,7 +5,7 @@ \alias{use_description_defaults} \title{Create or modify a DESCRIPTION file} \usage{ -use_description(fields = NULL, check_name = TRUE) +use_description(fields = NULL, check_name = TRUE, roxygen = TRUE) use_description_defaults() } @@ -16,6 +16,8 @@ personalized defaults using package options} \item{check_name}{Whether to check if the name is valid for CRAN and throw an error if not} + +\item{roxygen}{If \code{TRUE}, sets \code{RoxygenNote} to current roxygen2 version.} } \description{ \code{use_description()} creates a \code{DESCRIPTION} file. Although mostly associated diff --git a/man/use_namespace.Rd b/man/use_namespace.Rd index 71264cc15..7e37d4194 100644 --- a/man/use_namespace.Rd +++ b/man/use_namespace.Rd @@ -4,11 +4,16 @@ \alias{use_namespace} \title{Use a basic \code{NAMESPACE}} \usage{ -use_namespace() +use_namespace(roxygen = TRUE) +} +\arguments{ +\item{roxygen}{Are you planning to use roxygen2?} } \description{ -This \code{NAMESPACE} exports everything, except functions that start -with a \code{.}. +If \code{roxygen} is \code{TRUE} generates a empty \code{NAMESPACE} that exports nothing; +you'll need to explicitly export functions with \verb{@export}. If \code{roxygen} +is \code{FALSE}, generates a default \code{NAMESPACE} that exports all functions +except those that start with \code{.}. } \seealso{ The \href{https://r-pkgs.org/namespace.html}{namespace chapter} of diff --git a/tests/testthat/test-use-roxygen.R b/tests/testthat/test-use-roxygen.R index d688022e7..bbec40fef 100644 --- a/tests/testthat/test-use-roxygen.R +++ b/tests/testthat/test-use-roxygen.R @@ -11,19 +11,3 @@ test_that("use_roxygen_md() adds DESCRIPTION fields to naive package", { expect_true(desc::desc_has_fields("RoxygenNote", pkg)) expect_true(uses_roxygen_md()) }) - -test_that("use_roxygen_md() does not error on a roxygen-using package", { - skip_if_not_installed("roxygen2") - with_mock( - ## need to pass the check re: whether roxygen2md is installed - `usethis:::check_installed` = function(pkg) TRUE, { - scoped_temporary_package() - cat( - "RoxygenNote: 6.0.1\n", - file = proj_path("DESCRIPTION"), - append = TRUE - ) - expect_error_free(use_roxygen_md()) - } - ) -}) diff --git a/tests/testthat/test-use-tidy.R b/tests/testthat/test-use-tidy.R index 728775633..0711cb017 100644 --- a/tests/testthat/test-use-tidy.R +++ b/tests/testthat/test-use-tidy.R @@ -17,7 +17,6 @@ test_that("use_tidy_eval() inserts the template file and Imports rlang", { pkg <- scoped_temporary_package() ## fake the use of roxygen; this better in a test than use_roxygen_md() - use_description_field(name = "RoxygenNote", value = "6.0.1.9000") use_tidy_eval() expect_match(dir_ls(proj_path("R")), "utils-tidy-eval.R") expect_match(desc::desc_get("Imports", pkg), "rlang") From e2e016612aabea92ce68112ca1ca9116c19145e1 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Wed, 18 Mar 2020 12:04:30 -0500 Subject: [PATCH 2/6] Delete namespace template --- inst/templates/NAMESPACE | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 inst/templates/NAMESPACE diff --git a/inst/templates/NAMESPACE b/inst/templates/NAMESPACE deleted file mode 100644 index 884a6312a..000000000 --- a/inst/templates/NAMESPACE +++ /dev/null @@ -1,2 +0,0 @@ -# Generated by roxygen2: fake comment so roxygen2 overwrites silently. -exportPattern("^[^\\.]") From 09f8bf7e42f4797d3ebda4e77d805ec161cf91cb Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Wed, 18 Mar 2020 12:07:04 -0500 Subject: [PATCH 3/6] Apply suggestions from code review Co-Authored-By: Jennifer (Jenny) Bryan --- NEWS.md | 2 +- R/create.R | 2 +- R/namespace.R | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/NEWS.md b/NEWS.md index 4f4dfe37e..248be5768 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,7 +3,7 @@ * `create_package()` gains a `roxygen` argument. If `TRUE` (the default), adds a `RoxygenNote` field to the `DESCRIPTION` (which means the first run of `devtools::check()` will re-document the package, #963), and creates an - empty `NAMESPACE` (which means you'll need always need explicit `@export` + empty `NAMESPACE` (which means you'll always need an explicit `@export` if you want to export functions, #927). * In `use_travis()`, `use_travis_badge()` and `browse_travis()`, argument `ext` diff --git a/R/create.R b/R/create.R index 86d1ca4c2..9b39827ad 100644 --- a/R/create.R +++ b/R/create.R @@ -12,7 +12,7 @@ #' @inheritParams use_description #' @param path A path. If it exists, it is used. If it does not exist, it is #' created, provided that the parent path exists. -#' @param roxygen Are you planning on using roxygen to document your package? +#' @param roxygen Do you plan to use roxygen2 to document your package? #' @param rstudio If `TRUE`, calls [use_rstudio()] to make the new package or #' project into an [RStudio #' Project](https://support.rstudio.com/hc/en-us/articles/200526207-Using-Projects). diff --git a/R/namespace.R b/R/namespace.R index b4a603296..790d3c723 100644 --- a/R/namespace.R +++ b/R/namespace.R @@ -1,11 +1,11 @@ #' Use a basic `NAMESPACE` #' -#' If `roxygen` is `TRUE` generates a empty `NAMESPACE` that exports nothing; +#' If `roxygen` is `TRUE` generates an empty `NAMESPACE` that exports nothing; #' you'll need to explicitly export functions with `@export`. If `roxygen` #' is `FALSE`, generates a default `NAMESPACE` that exports all functions #' except those that start with `.`. #' -#' @param roxygen Are you planning to use roxygen2? +#' @param roxygen Do you plan to manage `NAMESPACE` with roxygen2? #' @seealso The [namespace chapter](https://r-pkgs.org/namespace.html) of #' [R Packages](https://r-pkgs.org). #' @export From e39319bca7b66171b0d8e758490845c6dd0de5ab Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Wed, 18 Mar 2020 12:08:26 -0500 Subject: [PATCH 4/6] Re-document --- man/create_package.Rd | 2 +- man/proj_utils.Rd | 3 ++- man/use_namespace.Rd | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/man/create_package.Rd b/man/create_package.Rd index 1d1da3065..69a23e9c9 100644 --- a/man/create_package.Rd +++ b/man/create_package.Rd @@ -31,7 +31,7 @@ that the directory can be recognized as a project by the \href{https://here.r-lib.org}{here} or \href{https://rprojroot.r-lib.org}{rprojroot} packages.} -\item{roxygen}{Are you planning on using roxygen to document your package?} +\item{roxygen}{Do you plan to use roxygen2 to document your package?} \item{check_name}{Whether to check if the name is valid for CRAN and throw an error if not} diff --git a/man/proj_utils.Rd b/man/proj_utils.Rd index 4f897a8fe..12afcb77b 100644 --- a/man/proj_utils.Rd +++ b/man/proj_utils.Rd @@ -39,7 +39,8 @@ project-signalling infrastructure, such as initialising a Git repo or adding a \code{DESCRIPTION} file.} \item{...}{character vectors, if any values are NA, the result will also be -NA.} +NA. The paths follow the recycling rules used in the tibble package, +namely that only length 1 arguments are recycled.} \item{ext}{An optional extension to append to the generated path.} diff --git a/man/use_namespace.Rd b/man/use_namespace.Rd index 7e37d4194..b3a8a746b 100644 --- a/man/use_namespace.Rd +++ b/man/use_namespace.Rd @@ -7,10 +7,10 @@ use_namespace(roxygen = TRUE) } \arguments{ -\item{roxygen}{Are you planning to use roxygen2?} +\item{roxygen}{Do you plan to manage \code{NAMESPACE} with roxygen2?} } \description{ -If \code{roxygen} is \code{TRUE} generates a empty \code{NAMESPACE} that exports nothing; +If \code{roxygen} is \code{TRUE} generates an empty \code{NAMESPACE} that exports nothing; you'll need to explicitly export functions with \verb{@export}. If \code{roxygen} is \code{FALSE}, generates a default \code{NAMESPACE} that exports all functions except those that start with \code{.}. From d96a4542b09ac8b509029938255f38d96cc9c084 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Wed, 18 Mar 2020 12:22:26 -0500 Subject: [PATCH 5/6] Move test file --- tests/testthat/{test-use-description.R => test-description.R} | 2 -- 1 file changed, 2 deletions(-) rename tests/testthat/{test-use-description.R => test-description.R} (98%) diff --git a/tests/testthat/test-use-description.R b/tests/testthat/test-description.R similarity index 98% rename from tests/testthat/test-use-description.R rename to tests/testthat/test-description.R index 65daed3e8..1561d91cb 100644 --- a/tests/testthat/test-use-description.R +++ b/tests/testthat/test-description.R @@ -1,5 +1,3 @@ -context("use_description") - test_that("build_description_list() defaults to values built into usethis", { withr::local_options(list(usethis.description = NULL, devtools.desc = NULL)) d <- build_description_list() From 64a59bbd5227ac0f1441ccc5fad8414a45b8df98 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Wed, 18 Mar 2020 12:26:38 -0500 Subject: [PATCH 6/6] Remove redundant comment --- tests/testthat/test-use-tidy.R | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/testthat/test-use-tidy.R b/tests/testthat/test-use-tidy.R index dd753967b..4ccd43c89 100644 --- a/tests/testthat/test-use-tidy.R +++ b/tests/testthat/test-use-tidy.R @@ -16,7 +16,6 @@ test_that("use_tidy_eval() inserts the template file and Imports rlang", { skip_if_not_installed("roxygen2") pkg <- scoped_temporary_package() - ## fake the use of roxygen; this better in a test than use_roxygen_md() use_tidy_eval() expect_match(dir_ls(proj_path("R")), "utils-tidy-eval.R") expect_match(desc::desc_get("Imports", pkg), "rlang")