diff --git a/DESCRIPTION b/DESCRIPTION index acca17ac..b878784b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -41,6 +41,7 @@ Collate: 'seed.R' 'wrap.R' 'sink.R' + 'tempfile.R' 'utils.R' 'with.R' RoxygenNote: 6.0.1 diff --git a/NAMESPACE b/NAMESPACE index d701544a..4a925df5 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -30,4 +30,5 @@ export(with_path) export(with_preserve_seed) export(with_seed) export(with_temp_libpaths) +export(with_tempfile) importFrom(stats,runif) diff --git a/NEWS.md b/NEWS.md index a69a0c52..0e4cf90f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # devel +- Add `with_tempfile()` and `local_tempfile()` functions to create temporary + files which are cleanup up afterwards. (#32) + - Remove the `code` argument from `local_` functions (#50). # 2.0.0 diff --git a/R/tempfile.R b/R/tempfile.R new file mode 100644 index 00000000..ea251aa7 --- /dev/null +++ b/R/tempfile.R @@ -0,0 +1,24 @@ +#' Temporary files +#' +#' Temporarily create a tempfile, which is automatically removed afterwards. +#' @template with +#' @param new `[character vector]`\cr Names of temporay file handles to create. +#' @param envir `[environment]`\cr Environment in which to define the temporary files. +#' @export +with_tempfile <- function(new, code, envir = parent.frame()) { + env <- new.env(parent = envir) + for (f in new) { + assign(f, tempfile(), envir = env) + } + on.exit(unlink(mget(new, envir = env))) + eval(substitute(code), envir = env) +} + +#' @rdname with_tempfile +#' @export +local_tempfile <- function(new, envir = parent.frame()) { + for (f in new) { + assign(f, tempfile(), envir = envir) + } + defer(unlink(mget(new, envir = envir)), envir = envir) +} diff --git a/man/with_tempfile.Rd b/man/with_tempfile.Rd new file mode 100644 index 00000000..7bbca1e4 --- /dev/null +++ b/man/with_tempfile.Rd @@ -0,0 +1,25 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tempfile.R +\name{with_tempfile} +\alias{with_tempfile} +\title{Temporary files} +\usage{ +with_tempfile(new, code, envir = parent.frame()) +} +\arguments{ +\item{new}{\code{[character vector]}\cr Names of temporay file handles to create.} + +\item{code}{\code{[any]}\cr Code to execute in the temporary environment} + +\item{envir}{\code{[environment]}\cr Environment in which to define the temporary files.} +} +\value{ +\code{[any]}\cr The results of the evaluation of the \code{code} + argument. +} +\description{ +Temporarily create a tempfile, which is automatically removed afterwards. +} +\seealso{ +\code{\link{withr}} for examples +} diff --git a/tests/testthat/test-tempfile.R b/tests/testthat/test-tempfile.R new file mode 100644 index 00000000..f85676dd --- /dev/null +++ b/tests/testthat/test-tempfile.R @@ -0,0 +1,44 @@ +context("tempfile") + +test_that("with_tempfile works", { + + f1 <- character() + f2 <- character() + + with_tempfile("file1", { + writeLines("foo", file1) + expect_equal(readLines(file1), "foo") + with_tempfile("file2", { + writeLines("bar", file2) + expect_equal(readLines(file1), "foo") + expect_equal(readLines(file2), "bar") + + f2 <<- file2 + }) + expect_false(file.exists(f2)) + f1 <<- file1 + }) + expect_false(file.exists(f1)) +}) + +test_that("local_tempfile works", { + + f1 <- character() + f2 <- character() + + f <- function() { + local_tempfile("file1") + writeLines("foo", file1) + expect_equal(readLines(file1), "foo") + local_tempfile("file2") + writeLines("bar", file2) + expect_equal(readLines(file1), "foo") + expect_equal(readLines(file2), "bar") + f1 <<- file1 + f2 <<- file2 + } + f() + + expect_false(file.exists(f1)) + expect_false(file.exists(f2)) +})