Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
97c9748
add `use_import_from()`
malcolmbarrett Feb 25, 2021
5eddef7
extract package doc check logic
malcolmbarrett Feb 25, 2021
cc26964
update docs
malcolmbarrett Feb 26, 2021
cb8a345
add tests for `use_import_from()`
malcolmbarrett Feb 26, 2021
6b164d5
fix typo
malcolmbarrett Feb 26, 2021
9e68d1a
Update R/use_import_from.R
malcolmbarrett Feb 26, 2021
23ec601
Update R/use_import_from.R
malcolmbarrett Feb 26, 2021
f069038
Update R/use_import_from.R
malcolmbarrett Feb 26, 2021
3a8cb94
vectorize `fun`
malcolmbarrett Feb 26, 2021
c03adda
Merge branch 'use_import' of github.com:malcolmbarrett/usethis into u…
malcolmbarrett Feb 26, 2021
55fc380
update docs
malcolmbarrett Feb 26, 2021
bd39b04
dissolve import_from()
malcolmbarrett Feb 26, 2021
ebc9dfc
`roxygen_update()` -> `roxygen_remind()`
malcolmbarrett Feb 26, 2021
83ec2da
+ `roxygen_update_ns()`
malcolmbarrett Feb 26, 2021
de55a32
clean up load aspect
malcolmbarrett Feb 26, 2021
bdb5d94
document
malcolmbarrett Feb 26, 2021
7bfee79
make ui more usethis-like
malcolmbarrett Feb 26, 2021
23e41ba
fix note
malcolmbarrett Feb 26, 2021
9d86bcc
Update R/use_import_from.R
malcolmbarrett Feb 27, 2021
c9819a8
match ui_yeah style
malcolmbarrett Feb 27, 2021
e515be8
Merge branch 'use_import' of github.com:malcolmbarrett/usethis into u…
malcolmbarrett Feb 27, 2021
78e4f94
add news item
malcolmbarrett Feb 27, 2021
b8515dd
Documentation tweaks
hadley Feb 27, 2021
1000c3e
A little refactoring
hadley Feb 27, 2021
e4c8cad
Correctly name test file
hadley Feb 27, 2021
f4a401a
More noodling
hadley Feb 27, 2021
4602be5
check length of `package`
malcolmbarrett Feb 27, 2021
cb5416c
update test
malcolmbarrett Feb 28, 2021
111568e
Don't duplicate lines; sort if requested
hadley Mar 3, 2021
8e8cde4
Drop warning
hadley Mar 3, 2021
659952f
Tweak tests
hadley Mar 3, 2021
ddb048d
Use local_tempfile()
hadley Mar 3, 2021
7821456
Update R/use_import_from.R
hadley Mar 3, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ Suggests:
knitr,
magick,
mockr,
pkgload,
rmarkdown,
roxygen2,
spelling (>= 1.2),
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ export(use_github_release)
export(use_gitlab_ci)
export(use_gpl3_license)
export(use_gpl_license)
export(use_import_from)
export(use_jenkins)
export(use_latest_dependencies)
export(use_lgpl_license)
Expand Down
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@

* `use_tidy_release_test_env()` has been deleted since we no longer recommend
including test environment in CRAN comments (#1365).

* Added `use_import_from()` to put `@importFrom pkg fun` into a package in a
consistent way (@malcolmbarrett, #1377)

# usethis 2.0.1

Expand Down
30 changes: 22 additions & 8 deletions R/block.R
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
block_append <- function(desc, value, path, block_start, block_end,
block_prefix = NULL, block_suffix = NULL) {
block_append <- function(desc, value, path,
block_start = "# <<<",
block_end = "# >>>",
block_prefix = NULL,
block_suffix = NULL,
sort = FALSE) {
if (!is.null(path) && file_exists(path)) {
lines <- read_utf8(path)
if (value %in% lines) {
if (all(value %in% lines)) {
return(FALSE)
}

Expand All @@ -24,18 +28,24 @@ block_append <- function(desc, value, path, block_start, block_end,
end <- block_lines[[2]]
block <- lines[seq2(start, end)]

new_lines <- union(block, value)
if (sort) {
new_lines <- sort(new_lines)
}

lines <- c(
lines[seq2(1, start - 1L)],
block,
value,
new_lines,
lines[seq2(end + 1L, length(lines))]
)
write_utf8(path, lines)

TRUE
}

block_replace <- function(desc, value, path, block_start, block_end) {
block_replace <- function(desc, value, path,
block_start = "# <<<",
block_end = "# >>>") {
if (!is.null(path) && file_exists(path)) {
lines <- read_utf8(path)
block_lines <- block_find(lines, block_start, block_end)
Expand Down Expand Up @@ -68,13 +78,13 @@ block_replace <- function(desc, value, path, block_start, block_end) {
}


block_show <- function(path, block_start, block_end) {
block_show <- function(path, block_start = "# <<<", block_end = "# >>>") {
lines <- read_utf8(path)
block <- block_find(lines, block_start, block_end)
lines[seq2(block[[1]], block[[2]])]
}

block_find <- function(lines, block_start, block_end) {
block_find <- function(lines, block_start = "# <<<", block_end = "# >>>") {
# No file
if (is.null(lines)) {
return(NULL)
Expand All @@ -97,3 +107,7 @@ block_find <- function(lines, block_start, block_end) {

c(start + 1L, end - 1L)
}

block_create <- function(lines = character(), block_start = "# <<<", block_end = "# >>>") {
c(block_start, unique(lines), block_end)
}
4 changes: 2 additions & 2 deletions R/pipe.R
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ use_pipe <- function(export = TRUE) {
use_dependency("magrittr", "Imports")

if (export) {
use_template("pipe.R", "R/utils-pipe.R") && roxygen_update()
use_template("pipe.R", "R/utils-pipe.R") && roxygen_remind()
return(invisible(TRUE))
}

if (has_package_doc()) {
roxygen_ns_append("@importFrom magrittr %>%") && roxygen_update()
roxygen_ns_append("@importFrom magrittr %>%") && roxygen_remind()
return(invisible(TRUE))
}

Expand Down
6 changes: 3 additions & 3 deletions R/rcpp.R
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use_rcpp <- function(name = NULL) {

use_dependency("Rcpp", "LinkingTo")
use_dependency("Rcpp", "Imports")
roxygen_ns_append("@importFrom Rcpp sourceCpp") && roxygen_update()
roxygen_ns_append("@importFrom Rcpp sourceCpp") && roxygen_remind()

use_src_example_script(name, "cpp")

Expand Down Expand Up @@ -55,7 +55,7 @@ use_rcpp_eigen <- function(name = NULL) {

use_dependency("RcppEigen", "LinkingTo")

roxygen_ns_append("@import RcppEigen") && roxygen_update()
roxygen_ns_append("@import RcppEigen") && roxygen_remind()

invisible()
}
Expand All @@ -77,7 +77,7 @@ use_src <- function() {
use_directory("src")
use_git_ignore(c("*.o", "*.so", "*.dll"), "src")
roxygen_ns_append(glue("@useDynLib {project_name()}, .registration = TRUE")) &&
roxygen_update()
roxygen_remind()

invisible()
}
Expand Down
19 changes: 17 additions & 2 deletions R/roxygen.R
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,30 @@ roxygen_ns_append <- function(tag) {
path = proj_path(package_doc_path()),
block_start = "## usethis namespace: start",
block_end = "## usethis namespace: end",
block_suffix = "NULL"
block_suffix = "NULL",
sort = TRUE
)
}
roxygen_ns_show <- function(tag) {
block_show(
path = proj_path(package_doc_path()),
block_start = "## usethis namespace: start",
block_end = "## usethis namespace: end"
)
}

roxygen_update <- function() {
roxygen_remind <- function() {
ui_todo("Run {ui_code('devtools::document()')} to update {ui_path('NAMESPACE')}")
TRUE
}

roxygen_update_ns <- function() {
ui_done("Writing {ui_path('NAMESPACE')}")
utils::capture.output(
suppressMessages(roxygen2::roxygenise(proj_get(), "namespace"))
)
TRUE
}

# Checkers ----------------------------------------------------------------

Expand Down
2 changes: 1 addition & 1 deletion R/tibble.R
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ use_tibble <- function() {
check_uses_roxygen("use_tibble()")

use_dependency("tibble", "Imports")
roxygen_ns_append("@importFrom tibble tibble") && roxygen_update()
roxygen_ns_append("@importFrom tibble tibble") && roxygen_remind()

ui_todo("Document a returned tibble like so:")
ui_code_block("#' @return a [tibble][tibble::tibble-package]", copy = FALSE)
Expand Down
79 changes: 79 additions & 0 deletions R/use_import_from.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#' Import a function from another package
#'
#' @description
#' `use_import_from()` imports a function from another package by adding the
#' roxygen2 `@importFrom` tag to the package-level documentation (which can be
#' created with [`use_package_doc()`]). Importing a function from another
#' package allows you to refer to it without a namespace (e.g., `fun()` instead
#' of `package::fun()`).
#'
#' `use_import_from()` also re-documents the NAMESPACE, and re-load the current
#' package. This ensures that `fun` is immediately available in your development
#' session.
#'
#' @param package Package name
#' @param fun A vector of function names
#' @param load Logical. Re-load with [`pkgload::load_all()`]?
#' @return
#' Invisibly, `TRUE` if the package document has changed, `FALSE` if not.
#' @export
#' @examples
#' \dontrun{
#' use_import_from("usethis", "ui_todo")
#' }
use_import_from <- function(package, fun, load = is_interactive()) {
if (!is_string(package)) {
ui_stop("{ui_code('package')} must be a single string")
}
check_is_package("use_import_from()")
check_uses_roxygen("use_import_from()")

if (!check_has_package_doc()) {
return(invisible(FALSE))
}
purrr::walk2(package, fun, check_fun_exists)

use_dependency(package, "Imports")
changed <- roxygen_ns_append(glue("@importFrom {package} {fun}"))

if (changed) {
roxygen_update_ns()

if (load) {
ui_done("Loading {project_name()}")
pkgload::load_all(quiet = TRUE)
}
}

invisible(changed)
}

check_fun_exists <- function(package, fun) {
if (exists(fun, envir = asNamespace(package))) {
return()
}
name <- paste0(package, "::", fun, "()")
ui_stop("Can't find {ui_code(name)}")
}

check_has_package_doc <- function() {
if (has_package_doc()) {
return(invisible(TRUE))
}

if (!is_interactive()) {
return(invisible(FALSE))
}

if (ui_yeah("
{ui_code('use_import_from()')} requires \\
package-level documentation. Would you like to add \\
it now?")) {
use_package_doc()
} else {
ui_todo("Run {ui_code('use_package_doc()')}")
return(invisible(FALSE))
}

invisible(TRUE)
}
2 changes: 0 additions & 2 deletions R/usethis-package.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
#' @import rlang
"_PACKAGE"

# The following block is used by usethis to automatically manage
# roxygen namespace tags. Modify with care!
## usethis namespace: start
#' @importFrom lifecycle deprecated
## usethis namespace: end
Expand Down
2 changes: 0 additions & 2 deletions inst/templates/packagename-package.R
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#' @keywords internal
"_PACKAGE"

# The following block is used by usethis to automatically manage
# roxygen namespace tags. Modify with care!
## usethis namespace: start
## usethis namespace: end
NULL
34 changes: 34 additions & 0 deletions man/use_import_from.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions tests/testthat/_snaps/use_import_from.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# use_import_from() adds one line for each function

Code
roxygen_ns_show()
Output
[1] "#' @importFrom tibble deframe" "#' @importFrom tibble enframe"
[3] "#' @importFrom tibble tibble"

# use_import_from() generates helpful errors

Code
use_import_from(1)
Error <usethis_error>
`package` must be a single string
Code
use_import_from(c("tibble", "rlang"))
Error <usethis_error>
`package` must be a single string
Code
use_import_from("tibble", "pool_noodle")
Error <usethis_error>
Can't find `tibble::pool_noodle()`

18 changes: 18 additions & 0 deletions tests/testthat/test-block.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
test_that("block_append() only writes unique lines", {

path <- withr::local_tempfile()
writeLines(block_create(), path)

block_append("---", c("x", "y"), path)
block_append("---", c("y", "x"), path)
expect_equal(block_show(path), c("x", "y"))
})

test_that("block_append() can sort, if requested", {
path <- withr::local_tempfile()
writeLines(block_create(), path)

block_append("---", c("z", "y"), path)
block_append("---", "x", path, sort = TRUE)
expect_equal(block_show(path), c("x", "y", "z"))
})
28 changes: 28 additions & 0 deletions tests/testthat/test-use_import_from.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
test_that("use_import_from() imports the related package & adds line to package doc", {
create_local_package()
use_package_doc()
use_import_from("tibble", "tibble")

expect_equal(trimws(desc::desc_get("Imports", proj_get()))[[1]], "tibble")
expect_equal(roxygen_ns_show(), "#' @importFrom tibble tibble")
})

test_that("use_import_from() adds one line for each function", {
create_local_package()
use_package_doc()
use_import_from("tibble", c("tibble", "enframe", "deframe"))

expect_snapshot(roxygen_ns_show())
})

test_that("use_import_from() generates helpful errors", {
create_local_package()
use_package_doc()

expect_snapshot(error = TRUE, {
use_import_from(1)
use_import_from(c("tibble", "rlang"))

use_import_from("tibble", "pool_noodle")
})
})