From 21068724b6755078cd8e9a761a0d4065ec96f8f0 Mon Sep 17 00:00:00 2001 From: Michael Chirico Date: Sun, 17 Jul 2022 15:18:22 -0700 Subject: [PATCH] initial work on with_trace() --- .gitignore | 5 +++ DESCRIPTION | 3 +- NAMESPACE | 2 ++ R/debug.R | 49 +++++++++++++++++++++++++++++ man/with_trace.Rd | 62 +++++++++++++++++++++++++++++++++++++ man/withr.Rd | 2 +- tests/testthat/test-debug.R | 22 +++++++++++++ 7 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 R/debug.R create mode 100644 man/with_trace.Rd create mode 100644 tests/testthat/test-debug.R diff --git a/.gitignore b/.gitignore index 7e07f0c8..72a07567 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,8 @@ inst/doc docs revdep/data.sqlite + +# emacs temp files +\#*\# +*~ + diff --git a/DESCRIPTION b/DESCRIPTION index 37e389ed..98a8cf2d 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -62,13 +62,14 @@ VignetteBuilder: knitr Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.1.2 +RoxygenNote: 7.2.0 Collate: 'aaa.R' 'collate.R' 'compat-defer.R' 'connection.R' 'db.R' + 'debug.R' 'defer.R' 'wrap.R' 'local_.R' diff --git a/NAMESPACE b/NAMESPACE index b4a4dd77..63a6fd75 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -39,6 +39,7 @@ export(local_tempdir) export(local_tempfile) export(local_tiff) export(local_timezone) +export(local_trace) export(local_xfig) export(makevars_user) export(set_makevars) @@ -77,5 +78,6 @@ export(with_tempdir) export(with_tempfile) export(with_tiff) export(with_timezone) +export(with_trace) export(with_xfig) importFrom(stats,setNames) diff --git a/R/debug.R b/R/debug.R new file mode 100644 index 00000000..dc91129d --- /dev/null +++ b/R/debug.R @@ -0,0 +1,49 @@ +#' Debugging states which unset themselves +#' +#' Create debugging states, which are then automatically unset afterwards. +#' @template with +#' +#' @param file,.file `[named list]`\cr Files to create. +#' @param ... Additional (possibly named) arguments of files to create. +#' @param .local_envir `[environment]`\cr The environment to use for scoping. +#' +#' @examples +#' with_file("file1", { +#' writeLines("foo", "file1") +#' readLines("file1") +#' }) +#' +#' with_file(list("file1" = writeLines("foo", "file1")), { +#' readLines("file1") +#' }) +#' +#' @export +with_trace <- function(what, code, + tracer = NULL, + exit = NULL, + at = numeric(), + print = TRUE, + signature = NULL, + where = topenv(parent.frame()), + edit = FALSE) { + if (!is.character(what)) what <- as.character(substitute(what)) + methods::.TraceWithMethods(what, tracer, exit, at, print, signature, where, edit) + on.exit(untrace(what, signature, where)) + force(code) +} + +#' @rdname with_trace +#' @export +local_trace <- function(what, code, + tracer = NULL, + exit = NULL, + at = numeric(), + print = TRUE, + signature = NULL, + where = topenv(.local_envir), + edit = FALSE, + .local_envir = parent.frame()) { + defer(untrace(what, signature, where), envir = .local_envir) + + trace(what, tracer, exit, at, print, signature, where, edit) +} diff --git a/man/with_trace.Rd b/man/with_trace.Rd new file mode 100644 index 00000000..66b7caff --- /dev/null +++ b/man/with_trace.Rd @@ -0,0 +1,62 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/debug.R +\name{with_trace} +\alias{with_trace} +\alias{local_trace} +\title{Debugging states which unset themselves} +\usage{ +with_trace( + what, + code, + tracer = NULL, + exit = NULL, + at = numeric(), + print = TRUE, + signature = NULL, + where = topenv(parent.frame()), + edit = FALSE +) + +local_trace( + what, + code, + tracer = NULL, + exit = NULL, + at = numeric(), + print = TRUE, + signature = NULL, + where = topenv(.local_envir), + edit = FALSE, + .local_envir = parent.frame() +) +} +\arguments{ +\item{code}{\code{[any]}\cr Code to execute in the temporary environment} + +\item{.local_envir}{\verb{[environment]}\cr The environment to use for scoping.} + +\item{file, .file}{\verb{[named list]}\cr Files to create.} + +\item{...}{Additional (possibly named) arguments of files to create.} +} +\value{ +\code{[any]}\cr The results of the evaluation of the \code{code} +argument. +} +\description{ +Create debugging states, which are then automatically unset afterwards. +} +\examples{ +with_file("file1", { + writeLines("foo", "file1") + readLines("file1") +}) + +with_file(list("file1" = writeLines("foo", "file1")), { + readLines("file1") +}) + +} +\seealso{ +\code{\link{withr}} for examples +} diff --git a/man/withr.Rd b/man/withr.Rd index 1cb22e64..6fcf3658 100644 --- a/man/withr.Rd +++ b/man/withr.Rd @@ -100,7 +100,7 @@ Other contributors: \itemize{ \item Jennifer Bryan [contributor] \item Richard Cotton [contributor] - \item RStudio [copyright holder] + \item RStudio [copyright holder, funder] } } diff --git a/tests/testthat/test-debug.R b/tests/testthat/test-debug.R new file mode 100644 index 00000000..efdf4547 --- /dev/null +++ b/tests/testthat/test-debug.R @@ -0,0 +1,22 @@ +test_that("with_trace sets and unsets tracing", { + skip_if(exists("foo", envir = .GlobalEnv)) + .GlobalEnv$foo <- function(x) x + 1 + on.exit(rm("foo", envir = .GlobalEnv)) + + with_trace( + foo, + tracer = quote(message("hi")), + expect_message( + expect_output( + expect_identical(foo(1), 2), + "Tracing foo(1) on entry", + fixed = TRUE + ), + "hi", + fixed = TRUE + ) + ) + + # untraced + expect_silent(expect_identical(foo(1), 2)) +})